PathAnimationLib — Path Animation Library

Animates a control along a path defined using SVG-like path syntax. Perfect for complex motion — curves, orbits, figure-8 patterns, bouncing trajectories, and wave paths. The control follows the path as a trajectory, and can optionally rotate to face its direction of travel. 43 functions.

CategoryCountDescription
Error Handling4pathani_error, errormsg$, strerror$, clearerror
Creation & Destruction3pathani# (2 overloads), pathani_free
Playback Control3start, stop, stopatcurrent
Path Data & Rotation5path# (set), path$ (get), clearpath#, rotate (get/set)
Timing4duration, delay (get/set)
Behavior — Easing4animationtype, interpolation (get/set)
Behavior — Flags8autoreverse, inverse, loop, enabled (get/set)
State Queries3running, normalizedtime, name$
Triggers4trigger, triggerinverse (get/set)
Events5onfinish, onprocess (get/set), clearcallbacks#

Cross-Platform Support

PlatformStatusNotes
Windows✅ Full SupportWin32/Win64
Linux✅ Full SupportGTK-based
Android✅ Full SupportHardware-accelerated

Error Handling

FunctionSignatureDescription
pathani_error()pathani_error@Last error code (0 = no error)
pathani_errormsg$()pathani_errormsg$@Last error message as string
pathani_strerror$(code)pathani_strerror$@nDescription for a given error code
pathani_clearerror()pathani_clearerror@Clear the error state

Error Codes

CodeConstantDescription
0ERR_NONENo error
1ERR_NIL_ANIMATIONAnimation pointer is nil
2ERR_INVALID_PATHInvalid path data string
3ERR_INVALID_VALUEInvalid parameter value
4ERR_ANIMATION_RUNNINGCannot modify while animation is running

How It Works

A path animation moves a control along a trajectory described by an SVG path string. The control’s position is interpolated along the path from start to end over the given duration. You define the trajectory with standard SVG path commands — lines, curves, arcs — and the animation engine handles the rest:

╯ basic pattern
' 1. Create the animation on a control
let ani# = pathani#(myCircle#)

' 2. Define the path (SVG syntax)
pathani_path#(ani#, "M 50,200 C 150,50 350,350 450,200")

' 3. Optionally rotate to follow the path
pathani_rotate#(ani#, 1)

' 4. Set timing
pathani_duration#(ani#, 3.0)

