From the web

Text Reflow

A paragraph that re-lays itself around your pointer, live.

Pretext · Canvas 2D

Real text layout at 60fps: every frame, each line is measured and broken around a moving obstacle, the way print designers wrap text around images.

Pretext measures the paragraph once per font size, so each frame only does line breaking. For every line band the circle's chord is computed, which leaves a left and a right segment; each segment is filled with the next run of text from layoutNextLineRange before y advances by one line height. Because y only moves once per band, lines can never overlap.

let cursor = START;
let y = startY;
while (!done && y < height + lh) {
  const segs = [];
  let blocked = false;
  if (r > 1) {
    const nearY = Math.min(Math.max(cy, y), y + lh);
    const dy = nearY - cy;
    if (Math.abs(dy) < r) {
      const half = Math.sqrt(r * r - dy * dy) + PAD;
      blocked = true;
      if (Math.min(x1, cx - half) - x0 >= minW) segs.push([x0, Math.min(x1, cx - half)]);
      if (x1 - Math.max(x0, cx + half) >= minW) segs.push([Math.max(x0, cx + half), x1]);
    }
  }
  if (!blocked) segs.push([x0, x1]);

  for (const [sx0, sx1] of segs) {
    const range = layoutNextLineRange(prepared, cursor, sx1 - sx0);
    if (!range) { done = true; break; }
    out.push({ text: materializeLineRange(prepared, range).text, x: sx0, y });
    cursor = range.end;
  }
  y += lh; // exactly one line height per band
}