svg`<svg width="${w}" height="${h}">
<rect x="0" y="0" width="${w}" height="${h}" stroke="none" fill="${palette[0]}"></rect>
<g transform="translate(${w/2}, ${h/2}) scale(0.55)">
${array(n).map(i => {
const x1 = randInt(w/2/gridSize) * gridSize * coin()
const y1 = randInt(h/2/gridSize) * gridSize * coin()
const A = PVector(x1, y1)
const B = PVector.add(A, PVector(coin(), coin()).mult(gridSize).mult(randInt(2, 15)))
const dir = random() < .5 ? PVector(1, 0) : PVector(0, 1)
dir.mult(randInt(1, 16) * 5)
const p1 = PVector.add(A, dir)
const p2 = PVector.sub(A, dir)
const p3 = PVector.sub(B, dir)
const p4 = PVector.add(B, dir)
const c = palette[randInt(palette.length)]
return `<g opacity="0.95">
<!-- shadows -->
<g opacity="0.7" transform="translate(0, ${random(1, 20)})">
<polygon
points="${[p1, p2, p3, p4].reduce((acc, p) => `${acc} ${p.x} ${p.y}`, '')}"
stroke="none"
fill="black"
/>
<polygon
points="${[p1, p2, p3, p4].reduce((acc, p) => `${acc} ${-p.x} ${p.y}`, '')}"
stroke="none"
fill="black"
/>
</g>
<!-- contours -->
<polygon
points="${[p1, p2, p3, p4].reduce((acc, p) => `${acc} ${p.x} ${p.y}`, '')}"
stroke="black"
stroke-width="1"
fill="black"
/>
<polygon
points="${[p1, p2, p3, p4].reduce((acc, p) => `${acc} ${-p.x} ${p.y}`, '')}"
stroke="black"
stroke-width="1"
fill="black"
/>
<polygon
points="${[p1, p2, p3, p4].reduce((acc, p) => `${acc} ${p.x} ${p.y}`, '')}"
stroke="none"
fill="${c}"
/>
<polygon
points="${[p1, p2, p3, p4].reduce((acc, p) => `${acc} ${-p.x} ${p.y}`, '')}"
stroke="none"
fill="${c}"
/>
</g>`
}).join('\n')}
</g>
</svg>`