FloatAnimationLib — Float Animation Library

Animates any numeric (float) property of a visual control — position, size, opacity, rotation, scale, and more. This is the most versatile animation type in Plan9Basic, capable of creating smooth transitions, looping effects, and complex motion with 11 interpolation curves and 3 easing modes. 46 functions.

CategoryCountDescription
Error Handling4floatani_error, errormsg$, strerror$, clearerror
Creation & Destruction3floatani# (2 overloads), floatani_free
Playback Control3start, stop, stopatcurrent
Core Properties10propertyname, startvalue, stopvalue, duration, delay (get/set)
Behavior — Easing4animationtype, interpolation (get/set)
Behavior — Flags10autoreverse, inverse, loop, enabled, startfromcurrent (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
floatani_error()floatani_error@Last error code (0 = no error)
floatani_errormsg$()floatani_errormsg$@Last error message as string
floatani_strerror$(code)floatani_strerror$@nDescription for a given error code
floatani_clearerror()floatani_clearerror@Clear the error state

Error Codes

CodeConstantDescription
0ERR_NONENo error
1ERR_NIL_ANIMATIONAnimation pointer is nil
2ERR_INVALID_PROPERTYInvalid property name or object
3ERR_INVALID_VALUEInvalid parameter value
4ERR_ANIMATION_RUNNINGCannot modify while animation is running

How It Works

A float animation smoothly transitions a single numeric property of its parent control from a start value to a stop value over a given duration. The animation is attached to a parent control (rectangle, circle, image, label, etc.) and targets one of its properties by name.

╯ basic pattern
' 1. Create the animation on a parent control
let ani# = floatani#(myControl#)

' 2. Tell it WHAT to animate
floatani_propertyname#(ani#, "Opacity")

' 3. Tell it FROM where TO where
floatani_startvalue#(ani#, 1.0)
floatani_stopvalue#(ani#, 0.0)

' 4. Tell it HOW LONG
floatani_duration#(ani#, 2.0)

' 5. Optionally set easing curve
floatani_interpolation#(ani#, "Quadratic")
floatani_animationtype#(ani#, "InOut")

' 6. Start!
floatani_start(ani#)
ⓘ Key concept: The animation is a child of the control it animates. When you call floatani#(rect#), the animation becomes owned by that rectangle and will animate one of its properties.

Animatable Properties

You can animate any numeric property accessible by name on a FireMonkey control. The most common ones:

Property NameTypeDescriptionTypical Range
Position.XFloatHorizontal position0 – parent width
Position.YFloatVertical position0 – parent height
WidthFloatControl width0+
HeightFloatControl height0+
OpacityFloatTransparency0.0 (invisible) – 1.0 (opaque)
RotationAngleFloatRotation in degrees0 – 360
Scale.XFloatHorizontal scale factor0.0+ (1.0 = normal)
Scale.YFloatVertical scale factor0.0+ (1.0 = normal)
ⓘ Tip: Property names are case-insensitive in FireMonkey. "Opacity", "opacity", and "OPACITY" all work. Dot notation accesses sub-properties: "Position.X", "Scale.Y".

Interpolation Curves

The interpolation type controls the mathematical curve used to transition between values. Combined with an easing type (In/Out/InOut), this creates a wide range of motion effects:

InterpolationCharacterBest For
"Linear"Constant speed, no accelerationProgress bars, continuous rotation
"Quadratic"Gentle curveSubtle, natural-feeling motion
"Cubic"Moderate curveUI transitions, slide-ins
"Quartic"Pronounced curveDramatic entrances/exits
"Quintic"Very pronounced curveEmphatic motion
"Sinusoidal"Sine-wave smoothnessPulsing, breathing effects
"Exponential"Sharp start or endSnap-in or fade-out effects
"Circular"Arc-based accelerationOrbital or circular-feeling motion
"Elastic"Springy overshootBouncy UI, playful interactions
"Back"Overshoots then settlesPull-back effects, attention-grabbing
"Bounce"Bouncing ball effectDrop animations, playful physics

Easing Types (AnimationType)

The easing type controls where the interpolation curve is applied:

TypeEffectDescription
"In"Slow start → fast endAcceleration at the beginning
"Out"Fast start → slow endDeceleration at the end
"InOut"Slow → fast → slowAccelerate then decelerate
╯ easing combinations
' Smooth slide-in: starts fast, decelerates
floatani_interpolation#(ani#, "Cubic")
floatani_animationtype#(ani#, "Out")

' Bouncing drop: drops and bounces at the end
floatani_interpolation#(ani#, "Bounce")
floatani_animationtype#(ani#, "Out")

' Elastic snap: overshoots with springy feel
floatani_interpolation#(ani#, "Elastic")
floatani_animationtype#(ani#, "Out")

' Gentle pulse: smooth in and out
floatani_interpolation#(ani#, "Sinusoidal")
floatani_animationtype#(ani#, "InOut")

Creation & Destruction

FunctionSignatureDescription
floatani#(parent#)floatani#@#Create animation attached to parent control
floatani#(parent#, name$)floatani#@#$Create named animation attached to parent
floatani_free(ani#)floatani_free@#Destroy animation object
ⓘ Note: The parent# parameter is the control being animated, not a layout container. The animation becomes a child component of that control. Named animations are useful for identification when multiple animations exist on one control.

Playback Control

FunctionSignatureDescription
floatani_start(ani#)floatani_start@#Start the animation
floatani_stop(ani#)floatani_stop@#Stop and reset to start value
floatani_stopatcurrent(ani#)floatani_stopatcurrent@#Stop at the current interpolated position
ⓘ Tip: Use floatani_stopatcurrent when you want the property to freeze at wherever it is mid-animation, rather than snapping back to the start value.

Core Properties

Property Name

FunctionSignatureDescription
floatani_propertyname#(ani#, name$)floatani_propertyname#@#$Set which property to animate
floatani_propertyname$(ani#)floatani_propertyname$@#Get the property name

Value Range

FunctionSignatureDescription
floatani_startvalue#(ani#, value)floatani_startvalue#@#nSet starting value
floatani_startvalue(ani#)floatani_startvalue@#Get starting value
floatani_stopvalue#(ani#, value)floatani_stopvalue#@#nSet ending value
floatani_stopvalue(ani#)floatani_stopvalue@#Get ending value

Timing

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

Behavior Flags

Easing & Interpolation

FunctionSignatureDescription
floatani_animationtype#(ani#, type$)floatani_animationtype#@#$Set easing: "In", "Out", "InOut"
floatani_animationtype$(ani#)floatani_animationtype$@#Get current easing type
floatani_interpolation#(ani#, type$)floatani_interpolation#@#$Set interpolation curve (see table above)
floatani_interpolation$(ani#)floatani_interpolation$@#Get current interpolation type

Boolean Flags

FunctionSignatureDescription
floatani_autoreverse#(ani#, flag)floatani_autoreverse#@#nIf 1, plays forward then backward
floatani_autoreverse(ani#)floatani_autoreverse@#Get autoreverse flag
floatani_inverse#(ani#, flag)floatani_inverse#@#nIf 1, plays in reverse direction
floatani_inverse(ani#)floatani_inverse@#Get inverse flag
floatani_loop#(ani#, flag)floatani_loop#@#nIf 1, loops indefinitely
floatani_loop(ani#)floatani_loop@#Get loop flag
floatani_enabled#(ani#, flag)floatani_enabled#@#nEnable or disable the animation
floatani_enabled(ani#)floatani_enabled@#Get enabled state
floatani_startfromcurrent#(ani#, flag)floatani_startfromcurrent#@#nIf 1, ignores startvalue and begins from current property value
floatani_startfromcurrent(ani#)floatani_startfromcurrent@#Get startfromcurrent flag
ⓘ Combining flags: Set autoreverse = 1 + loop = 1 to create a continuous back-and-forth oscillation (e.g., pulsing opacity, breathing scale effect). Set startfromcurrent = 1 when you want to smoothly transition from wherever the property currently is, without jumping to the start value.

State Queries

FunctionSignatureDescription
floatani_running(ani#)floatani_running@#Returns 1 if currently animating
floatani_normalizedtime(ani#)floatani_normalizedtime@#Returns progress from 0.0 to 1.0
floatani_name$(ani#)floatani_name$@#Get the animation’s name (set at creation)

Triggers

Triggers let an animation start or reverse automatically when a parent property changes, without calling floatani_start manually. They use FireMonkey trigger expressions.

FunctionSignatureDescription
floatani_trigger#(ani#, expr$)floatani_trigger#@#$Set trigger expression (starts animation)
floatani_trigger$(ani#)floatani_trigger$@#Get trigger expression
floatani_triggerinverse#(ani#, expr$)floatani_triggerinverse#@#$Set inverse trigger (reverses animation)
floatani_triggerinverse$(ani#)floatani_triggerinverse$@#Get inverse trigger expression
╯ trigger example
' Auto-fade when mouse enters/leaves
floatani_trigger#(ani#, "IsMouseOver=true")
floatani_triggerinverse#(ani#, "IsMouseOver=false")

Events

Each event has a setter and a getter. Use floatani_clearcallbacks# to disconnect all at once.

Event SetterGetterCallback SignatureDescription
floatani_onfinish#(ani#, func$)floatani_onfinish$(ani#)function name(sender#)Fired when animation completes (after all loops)
floatani_onprocess#(ani#, func$)floatani_onprocess$(ani#)function name(sender#)Fired on every animation frame
floatani_clearcallbacks#(ani#)Disconnect all callbacks
⚠ Performance: The onprocess callback fires on every animation frame (typically 60 times per second). Use it sparingly — heavy logic in this callback can cause stuttering. Prefer onfinish when you only need to know when the animation completes.

Complete Examples

Fade In/Out

╯ fade.bas
let frm# = form#("Fade Demo", 400, 300)
form_position#(frm#, 4)

let rect# = rectangle#(frm#, 100, 50, 200, 200)
rectangle_fill#(rect#, "#3498db")

' Fade opacity from 1.0 to 0.2 and back, forever
let fadeAni# = floatani#(rect#)
floatani_propertyname#(fadeAni#, "Opacity")
floatani_startvalue#(fadeAni#, 1.0)
floatani_stopvalue#(fadeAni#, 0.2)
floatani_duration#(fadeAni#, 2.0)
floatani_interpolation#(fadeAni#, "Linear")
floatani_autoreverse#(fadeAni#, 1)
floatani_loop#(fadeAni#, 1)
floatani_start(fadeAni#)

form_show(frm#)

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

Bouncing Ball

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

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

' Animate Y position with bounce easing
let bounceAni# = floatani#(ball#)
floatani_propertyname#(bounceAni#, "Position.Y")
floatani_startvalue#(bounceAni#, 50)
floatani_stopvalue#(bounceAni#, 300)
floatani_duration#(bounceAni#, 1.5)
floatani_interpolation#(bounceAni#, "Bounce")
floatani_animationtype#(bounceAni#, "Out")
floatani_autoreverse#(bounceAni#, 1)
floatani_loop#(bounceAni#, 1)
floatani_start(bounceAni#)

form_show(frm#)

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

Spinning Rectangle

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

let rect# = rectangle#(frm#, 150, 150, 100, 100)
rectangle_fill#(rect#, "#2ecc71")

' Continuous 360-degree rotation
let spinAni# = floatani#(rect#)
floatani_propertyname#(spinAni#, "RotationAngle")
floatani_startvalue#(spinAni#, 0)
floatani_stopvalue#(spinAni#, 360)
floatani_duration#(spinAni#, 2.0)
floatani_interpolation#(spinAni#, "Linear")
floatani_loop#(spinAni#, 1)
floatani_start(spinAni#)

form_show(frm#)

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

Pulsing Scale

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

let circ# = circle#(frm#, 150, 150, 100, 100)
circle_fill#(circ#, "#9b59b6")

' Pulse Scale.X
let scaleX# = floatani#(circ#)
floatani_propertyname#(scaleX#, "Scale.X")
floatani_startvalue#(scaleX#, 1.0)
floatani_stopvalue#(scaleX#, 1.2)
floatani_duration#(scaleX#, 0.5)
floatani_interpolation#(scaleX#, "Sinusoidal")
floatani_animationtype#(scaleX#, "InOut")
floatani_autoreverse#(scaleX#, 1)
floatani_loop#(scaleX#, 1)
floatani_start(scaleX#)

' Pulse Scale.Y in sync
let scaleY# = floatani#(circ#)
floatani_propertyname#(scaleY#, "Scale.Y")
floatani_startvalue#(scaleY#, 1.0)
floatani_stopvalue#(scaleY#, 1.2)
floatani_duration#(scaleY#, 0.5)
floatani_interpolation#(scaleY#, "Sinusoidal")
floatani_animationtype#(scaleY#, "InOut")
floatani_autoreverse#(scaleY#, 1)
floatani_loop#(scaleY#, 1)
floatani_start(scaleY#)

form_show(frm#)

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

Slide with Finish Callback

╯ slide.bas
let frm# = form#("Slide Demo", 500, 300)
form_position#(frm#, 4)

let rect# = rectangle#(frm#, 0, 100, 80, 80)
rectangle_fill#(rect#, "#e67e22")

let lbl# = label#(frm#, "Sliding...")
label_bounds#(lbl#, 180, 250, 140, 25)

' Slide across the screen
let slideAni# = floatani#(rect#)
floatani_propertyname#(slideAni#, "Position.X")
floatani_startvalue#(slideAni#, 0)
floatani_stopvalue#(slideAni#, 420)
floatani_duration#(slideAni#, 3.0)
floatani_interpolation#(slideAni#, "Cubic")
floatani_animationtype#(slideAni#, "InOut")
floatani_onfinish#(slideAni#, "OnSlideComplete")
floatani_start(slideAni#)

form_show(frm#)

function OnSlideComplete(sender#)
    label_text#(lbl#, "Done!")
    ' Reverse direction and go back
    floatani_inverse#(sender#, 1)
    floatani_start(sender#)
endfunction

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

Multiple Animations on One Control

╯ combined.bas
let frm# = form#("Combined Animations", 500, 400)
form_position#(frm#, 4)

let rect# = rectangle#(frm#, 50, 150, 80, 80)
rectangle_fill#(rect#, "#1abc9c")

' Slide horizontally
let moveAni# = floatani#(rect#, "MoveX")
floatani_propertyname#(moveAni#, "Position.X")
floatani_startvalue#(moveAni#, 50)
floatani_stopvalue#(moveAni#, 370)
floatani_duration#(moveAni#, 3.0)
floatani_interpolation#(moveAni#, "Linear")
floatani_autoreverse#(moveAni#, 1)
floatani_loop#(moveAni#, 1)

' Spin while sliding
let spinAni# = floatani#(rect#, "Spin")
floatani_propertyname#(spinAni#, "RotationAngle")
floatani_startvalue#(spinAni#, 0)
floatani_stopvalue#(spinAni#, 360)
floatani_duration#(spinAni#, 1.5)
floatani_interpolation#(spinAni#, "Linear")
floatani_loop#(spinAni#, 1)

' Fade in and out
let fadeAni# = floatani#(rect#, "Fade")
floatani_propertyname#(fadeAni#, "Opacity")
floatani_startvalue#(fadeAni#, 1.0)
floatani_stopvalue#(fadeAni#, 0.3)
floatani_duration#(fadeAni#, 2.0)
floatani_interpolation#(fadeAni#, "Sinusoidal")
floatani_animationtype#(fadeAni#, "InOut")
floatani_autoreverse#(fadeAni#, 1)
floatani_loop#(fadeAni#, 1)

' Start all three at once
floatani_start(moveAni#)
floatani_start(spinAni#)
floatani_start(fadeAni#)

form_show(frm#)

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

Best Practices

PracticeWhy
Use autoreverse + loop for continuous oscillationCreates smooth back-and-forth without manual restart
Use "Linear" for continuous rotationOther interpolations create uneven speed, noticeable in looped spins
Use "Cubic" + "Out" for UI slide-insFeels natural — fast entry, gentle deceleration
Use "Bounce" + "Out" for playful dropsObjects appear to fall and bounce realistically
Use "Sinusoidal" + "InOut" for pulsingMost natural breathing/heartbeat rhythm
Use startfromcurrent = 1 for smooth interruptionsAvoids jarring jumps when restarting mid-animation
Avoid heavy logic in onprocessCalled every frame (~60/sec) — can cause stuttering
Name animations with floatani#(parent#, name$)Easier to identify when multiple animations on one control
Pair Scale.X and Scale.Y animationsAnimating only one axis creates distortion (unless that’s intended)
Use delay for staggered animationsDifferent delays on multiple controls create cascade effects

Quick Reference

FunctionSignatureDescription
floatani_error / errormsg$ / strerror$ / clearerrorvariousError handling (4)
floatani#(parent#[, name$])floatani#@# / floatani#@#$Create (2 overloads)
floatani_free(ani#)floatani_free@#Destroy
floatani_start / stop / stopatcurrentvariousPlayback control (3)
floatani_propertyname# / propertyname$variousTarget property (2)
floatani_startvalue / stopvaluevariousValue range (4)
floatani_duration / delayvariousTiming (4)
floatani_animationtype / interpolationvariousEasing & curves (4)
floatani_autoreverse / inverse / loop / enabled / startfromcurrentvariousBehavior flags (10)
floatani_running / normalizedtime / name$variousState queries (3)
floatani_trigger / triggerinversevariousAutomatic triggers (4)
floatani_onfinish / onprocess / clearcallbacks#variousEvents (5)

46 functions. Part of the Plan9Basic Animation library system.