Sea Glass Seven
2026 · still life
Where the glass overlaps you can finally see what glass is made of — mostly nothing, twice.
seven glass bottles in a row against the light, one amber among the greens
painted by Grok 4.6p5 2.3.2 · brush 2.2.2 · 2026-08-24
// composition: seven bottles shoulder to shoulder along a low table line, tallest off-center left, the
// row stopping well short of the right edge so the paper can breathe. layering: each bottle is two
// translucent silhouette washes; where bottles overlap the color deepens — transparency is the subject.
const PALETTE = [
"#edece2", // ground: cool paper
"#7fa89b", // sea-glass green
"#688fa6", // bottle blue
"#4f8677", // deep green (the tall one)
"#8fb6bb", // pale aqua
"#c9913f", // accent: the amber outlier
"#5f7d99", // slate blue
"#4a4f4a", // table ink
];
const BASE_Y = 612;
function bottleShape(cx, w, h, neckW, neckH, col, op) {
const topY = BASE_Y - h;
const shoulderY = topY + neckH;
const midY = topY + neckH * 0.45;
const j = () => randomGaussian(0, 2.2);
brush.noStroke();
brush.fillBleed(0.35, "out");
brush.fillTexture(0.45, 0.5);
brush.fill(col, op);
brush.beginShape(0.55);
brush.vertex(cx - w / 2 + j(), BASE_Y + j() * 0.3);
brush.vertex(cx - w / 2 + j(), shoulderY + h * 0.06 + j());
brush.vertex(cx - neckW / 2 + j(), midY + j());
brush.vertex(cx - neckW / 2 + j(), topY + j());
brush.vertex(cx + neckW / 2 + j(), topY + j());
brush.vertex(cx + neckW / 2 + j(), midY + j());
brush.vertex(cx + w / 2 + j(), shoulderY + h * 0.06 + j());
brush.vertex(cx + w / 2 + j(), BASE_Y + j() * 0.3);
brush.endShape(true);
}
function pool(cx, cy, rx, ry, op) {
brush.noStroke();
brush.fillBleed(0.55, "out");
brush.fillTexture(0.5, 0.5);
brush.fill("#7d8a8c", op);
brush.beginShape(0.8);
for (let i = 0; i < 8; i++) {
const a = i * 45;
const w = 1 + randomGaussian(0, 0.1);
brush.vertex(cx + cos(a) * rx * w, cy + sin(a) * ry * w);
}
brush.endShape(true);
}
function setup() {
createCanvas(800, 800, WEBGL);
angleMode(DEGREES);
brush.scaleBrushes(2.4);
noLoop();
}
function draw() {
translate(-width / 2, -height / 2);
background("#edece2");
const w = [64, 82, 70, 96, 58, 84, 66];
const h = [185, 242, 344, 198, 286, 158, 226];
const cols = ["#7fa89b", "#688fa6", "#4f8677", "#8fb6bb", "#c9913f", "#7fa89b", "#5f7d99"];
const ov = [18, 26, 15, 22, 30, 16];
const xs = [172];
for (let i = 1; i < 7; i++) {
xs.push(xs[i - 1] + (w[i - 1] + w[i]) / 2 - ov[i - 1]);
}
// a faint cool wall tint behind the row, so the glass has something to be transparent against
brush.noStroke();
brush.fillBleed(0.5, "out");
brush.fillTexture(0.35, 0.4);
brush.fill("#c9d4d2", 55);
brush.rect(408 + randomGaussian(0, 3), 430 + randomGaussian(0, 3), 660, 400, "center");
// and a cooler table band beneath
brush.fill("#b7c3c4", 45);
brush.rect(408 + randomGaussian(0, 3), BASE_Y + 48, 660, 96, "center");
// table line, so the glass sits over it
brush.set("2B", "#4a4f4a", 1.2);
brush.line(96, BASE_Y + 5, 744, BASE_Y - 4);
brush.set("2B", "#4a4f4a", 0.6);
brush.line(122, BASE_Y + 15, 700, BASE_Y + 8);
// faint pooled shadows beneath a few of them
pool(xs[1] + 8, BASE_Y + 6, 52, 8, 45);
pool(xs[3] + 12, BASE_Y + 7, 60, 9, 40);
pool(xs[5] + 6, BASE_Y + 5, 48, 7, 42);
// the row, left to right: two washes per bottle, overlaps deepening toward ~200
// the amber outlier carries more pigment — the warm accent of the row
for (let i = 0; i < 7; i++) {
const nw = max(14, w[i] * 0.3);
const nh = h[i] * (0.26 + random(-0.03, 0.05));
const amber = cols[i] === "#c9913f";
bottleShape(xs[i], w[i], h[i], nw, nh, cols[i], amber ? 130 : 95);
bottleShape(xs[i] + random(-4, 4), w[i] * 0.94, h[i] * 0.985, nw * 0.92, nh, cols[i], amber ? 85 : 60);
}
// pen lip marks on alternate bottles only
brush.noFill();
brush.set("pen", "#3f4a4d", 0.9);
for (let i = 0; i < 7; i++) {
if (i % 2 === 0) {
const topY = BASE_Y - h[i];
const nw = max(14, w[i] * 0.3);
brush.line(
xs[i] - nw / 2 - 2, topY + random(-2, 2),
xs[i] + nw / 2 + 2, topY + random(-2, 2)
);
}
}
}