a kintsugi bowl in a spotlight, the gold repair the only bright thing in the room
painted by DeepSeek V4p5 2.3.2 · brush 2.2.2 · 2026-08-24
// composition: kintsugi bowl low-center-right inside a warm spotlight pool; upper-left and all margins stay quiet paper
// layering: spotlight washes -> cast shadow -> three charcoal silhouette passes -> rim line -> gold seam (2 forks), shadow pass then two bright passes -> lacquer pools
const PALETTE = [
"#f2e9d8", // warm paper ground
"#efd9a8", // spotlight warmth
"#2c2a2f", // charcoal bowl mass
"#191a1e", // bowl core shadow
"#d1a437", // gold seam — the only bright element
"#6e5418", // gold understroke / seam shadow
];
const CX = 520;
const CY = 560;
function wander(x0, y0, x1, y1, n, amp) {
const pts = [];
for (let i = 0; i <= n; i++) {
const t = i / n;
const jx = i === 0 || i === n ? 0 : randomGaussian(0, amp);
const jy = i === 0 || i === n ? 0 : randomGaussian(0, amp * 0.7);
pts.push([lerp(x0, x1, t) + jx, lerp(y0, y1, t) + jy]);
}
return pts;
}
function bowlPass(col, opacity, dx, dy, jit) {
const v = [
[-142, -64], [-60, -78], [40, -80], [140, -66],
[128, -6], [96, 52], [52, 84], [30, 92],
[-34, 92], [-70, 80], [-104, 44], [-136, -10],
];
brush.noStroke();
brush.fillBleed(0.3, "out");
brush.fillTexture(0.55, 0.65);
brush.fill(col, opacity);
brush.beginShape(0.5);
for (const [x, y] of v) {
brush.vertex(CX + x + dx + randomGaussian(0, jit), CY + y + dy + randomGaussian(0, jit));
}
brush.endShape(true);
}
function goldPath(pts, col, w, jit) {
brush.set("pen", col, w);
brush.beginShape(0.25);
for (const [x, y] of pts) {
brush.vertex(x + randomGaussian(0, jit), y + randomGaussian(0, jit));
}
brush.endShape(false);
}
function setup() {
createCanvas(800, 800, WEBGL);
angleMode(DEGREES);
brush.scaleBrushes(2.4);
noLoop();
}
function draw() {
translate(-width / 2, -height / 2);
background("#f2e9d8");
// spotlight pool — three soft concentric washes, off-center on the bowl
brush.noStroke();
brush.fillBleed(0.55, "out");
brush.fillTexture(0.35, 0.4);
brush.fill("#efd9a8", 26);
brush.circle(CX + 6, CY - 40, 300, true);
brush.fill("#efd9a8", 34);
brush.circle(CX + 16, CY - 22, 176, true);
// faint table line running off to the left, grounding the still life
brush.set("2B", "#c9b995", 0.8);
brush.line(128, CY + 96, CX - 152, CY + 93);
// cast shadow pooling lower-left of the foot
brush.noStroke();
brush.fillBleed(0.5, "out");
brush.fillTexture(0.4, 0.5);
brush.fill("#3a3630", 52);
brush.beginShape(0.7);
brush.vertex(CX - 172, CY + 98);
brush.vertex(CX - 60, CY + 86);
brush.vertex(CX + 66, CY + 90);
brush.vertex(CX + 38, CY + 112);
brush.vertex(CX - 118, CY + 118);
brush.endShape(true);
// bowl silhouette — three translucent charcoal passes, slightly offset
bowlPass("#2c2a2f", 150, 0, 0, 2.5);
bowlPass("#191a1e", 95, 2, 2, 2);
// rim — a darker line along the lip, hand-wavering
brush.set("2B", "#101014", 1.3);
brush.beginShape(0.4);
brush.vertex(CX - 138, CY - 62);
brush.vertex(CX - 52, CY - 77);
brush.vertex(CX + 44, CY - 79);
brush.vertex(CX + 136, CY - 64);
brush.endShape(false);
// the break — one main seam descending, forking twice
const main = wander(CX - 46, CY - 74, CX + 22, CY + 82, 8, 7);
const forkA = wander(main[3][0], main[3][1], CX + 96, CY + 30, 5, 5);
const forkB = wander(main[6][0], main[6][1], CX - 96, CY + 58, 4, 5);
// shadow pass first — dim gold, offset, so the seam sits IN the glaze
for (const p of [main, forkA, forkB]) {
goldPath(p.map(([x, y]) => [x + 2, y + 2]), "#6e5418", 1.7, 0.8);
}
// two bright passes — the kintsugi glow
for (const p of [main, forkA, forkB]) {
goldPath(p, "#d1a437", 1.3, 0.7);
goldPath(p, "#d1a437", 0.9, 1.1);
}
// a small tick of gold rising past the rim
brush.set("pen", "#d1a437", 1.1);
brush.line(main[0][0], main[0][1], main[0][0] - 5, main[0][1] - 12);
// lacquer pools where the seam turns and forks
brush.noStroke();
brush.fillBleed(0.25, "out");
brush.fillTexture(0.6, 0.7);
const pools = [main[3], main[6], forkA[2], forkB[2], main[5]];
for (const [px, py] of pools) {
brush.fill("#d1a437", 215);
brush.circle(px + randomGaussian(0, 1.5), py + randomGaussian(0, 1.5), random(2, 3.6), true);
}
}