function drawCurves(pts, indices) {
const lines = indices.map(({ from, to }) => {
const hasVerticalBias =
Math.abs(from[0] - to[0]) >= Math.abs(from[1] - to[1]);
const points = hasVerticalBias
? [from, to].sort((a, b) => a[0] - b[0])
: [from, to].sort((a, b) => a[1] - b[1]);
const p1 = pts[points[0][1]][points[0][0]];
const x1 = bounds.x + math.lerp(0, bounds.width, p1.uv[0]);
const y1 = bounds.y + math.lerp(0, bounds.height, p1.uv[1]);
const p2 = pts[points[1][1]][points[1][0]];
const x2 = bounds.x + math.lerp(0, bounds.width, p2.uv[0]);
const y2 = bounds.y + math.lerp(0, bounds.height, p2.uv[1]);
const kx = hasVerticalBias ? Math.abs(x1 - x2) / 2 : 0;
const ky = hasVerticalBias ? 0 : Math.abs(y1 - y2) / 2;
const path = d3.path();
path.moveTo(x1, y1);
path.bezierCurveTo(x1 + kx, y1 + ky, x2 - kx, y2 - ky, x2, y2);
const r = 8;
return svg`<path
d=${path.toString()}
fill=none
stroke=${palette.curve}
></path>
<g fill=${palette.fgFill} stroke=${palette.curve} stroke-width="1">
<circle cx=${x1} cy=${y1} r=${r}></circle>
<circle cx=${x2} cy=${y2} r=${r}></circle>
</g>`;
});
return svg`<g>${lines}</g>`;
}