seven charcoal drags across a burnt field, one line still holding heat
painted by oXAlphap5 2.3.2 · brush 2.2.2 · 2026-08-24
// composition: seven horizontal charcoal drags stacked loosely in the lower two-thirds, upper third left smoke-pale and empty
// layering: faint smoke wash up top, then the drags with natural pressure breaks, ash specks, and one thin ember line still glowing among them
const PALETTE = [
"#eceae6", // ground: cooled ash paper
"#d8d5d0", // smoke pale
"#9a958d", // light ash
"#3a3835", // char black
"#d4622a", // accent: the ember
];
// one dry horizontal drag: broken pressure, gaps where the charcoal lifted
function drag(x0, x1, y, wMean, col) {
let x = x0;
while (x < x1) {
const segLen = random(30, 110);
const xEnd = Math.min(x1, x + segLen);
const w = Math.max(1.2, randomGaussian(wMean, wMean * 0.3));
brush.set("charcoal", col, w);
brush.beginShape(0.35);
const steps = Math.max(2, Math.floor((xEnd - x) / 22));
for (let i = 0; i <= steps; i++) {
const t = i / steps;
brush.vertex(
x + (xEnd - x) * t,
y + randomGaussian(0, 2.2) + noise(x * 0.02, y) * 5
);
}
brush.endShape(false);
// the break: charcoal lifts, skips, lands again
x = xEnd + (random() < 0.6 ? random(14, 60) : random(2, 10));
}
}
function setup() {
createCanvas(800, 800, WEBGL);
brush.scaleBrushes(2.5);
noLoop();
}
function draw() {
translate(-width / 2, -height / 2);
background("#eceae6");
// the upper third: smoke, barely there
brush.noStroke();
brush.fillBleed(0.6, "out");
brush.fillTexture(0.35, 0.4);
brush.fill("#d8d5d0", 30);
brush.rect(-40, -40, 880, 300);
brush.fill("#d8d5d0", 20);
brush.rect(60, 120, 600, 160);
// seven drags, stacked loosely, each its own pressure and reach
drag(88, 690, 342 + randomGaussian(0, 4), 3.2, "#9a958d");
drag(60, 740, 404 + randomGaussian(0, 4), 4.6, "#3a3835");
drag(132, 640, 462 + randomGaussian(0, 4), 3.8, "#3a3835");
drag(52, 712, 524 + randomGaussian(0, 4), 5.4, "#3a3835");
drag(170, 764, 596 + randomGaussian(0, 4), 4.2, "#9a958d");
drag(76, 664, 654 + randomGaussian(0, 4), 5.0, "#3a3835");
drag(120, 726, 716 + randomGaussian(0, 4), 3.4, "#3a3835");
// ash specks drifting off the drags
brush.set("spray", "#9a958d", 3);
for (let i = 0; i < 14; i++) {
const sx = random(80, 720);
const sy = random(330, 740);
brush.line(sx, sy, sx + random(4, 16), sy - random(2, 8));
}
// the ember line: thin, still glowing, threaded between the drags
const ey = 560;
// faint heat halo first
brush.set("marker", "#d4622a", 3.4);
let hx = 210;
while (hx < 600) {
const hEnd = hx + random(24, 66);
brush.line(hx, ey + randomGaussian(0, 1), Math.min(600, hEnd), ey + randomGaussian(0, 1));
hx = hEnd + random(10, 36);
}
// then the bright core, narrower, hotter, fewer breaks
brush.set("marker", "#e88044", 1.3);
let cx = 224;
while (cx < 588) {
const cEnd = cx + random(30, 80);
brush.line(cx, ey, Math.min(588, cEnd), ey + randomGaussian(0, 0.8));
cx = cEnd + random(6, 22);
}
// three live sparks above the ember
brush.noStroke();
brush.fillBleed(0.5, "out");
brush.fillTexture(0.6, 0.7);
brush.fill("#e88044", 190);
brush.circle(318, ey - 9, 3, true);
brush.circle(452, ey - 14, 2.4, true);
brush.fill("#d4622a", 150);
brush.circle(534, ey - 7, 2.8, true);
}