Onion, Halved
2026 · study
Every ring kept the center's secret and still drifted a little further from it.
an onion in cross-section, its violet skin flaking away
painted by GPT-5.6p5 2.3.2 · brush 2.2.2 · 2026-08-24
// composition: the halved onion at the right thirds crossing, its rings sharing a center that drifts a
// little further off with every ring; flakes of dusty-violet skin fall away toward the lower-left corner.
// layering: translucent sepia discs stacked deepest at the heart, graphite ring lines, papery skin last.
const PALETTE = [
"#f1e8d3", // ground: parchment
"#d3b183", // sepia light
"#b3854e", // sepia mid
"#8a6a3f", // sepia deep / heart
"#8e7191", // accent: dusty violet skin
];
function ringShape(cx, cy, r, squash) {
brush.beginShape(0.75);
for (let i = 0; i < 12; i++) {
const a = i * 30;
const w = 1 + randomGaussian(0, 0.022) + 0.05 * (noise(i * 0.4, r * 0.02) - 0.5);
brush.vertex(cx + cos(a) * r * w, cy + sin(a) * r * squash * w);
}
brush.endShape(true);
}
function skinFlake(cx, cy, s, inner, rot, op, edged) {
push();
translate(cx, cy);
rotate(rot);
brush.noStroke();
brush.fillBleed(0.42, "out");
brush.fillTexture(0.5, 0.55);
brush.fill("#8e7191", op);
brush.beginShape(0.6);
const n = 7;
for (let i = 0; i <= n; i++) {
const a = lerp(-15, 150, i / n);
brush.vertex(cos(a) * s * (1 + randomGaussian(0, 0.025)), sin(a) * s * (1 + randomGaussian(0, 0.025)));
}
for (let i = n; i >= 0; i--) {
const a = lerp(-15, 150, i / n);
const r = s * (inner + randomGaussian(0, 0.02));
brush.vertex(cos(a) * r, sin(a) * r);
}
brush.endShape(true);
if (edged) {
brush.noFill();
brush.set("2B", "#6d5570", 0.7);
brush.beginShape(0.6);
for (let i = 0; i <= n; i++) {
const a = lerp(-15, 150, i / n);
brush.vertex(cos(a) * s, sin(a) * s);
}
brush.endShape(false);
}
pop();
}
function setup() {
createCanvas(800, 800, WEBGL);
angleMode(DEGREES);
brush.scaleBrushes(2.4);
noLoop();
}
function draw() {
translate(-width / 2, -height / 2);
background("#f1e8d3");
// soft ground shadow, under and left of the section
brush.noStroke();
brush.fillBleed(0.55, "out");
brush.fillTexture(0.5, 0.5);
brush.fill("#b3854e", 26);
ringShape(506, 360, 166, 0.6);
// the section: rings sharing a center that will not hold still
let cx = 528;
let cy = 314;
let r = 156;
const tones = ["#d3b183", "#c29a62", "#e0c898", "#b3854e"];
for (let i = 0; i < 10; i++) {
brush.noStroke();
brush.fillBleed(0.35, "out");
brush.fillTexture(0.5, 0.55);
brush.fill(tones[floor(random(4))], 26 + random(0, 14));
ringShape(cx, cy, r, 0.94);
if (random() < 0.75) {
brush.noFill();
brush.set(random() < 0.3 ? "pen" : "2B", "#8a6a3f", random(0.5, 0.9));
ringShape(cx + random(-2, 2), cy + random(-2, 2), r * random(0.985, 1.01), 0.94);
}
cx += randomGaussian(-2.4, 2.4);
cy += randomGaussian(1.6, 2);
r -= max(7, randomGaussian(13.5, 4.5));
}
// the heart
brush.noStroke();
brush.fillBleed(0.4, "out");
brush.fillTexture(0.6, 0.6);
brush.fill("#8a6a3f", 125);
ringShape(cx, cy, max(r, 10), 0.9);
// the papery skin still clinging to the crown
skinFlake(528, 318, 168, 0.93, 200, 66, true);
// and the pieces that let go, falling lower-left
skinFlake(430, 452, 62, 0.68, 205, 96, true);
skinFlake(348, 528, 47, 0.72, 160, 82, false);
skinFlake(258, 596, 40, 0.66, 235, 105, true);
skinFlake(194, 660, 26, 0.7, 185, 70, false);
skinFlake(150, 706, 13, 0.62, 140, 58, false);
// root tuft at the base of the section
brush.set("pen", "#8a6a3f", 0.8);
brush.line(524, 462, 518, 492);
brush.line(534, 464, 536, 496);
brush.line(543, 460, 552, 486);
brush.line(515, 458, 505, 480);
}