' 5. Start!
pathani_start(ani#)
ⓘ Key difference from other animations: Path animation controls the control’s position along a 2D trajectory. It does not animate a named property — it moves the entire control through space. Use pathani_rotate#(ani#, 1) to make the control face its direction of travel (great for arrows, vehicles, or directional objects).

SVG Path Commands

Path data uses standard SVG path syntax. Uppercase commands use absolute coordinates; lowercase commands use relative offsets from the current position.

Movement & Lines

CommandParametersDescription
M / mx, yMove to position (absolute / relative)
L / lx, yLine to position (absolute / relative)
H / hxHorizontal line to X (absolute / relative)
V / vyVertical line to Y (absolute / relative)
Z / zClose path (line back to start point)

Cubic Bézier Curves

CommandParametersDescription
C / cx1,y1 x2,y2 x,yCubic Bézier with two control points
S / sx2,y2 x,ySmooth cubic — mirrors previous control point

Quadratic Bézier Curves

CommandParametersDescription
Q / qx1,y1 x,yQuadratic Bézier with one control point
T / tx,ySmooth quadratic — mirrors previous control point

Arcs

CommandParametersDescription
A / arx,ry rot large,sweep x,yElliptical arc to endpoint
╯ path syntax examples
' Straight horizontal line
"M 0,100 L 400,100"

' Square loop
"M 50,50 L 350,50 L 350,350 L 50,350 Z"

' S-curve (cubic Bézier)
"M 50,200 C 150,50 200,350 300,200 S 400,50 450,200"

' Full circle (two arcs)
"M 50,175 A 150,150 0 1,1 350,175 A 150,150 0 1,1 50,175"

' Bouncing trajectory (quadratic)
"M 25,300 Q 100,50 175,300 Q 250,100 325,300 Q 400,150 425,300"

Interpolation & Easing

Interpolation and easing control how fast the control moves along the path, not the shape of the path itself. The path geometry is fixed; the easing changes the speed profile:

Interpolation Curves

InterpolationCharacterBest For
"Linear"Constant speed along pathOrbits, continuous loops, steady motion
"Quadratic"Gentle accelerationSmooth starts
"Cubic"Moderate curveNatural-feeling traversal
"Sinusoidal"Sine-wave speedOscillating speed along path
"Elastic"Springy speedPlayful, bouncy traversal
"Bounce"Bouncing speedStop-and-go at end of path

Easing Types (AnimationType)

TypeEffectDescription
"In"Slow start → fast endObject accelerates along path
"Out"Fast start → slow endObject decelerates along path
"InOut"Slow → fast → slowAccelerate then decelerate
ⓘ Tip: Use "Linear" for most path animations. It gives constant speed along the path, which feels natural for orbits, figure-8s, and looping motion. Other curves change the speed while the trajectory remains the same.

Creation & Destruction

FunctionSignatureDescription
pathani#(parent#)pathani#@#Create animation attached to parent control
pathani#(parent#, name$)pathani#@#$Create named animation attached to parent
pathani_free(ani#)pathani_free@#Destroy animation object

Playback Control

FunctionSignatureDescription
pathani_start(ani#)pathani_start@#Start the animation
pathani_stop(ani#)pathani_stop@#Stop and reset to path start
pathani_stopatcurrent(ani#)pathani_stopatcurrent@#Stop at current position on path

Path Data & Rotation

Path Data

FunctionSignatureDescription
pathani_path#(ani#, pathdata$)pathani_path#@#$Set SVG path data string
pathani_path$(ani#)pathani_path$@#Get path data string
pathani_clearpath#(ani#)pathani_clearpath#@#Clear path data

Rotation

FunctionSignatureDescription
pathani_rotate#(ani#, flag)pathani_rotate#@#nIf 1, control rotates to follow path tangent
pathani_rotate(ani#)pathani_rotate@#Get rotate flag
ⓘ Rotation: When rotate = 1, the control automatically rotates to face the direction it is traveling along the path. This is ideal for arrow shapes, vehicles, fish, birds, or any object that should “point forward” along its trajectory.

Timing

FunctionSignatureDescription
pathani_duration#(ani#, seconds)pathani_duration#@#nSet duration in seconds
pathani_duration(ani#)pathani_duration@#Get duration
pathani_delay#(ani#, seconds)pathani_delay#@#nSet delay before animation starts
pathani_delay(ani#)pathani_delay@#Get delay

Behavior Flags

Easing & Interpolation

FunctionSignatureDescription
pathani_animationtype#(ani#, type$)pathani_animationtype#@#$Set easing: "In", "Out", "InOut"
pathani_animationtype$(ani#)pathani_animationtype$@#Get easing type
pathani_interpolation#(ani#, type$)pathani_interpolation#@#$Set interpolation curve
pathani_interpolation$(ani#)pathani_interpolation$@#Get interpolation type

Boolean Flags

FunctionSignatureDescription
pathani_autoreverse#(ani#, flag)pathani_autoreverse#@#nIf 1, plays forward then backward along path
pathani_autoreverse(ani#)pathani_autoreverse@#Get autoreverse flag
pathani_inverse#(ani#, flag)pathani_inverse#@#nIf 1, traverses path in reverse
pathani_inverse(ani#)pathani_inverse@#Get inverse flag
pathani_loop#(ani#, flag)pathani_loop#@#nIf 1, loops indefinitely
pathani_loop(ani#)pathani_loop@#Get loop flag
pathani_enabled#(ani#, flag)pathani_enabled#@#nEnable or disable the animation
pathani_enabled(ani#)pathani_enabled@#Get enabled state

State Queries

FunctionSignatureDescription
pathani_running(ani#)pathani_running@#Returns 1 if currently animating
pathani_normalizedtime(ani#)pathani_normalizedtime@#Returns progress from 0.0 to 1.0
pathani_name$(ani#)pathani_name$@#Get the animation’s name

Triggers

FunctionSignatureDescription
pathani_trigger#(ani#, expr$)pathani_trigger#@#$Set trigger expression (starts animation)
pathani_trigger$(ani#)pathani_trigger$@#Get trigger expression
pathani_triggerinverse#(ani#, expr$)pathani_triggerinverse#@#$Set inverse trigger (reverses animation)
pathani_triggerinverse$(ani#)pathani_triggerinverse$@#Get inverse trigger expression

Events

Event SetterGetterCallback SignatureDescription
pathani_onfinish#(ani#, func$)pathani_onfinish$(ani#)function name(sender#)Fired when animation completes
pathani_onprocess#(ani#, func$)pathani_onprocess$(ani#)function name(sender#)Fired on every animation frame
pathani_clearcallbacks#(ani#)Disconnect all callbacks

Complete Examples

Straight Line

╯ line-path.bas
let frm# = form#("Line Path Demo", 400, 300)
form_position#(frm#, 4)

let ball# = circle#(frm#, 0, 125, 50, 50)
circle_fill#(ball#, "#e74c3c")

let pathAni# = pathani#(ball#)
pathani_path#(pathAni#, "M 0,125 L 350,125")
pathani_duration#(pathAni#, 2.0)
pathani_interpolation#(pathAni#, "Sinusoidal")
pathani_animationtype#(pathAni#, "InOut")
pathani_autoreverse#(pathAni#, 1)
pathani_loop#(pathAni#, 1)
pathani_start(pathAni#)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Square Loop

╯ square-path.bas
let frm# = form#("Square Path Demo", 400, 400)
form_position#(frm#, 4)

let ball# = circle#(frm#, 50, 50, 40, 40)
circle_fill#(ball#, "#3498db")

let pathAni# = pathani#(ball#)
pathani_path#(pathAni#, "M 50,50 L 310,50 L 310,310 L 50,310 Z")
pathani_duration#(pathAni#, 4.0)
pathani_interpolation#(pathAni#, "Linear")
pathani_loop#(pathAni#, 1)
pathani_start(pathAni#)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Circular Orbit

╯ orbit.bas
let frm# = form#("Orbit Demo", 400, 400)
form_position#(frm#, 4)

' Center marker
let center# = circle#(frm#, 190, 190, 20, 20)
circle_fill#(center#, "Gray")

' Orbiting planet
let planet# = circle#(frm#, 50, 175, 50, 50)
circle_fill#(planet#, "#e67e22")

' Full circle using two arc commands
let pathAni# = pathani#(planet#)
pathani_path#(pathAni#, "M 50,175 A 150,150 0 1,1 350,175 A 150,150 0 1,1 50,175")
pathani_duration#(pathAni#, 3.0)
pathani_interpolation#(pathAni#, "Linear")
pathani_loop#(pathAni#, 1)
pathani_start(pathAni#)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

S-Curve with Rotation

╯ s-curve.bas
let frm# = form#("Curve Path Demo", 500, 400)
form_position#(frm#, 4)

' Arrow shape that will rotate to follow the path
let arrow# = path#(frm#)
path_data#(arrow#, "M 0,-15 L 30,0 L 0,15 Z")
path_fill#(arrow#, "#2ecc71")
path_move#(arrow#, 50, 200)

' S-curve with rotation enabled
let pathAni# = pathani#(arrow#)
pathani_path#(pathAni#, "M 50,200 C 150,50 200,350 300,200 S 400,50 450,200")
pathani_duration#(pathAni#, 4.0)
pathani_rotate#(pathAni#, 1)
pathani_interpolation#(pathAni#, "Linear")
pathani_loop#(pathAni#, 1)
pathani_start(pathAni#)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Figure-8

╯ figure8.bas
let frm# = form#("Figure-8 Demo", 500, 400)
form_position#(frm#, 4)

let ball# = circle#(frm#, 50, 175, 50, 50)
circle_fill#(ball#, "#9b59b6")

' Figure-8 using cubic Bézier curves
let p$ = "M 50,175 C 50,50 200,50 250,175 "
p$ = p$ + "C 300,300 450,300 450,175 "
p$ = p$ + "C 450,50 300,50 250,175 "
p$ = p$ + "C 200,300 50,300 50,175"

let pathAni# = pathani#(ball#)
pathani_path#(pathAni#, p$)
pathani_duration#(pathAni#, 5.0)
pathani_interpolation#(pathAni#, "Linear")
pathani_loop#(pathAni#, 1)
pathani_start(pathAni#)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Bouncing Ball Trajectory

╯ bounce-path.bas
let frm# = form#("Bounce Path Demo", 500, 400)
form_position#(frm#, 4)

let ball# = circle#(frm#, 25, 300, 50, 50)
circle_fill#(ball#, "#e74c3c")

' Bouncing arcs using quadratic Bézier
let pathAni# = pathani#(ball#)
pathani_path#(pathAni#, "M 25,300 Q 100,50 175,300 Q 250,100 325,300 Q 400,150 425,300")
pathani_duration#(pathAni#, 3.0)
pathani_interpolation#(pathAni#, "Linear")
pathani_autoreverse#(pathAni#, 1)
pathani_loop#(pathAni#, 1)
pathani_start(pathAni#)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Best Practices

PracticeWhy
Always start paths with M x,yRequired — defines the starting position on the path
Use "Linear" interpolation for orbits and loopsConstant speed feels natural for continuous circular or looping motion
Use Z to close looping pathsCreates a seamless return to start; essential for square/polygon paths
Enable rotate = 1 for directional objectsArrows, vehicles, fish, and similar shapes should face their travel direction
Use two A arc commands for full circlesSVG arcs cannot draw a full 360° in one command; use two 180° arcs
Build long paths with string concatenationKeeps code readable: p$ = p$ + "C ..."
Use Q for bouncing trajectoriesQuadratic curves create natural parabolic bounce arcs
Use C / S for smooth S-curvesCubic Béziers give the most control over curve shape
Use clearpath# before setting a new pathClean reset when dynamically changing paths at runtime
Uppercase commands for absolute, lowercase for relativeRelative is useful when reusing path segments at different offsets

Quick Reference

FunctionSignatureDescription
pathani_error / errormsg$ / strerror$ / clearerrorvariousError handling (4)
pathani#(parent#[, name$])pathani#@# / pathani#@#$Create (2 overloads)
pathani_free(ani#)pathani_free@#Destroy
pathani_start / stop / stopatcurrentvariousPlayback control (3)
pathani_path# / path$ / clearpath#variousPath data (3)
pathani_rotate# / rotatevariousAuto-rotation (2)
pathani_duration / delayvariousTiming (4)
pathani_animationtype / interpolationvariousEasing & curves (4)
pathani_autoreverse / inverse / loop / enabledvariousBehavior flags (8)
pathani_running / normalizedtime / name$variousState queries (3)
pathani_trigger / triggerinversevariousAutomatic triggers (4)
pathani_onfinish / onprocess / clearcallbacks#variousEvents (5)

43 functions. Part of the Plan9Basic Animation library system.