svg`<svg width="${w}" height="${h}">
<rect x="0" y="0" width="${w}" height="${h}" stroke="none" fill="${palette[0]}"></rect>
<g>
${(() => {
return array(n).map(() => {
let v = PVector.random(PVector(-w/4, -h/4), PVector(w*5/4, h*5/4))
const pts = [v.clone()]
let sideA = []
let sideB = []
array(trailLength).forEach(i => {
const angle = simplex.noise3D(v.x/noiseScale, v.y/noiseScale, seed) * TAU/2
const dir = PVector.fromAngle(angle)
v.add(dir.clone().setMag(stepLength))
pts.push(v.clone())
sideA.push(v.clone().add(dir.clone().rotateBy(Math.PI/2).setMag((i/trailLength) * strokeWeight)))
sideB.push(v.clone().add(dir.clone().rotateBy(-Math.PI/2).setMag((i/trailLength) * strokeWeight)))
})
sideA.push(v.clone())
sideB.push(v.clone())
sideB.reverse()
const c = palette[1 + (palette.length - 1) * Math.random() | 0]
return `<g opacity="0.9">
<polygon
points="${[...sideA, ...sideB].map(d => `${d.x},${d.y}`).join(' ')}"
stroke="none"
fill="${c}"
/>
<circle cx="${v.x}" cy="${v.y}" r="${strokeWeight - .5}"
stroke="none"
fill="${c}"
/>
</g>`
}).join('\n')
})()}
</g>
</svg>`