svg`<svg width="${w}" height="${h}" style="background: ${palette[0]}">
<style>
g {
/* testing different blend modes, only the last one is used
mix-blend-mode: normal;
mix-blend-mode: darken;
mix-blend-mode: exclusion;
mix-blend-mode: difference;
mix-blend-mode: overlay;
mix-blend-mode: soft-light;
mix-blend-mode: multiply;
mix-blend-mode: screen;
mix-blend-mode: hard-light;
*/
}
</style>
<defs>
${(() => {
const createClip = N => {
const size = w / N
return `<clipPath id="clip-${N}">
<rect
x="0"
y="0"
width="${size + .2}"
height="${size + .2}"
/>
</clipPath>`
}
const clips = []
for(let i = 2; i <= 32; i *= 2) {
clips.push(createClip(i))
}
return clips.join('')
})()}
</defs>
${(() => {
const prng = new PRNG(seed)
const createShapes = N => {
const size = w / N
let ny = Math.ceil(h / size)
if(ny % 2) ny ++
const marginY = (h - ny * size) / 2
return array(N).map((d, i, arr) => {
const x = i * size
return array(ny).map(j => {
const c = palette[prng.rand(1, palette.length-1)]
const y = marginY + j * size
const cx = prng.rand(1) * size
const cy = prng.rand(1) * size
const dir = prng.rand(1)
return `<g
transform="translate(${x}, ${y})"
clip-path="url(#clip-${N})"
>
${array(2).map(j => {
const lw = prng.rand(size)
const x1 = dir === 0 ? prng.rand(-size, size) : prng.rand(size * 2)
const x2 = x1 + (size + lw * 2) * (dir === 0 ? 1: -1)
return `<line
x1="${x1}"
y1="${-lw}"
x2="${x2}"
y2="${size + lw}"
stroke="${c}"
stroke-width="${lw*.8}"
opacity="${prng.rand(.95, 1.2)}"
/>`
}).join()}
</g>`
}).join('')
}).join('')
}
const shapes = []
for(let i = 64; i >= 4; i /= 2) {
shapes.push(createShapes(i))
}
return shapes.join('')
})()}
</svg>`