Blocks seated on surfaces and inclines with preset force vectors — normal, gravity, friction — sized and directed automatically.
A free-body diagram is two things: the body itself, drawn in contact with
what supports it, and force vectors drawn from its centre of mass at the
correct directions. The DSL does both with two lines — a
block on_incline seat and vector presets.
on_incline=ramp1 at=0.55 seats the block on the slope — it
follows the surface normal, so it stays correct even on mirrored ramps:
canvas 420x260 incline ramp1 x=60 y_base=210 angle=30 run=300 block m1 on_incline=ramp1 at=0.5 w=70 h=45 label="m1"
vector ... on=m1 preset=normal|gravity|friction_up|friction_down
draws the arrow from the block's centre in the physically correct direction —
normal is perpendicular to the contact, gravity always down:
canvas 420x260 incline ramp1 x=60 y_base=210 angle=30 run=300 block m1 on_incline=ramp1 at=0.5 w=70 h=45 label="m1" vector N on=m1 preset=normal len=60 vector W on=m1 preset=gravity len=75 vector Fr on=m1 preset=friction_up len=48
The canonical double-incline — one mirrored ramp, apexes joined so both bases stay grounded (run autoscales):
canvas 640x300 surface ground x=40 y=250 w=560 h=14 incline ramp1 x=60 y_base=250 angle=30 run=240 incline ramp2 x=560 y_base=250 angle=40 run=240 mirror=h ramp1.tip = ramp2.tip block m1 on_incline=ramp1 at=0.55 w=60 h=40 block m2 on_incline=ramp2 at=0.55 w=60 h=40
preset= over manual angle= — presets track
the contact normal automatically.len= sizes arrow length; make W longest when forces are
unbalanced.vector v on=m1 angle=-90 len=60 for an arbitrary direction
(0 = right, −90 = up).