Sampler, Unraveling
2026 · textile
Every row held its discipline except the one that learned to leave.
an embroidery sampler whose last row of stitches gives up and wanders off the cloth
painted by Grok 4.6p5 2.3.2 · brush 2.2.2 · 2026-08-24
// composition: an embroidery sampler — five stitch rows banded across the middle of a linen ground; the last row unravels into a loose thread exiting bottom-left
// layering: linen tone wash + faint weave -> pale pencil guide lines -> cross row, chain row, dot row, dash row -> running stitch that lets go
const PALETTE = [
"#eae0c9", // linen ground
"#d9cdae", // weave / guide thread
"#51618c", // faded indigo thread
"#a3503e", // madder thread — carries the unraveling
"#6b6b3a", // olive thread
];
const X0 = 152;
const X1 = 648;
function setup() {
createCanvas(800, 800, WEBGL);
angleMode(DEGREES);
brush.scaleBrushes(2.3);
noLoop();
}
function draw() {
translate(-width / 2, -height / 2);
background("#eae0c9");
// linen tone — one uneven wash so the cloth isn't flat
brush.noStroke();
brush.fillBleed(0.4, "out");
brush.fillTexture(0.75, 0.5);
brush.fill("#e2d6b8", 32);
brush.rect(30, 40, 740, 720);
// faint weave — sparse warp and weft lines, many skipped
brush.set("2H", "#d9cdae", 0.6);
for (let i = 0; i < 26; i++) {
if (random() < 0.4) continue;
const y = 70 + i * 26 + randomGaussian(0, 2);
brush.line(60 + random(0, 40), y, 740 - random(0, 40), y + randomGaussian(0, 2));
}
for (let i = 0; i < 18; i++) {
if (random() < 0.55) continue;
const x = 80 + i * 38 + randomGaussian(0, 3);
brush.line(x, 80 + random(0, 50), x + randomGaussian(0, 2), 720 - random(0, 50));
}
const rows = [278, 344, 410, 476, 548];
// pencil guide lines under each row — the sampler's ruled skeleton
brush.set("2H", "#cfc2a0", 0.5);
for (const y of rows) {
brush.beginShape(0.3);
brush.vertex(X0 - 8, y + 11 + randomGaussian(0, 1));
brush.vertex((X0 + X1) / 2, y + 11 + randomGaussian(0, 2));
brush.vertex(X1 + 8, y + 11 + randomGaussian(0, 1));
brush.endShape(false);
}
// row 1 — cross stitches, faded indigo, the occasional dropped stitch
brush.set("2B", "#51618c", 1.1);
for (let x = X0 + 8; x < X1; x += 26) {
if (random() < 0.06) continue; // a dropped stitch
const y = rows[0] + randomGaussian(0, 2.2);
const s = 7 + randomGaussian(0, 0.9);
brush.line(x - s + randomGaussian(0, 1.2), y - s, x + s + randomGaussian(0, 1.2), y + s);
brush.line(x - s + randomGaussian(0, 1.2), y + s, x + s + randomGaussian(0, 1.2), y - s);
}
// row 2 — chain loops, madder, overlapping rings
brush.set("2B", "#a3503e", 1.0);
brush.noFill();
for (let x = X0 + 10; x < X1; x += 19) {
const y = rows[1] + randomGaussian(0, 2);
brush.circle(x + randomGaussian(0, 1.5), y, 8 + randomGaussian(0, 0.8), true);
}
// row 3 — french-knot dots, olive
brush.noStroke();
brush.fillBleed(0.2, "out");
brush.fillTexture(0.5, 0.6);
for (let x = X0 + 6; x < X1; x += 18) {
if (random() < 0.05) continue;
brush.fill("#6b6b3a", 150 + random(0, 45));
brush.circle(x + randomGaussian(0, 2), rows[2] + randomGaussian(0, 2.5), 2.4 + random(0, 1.6), true);
}
// row 4 — long-short dashes, indigo
brush.set("2B", "#51618c", 1.3);
let dx = X0 + 4;
for (let i = 0; i < 40; i++) {
if (dx > X1) break;
const len = i % 2 === 0 ? 19 + randomGaussian(0, 2) : 7 + randomGaussian(0, 1.2);
const y = rows[3] + randomGaussian(0, 2);
brush.line(dx, y, dx + len, y + randomGaussian(0, 1.5));
dx += len + 8 + randomGaussian(0, 1.5);
}
// row 5 — running stitch in madder that sags, then lets go entirely
brush.set("2B", "#a3503e", 1.1);
let rx = X0 + 4;
let sag = 0;
for (let i = 0; i < 12; i++) {
if (rx > 360) break;
sag += random(0.2, 1.1); // tension failing
const y = rows[4] + sag + randomGaussian(0, 1.5);
brush.line(rx, y, rx + 14 + randomGaussian(0, 1.5), y + randomGaussian(0, 1.2) + sag * 0.15);
rx += 24 + randomGaussian(0, 2);
}
// the loose thread — wanders, curls twice, exits bottom-left
brush.spline(
[
[352, rows[4] + sag + 2],
[396, 572],
[376, 602],
[334, 588],
[306, 626],
[258, 612],
[216, 656],
[162, 696],
[104, 744],
[40, 800],
],
0.9
);
// frayed thread-end fibers where the stitching gave up
brush.set("2B", "#a3503e", 0.6);
brush.line(352, rows[4] + sag, 360, rows[4] + sag - 7);
brush.line(354, rows[4] + sag + 2, 363, rows[4] + sag + 6);
}