JSFiddle - React, Tailwind, and code Playground

HTML

<canvas></canvas>

CSS

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  display: grid;
  place-items: center;
  min-height: 100vh;
}

JavaScript

function vectorize(path) {
  const vectors = []

  if (path.length <= 1) return vectors

  for (let i = 0, j = 1; j < path.length; i++, j++) {
    const end = path[j]
    const start = path[i]
    const vector = {
      x: end.x - start.x,
      y: end.y - start.y,
    }

    vectors.push(vector)
  }

  return vectors
}

function make_line(path) {
  const vectors = vectorize(path)

  return vectors.reduce(
    (thing, current) => {
      const mag = Math.sqrt(current.x ** 2 + current.y ** 2)
      thing.points.push(thing.length + mag)
      thing.length += mag

      return thing
    },
    {
      points: [0],
      length: 0,
    },
  ).points
}

function get_dir(current, next, size) {
  const dir = {
    x: next.x - current.x,
    y: next.y - current.y,
  }
  const mag = Math.sqrt(dir.x ** 2 + dir.y ** 2)

  dir.x *= size / (mag || 1)
  dir.y *= size / (mag || 1)

  return dir
}

function make_path(path, size) {
  const line = make_line(path)
  const endPoints = []

  if (path.length < 2) return endPoints

  let nextIndex, currentPoint, currentLength

  nextIndex = line.findIndex((n) => n > size)
  currentPoint = path[0]
  currentLength = size

  while (nextIndex !== -1 && nextIndex < line.length) {
    const nextPoint = path[nextIndex]
    const dir = get_dir(currentPoint, nextPoint, size)

    endPoints.push(currentPoint)

    currentLength += size

    currentPoint = {
      x: currentPoint.x + dir.x,
      y: currentPoint.y + dir.y,
    }

    nextIndex = line.findIndex((n) => n > currentLength)

    if (nextIndex === -1) endPoints.push(currentPoint)
  }

  return endPoints
}

function is_not_closer_than(minDist, a, b) {
  const sq2 = (a.x - b.x) ** 2 + (a.y - b.y) ** 2
  const d2 = minDist ** 2

  return sq2 >= d2
}

function stroke_path(context, path, lineWidth, strokeStyle) {
  context.beginPath()
  context.lineWidth = lineWidth
  context.strokeStyle = strokeStyle
  context.moveTo(path[0].x, path[0].y)

  for (let i = 1; i < path.length; i++)...