Here is a semi-automated version using mannot:
#import "@preview/mannot:0.3.0": annot-cetz, mark
#import "@preview/cetz:0.4.1"
#let bent-arrow(from, to, body, bend: 0.1, shrink: 0.04) = {
import cetz.draw: arc-through, content, set-style
let mid = (rel: (bend, 0), to: (from, 50%, to))
set-style(mark: (end: ">", fill: black, scale: 0.5))
arc-through((rel: (0, -shrink), to: from), mid, (rel: (0, shrink), to: to))
content(mid, anchor: "west", pad(0.5em, body))
}
#let mark-line(tag) = mark(tag: tag)[]
#let arrow(from, to, body) = bent-arrow(from, to, body)
#let arrow-coords(ctx, ..coords) = {
let (_, ..coords) = cetz.coordinate.resolve(ctx, ..coords)
let right-most = calc.max(..coords.map(v => v.first())) + 0.2
coords.map(v => (right-most, v.at(1)))
}
$
x^2 + 5x & = 2x^2 #mark-line(<a>) \
-x^2 + 5x & = 0 #mark-line(<b>) \
x_(1,2) & = (-5 plus.minus sqrt(25)) / (-2) #mark-line(<c>) \
x_(1,2) & = 0, 5 #mark-line(<d>) \
#annot-cetz((<a>, <b>, <c>, <d>), cetz, cetz.draw.get-ctx(ctx => {
let (a, b, c, d) = arrow-coords(ctx, "a", "b", "c", "d")
arrow(a, b)[$-2x^2$]
arrow(b, c)[Quadratic Formula]
arrow(c, d)[Simplify]
}))
$
A fully automated version would require more code, and less verbose syntax — even more code. Latex witharrows in typst - #4 by bluss does give a somewhat 1 to 1 solution.
