svg`<svg width="${width}" height="${width * ratio}" >
<g transform="scale(${width/w})">
<rect width="${w}" height="${h}" stroke="blue" fill="none" stroke-width="${1/(width/w)}" />
<g transform="translate(${(w - (nx - 1) * gridSize) / 2}, ${(h - (ny - 1) * gridSize) / 2})" >
${array(nx * ny).map(index => {
const x = index % nx
const y = index / nx | 0
const pt = PVector(x, y)
const closest = pts[
pts.map((p, i) => ({index: i, dist: pt.dist(p)}))
.sort((a, b) => a.dist > b.dist ? 1 : a.dist < b.dist ? -1 : 0)[0].index
]
return `<line
stroke="black"
opacity="0.3"
stroke-width="${1/(width/w)}"
fill="none"
x1="${pt.x * gridSize}" y1="${pt.y * gridSize}"
x2="${closest.x * gridSize}" y2="${closest.y * gridSize}"
/>`
}).join('\n')}
</g>
</g>
</svg>`