RectAnimationLib — Rect Animation Library
Animates the bounds (position and size) of a visual control as a single composite animation. Unlike FloatAnimationLib which targets one property at a time, RectAnimationLib animates Position.X, Position.Y, Width, and Height simultaneously — making it ideal for expand/collapse, slide-and-resize, thumbnail-to-fullscreen, and card-flip effects. 44 functions.
| Category | Count | Description |
|---|---|---|
| Error Handling | 4 | rectani_error, errormsg$, strerror$, clearerror |
| Creation & Destruction | 3 | rectani# (2 overloads), rectani_free |
| Playback Control | 3 | start, stop, stopatcurrent |
| Bounds — Start | 5 | startbounds# (setter), startx, starty, startwidth, startheight (getters) |
| Bounds — Stop | 5 | stopbounds# (setter), stopx, stopy, stopwidth, stopheight (getters) |
| Timing | 4 | duration, delay (get/set) |
| Behavior — Easing | 4 | animationtype, interpolation (get/set) |
| Behavior — Flags | 8 | autoreverse, inverse, loop, enabled (get/set) |
| State Queries | 3 | running, normalizedtime, name$ |
| Events | 5 | onfinish, onprocess (get/set), clearcallbacks# |
Cross-Platform Support
| Platform | Status | Notes |
|---|---|---|
| Windows | ✅ Full Support | Win32/Win64 |
| Linux | ✅ Full Support | GTK-based |
| Android | ✅ Full Support | Hardware-accelerated |
Error Handling
| Function | Signature | Description |
|---|---|---|
rectani_error() | rectani_error@ | Last error code (0 = no error) |
rectani_errormsg$() | rectani_errormsg$@ | Last error message as string |
rectani_strerror$(code) | rectani_strerror$@n | Description for a given error code |
rectani_clearerror() | rectani_clearerror@ | Clear the error state |
Error Codes
| Code | Constant | Description |
|---|---|---|
| 0 | ERR_NONE | No error |
| 1 | ERR_NIL_ANIMATION | Animation pointer is nil |
| 2 | ERR_INVALID_PROPERTY | Invalid property or object |
| 3 | ERR_INVALID_VALUE | Invalid bounds value |
| 4 | ERR_ANIMATION_RUNNING | Cannot modify while animation is running |
How It Works
RectAnimationLib works differently from the other animation libraries. Instead of targeting a single named property, it always animates all four bounds values at once: X, Y, Width, and Height. You define a start rectangle and a stop rectangle, and the animation interpolates all four values simultaneously:
' 1. Create the animation on a control let ani# = rectani#(myRect#) ' 2. Define start bounds (x, y, width, height) rectani_startbounds#(ani#, 150, 150, 100, 100) ' 3. Define stop bounds (x, y, width, height) rectani_stopbounds#(ani#, 50, 50, 300, 300) ' 4. Set timing and easing rectani_duration#(ani#, 1.5) rectani_interpolation#(ani#, "Cubic") rectani_animationtype#(ani#, "Out") ' 5. Start! rectani_start(ani#)
propertyname function. It always targets the control’s bounds (position + size) as a composite unit.Rect vs Float Animation
Choose the right animation library based on what you need to animate:
| Scenario | Recommended | Why |
|---|---|---|
| Animate position only (slide) | FloatAnimationLib | Target Position.X or Position.Y individually |
| Animate size only (grow/shrink) | FloatAnimationLib | Target Width or Height individually |
| Animate opacity, rotation, scale | FloatAnimationLib | These are single float properties |
| Move and resize simultaneously | RectAnimationLib | Animates all 4 bounds as one unit |
| Expand/collapse effects | RectAnimationLib | Position and size must change together |
| Thumbnail → fullscreen zoom | RectAnimationLib | Coordinated move + resize |
| Card flip (width to 0 and back) | RectAnimationLib | X position shifts as width collapses |
| Slide panel from off-screen | RectAnimationLib | Position changes while size stays constant |
Interpolation & Easing
Interpolation Curves
| Interpolation | Character | Best For |
|---|---|---|
"Linear" | Constant speed | Mechanical, even motion |
"Quadratic" | Gentle curve | Smooth panel slides |
"Cubic" | Moderate curve | UI expand/collapse (most common) |
"Quartic" | Pronounced curve | Dramatic size changes |
"Quintic" | Very pronounced | Emphatic motion |
"Sinusoidal" | Sine-wave smooth | Card flip effects |
"Exponential" | Sharp curve | Snap-open dialogs |
"Circular" | Arc-based | Organic feeling motion |
"Elastic" | Springy overshoot | Bouncy expand effects |
"Back" | Overshoots then settles | Thumbnail zoom with overshoot |
"Bounce" | Bouncing ball | Playful expand/collapse |
Easing Types (AnimationType)
| Type | Effect | Description |
|---|---|---|
"In" | Slow start → fast end | Accelerating resize |
"Out" | Fast start → slow end | Decelerating resize (most natural) |
"InOut" | Slow → fast → slow | Smooth start and end |
Creation & Destruction
| Function | Signature | Description |
|---|---|---|
rectani#(parent#) | rectani#@# | Create animation attached to parent control |
rectani#(parent#, name$) | rectani#@#$ | Create named animation attached to parent |
rectani_free(ani#) | rectani_free@# | Destroy animation object |
Playback Control
| Function | Signature | Description |
|---|---|---|
rectani_start(ani#) | rectani_start@# | Start the animation |
rectani_stop(ani#) | rectani_stop@# | Stop and reset to start bounds |
rectani_stopatcurrent(ani#) | rectani_stopatcurrent@# | Stop at current interpolated bounds |
Bounds (Start / Stop)
Instead of a single start/stop value, RectAnimationLib uses rectangles defined by four values: X, Y, Width, Height. The setter takes all four at once; individual getters let you read each component.
Start Bounds
| Function | Signature | Description |
|---|---|---|
rectani_startbounds#(ani#, x, y, w, h) | rectani_startbounds#@#nnnn | Set starting rectangle (x, y, width, height) |
rectani_startx(ani#) | rectani_startx@# | Get starting X position |
rectani_starty(ani#) | rectani_starty@# | Get starting Y position |
rectani_startwidth(ani#) | rectani_startwidth@# | Get starting width |
rectani_startheight(ani#) | rectani_startheight@# | Get starting height |
Stop Bounds
| Function | Signature | Description |
|---|---|---|
rectani_stopbounds#(ani#, x, y, w, h) | rectani_stopbounds#@#nnnn | Set ending rectangle (x, y, width, height) |
rectani_stopx(ani#) | rectani_stopx@# | Get ending X position |
rectani_stopy(ani#) | rectani_stopy@# | Get ending Y position |
rectani_stopwidth(ani#) | rectani_stopwidth@# | Get ending width |
rectani_stopheight(ani#) | rectani_stopheight@# | Get ending height |
Timing
| Function | Signature | Description |
|---|---|---|
rectani_duration#(ani#, seconds) | rectani_duration#@#n | Set duration in seconds |
rectani_duration(ani#) | rectani_duration@# | Get duration |
rectani_delay#(ani#, seconds) | rectani_delay#@#n | Set delay before animation starts |
rectani_delay(ani#) | rectani_delay@# | Get delay |
Behavior Flags
Easing & Interpolation
| Function | Signature | Description |
|---|---|---|
rectani_animationtype#(ani#, type$) | rectani_animationtype#@#$ | Set easing: "In", "Out", "InOut" |
rectani_animationtype$(ani#) | rectani_animationtype$@# | Get easing type |
rectani_interpolation#(ani#, type$) | rectani_interpolation#@#$ | Set interpolation curve |
rectani_interpolation$(ani#) | rectani_interpolation$@# | Get interpolation type |
Boolean Flags
| Function | Signature | Description |
|---|---|---|
rectani_autoreverse#(ani#, flag) | rectani_autoreverse#@#n | If 1, plays forward then backward |
rectani_autoreverse(ani#) | rectani_autoreverse@# | Get autoreverse flag |
rectani_inverse#(ani#, flag) | rectani_inverse#@#n | If 1, plays in reverse direction |
rectani_inverse(ani#) | rectani_inverse@# | Get inverse flag |
rectani_loop#(ani#, flag) | rectani_loop#@#n | If 1, loops indefinitely |
rectani_loop(ani#) | rectani_loop@# | Get loop flag |
rectani_enabled#(ani#, flag) | rectani_enabled#@#n | Enable or disable the animation |
rectani_enabled(ani#) | rectani_enabled@# | Get enabled state |
rectani_inverse# to toggle between expand and collapse. Set inverse = 0 to play forward (start → stop), inverse = 1 to play backward (stop → start). This is the standard pattern for expand/collapse buttons and sliding panels.State Queries
| Function | Signature | Description |
|---|---|---|
rectani_running(ani#) | rectani_running@# | Returns 1 if currently animating |
rectani_normalizedtime(ani#) | rectani_normalizedtime@# | Returns progress from 0.0 to 1.0 |
rectani_name$(ani#) | rectani_name$@# | Get the animation’s name |
Events
| Event Setter | Getter | Callback Signature | Description |
|---|---|---|---|
rectani_onfinish#(ani#, func$) | rectani_onfinish$(ani#) | function name(sender#) | Fired when animation completes |
rectani_onprocess#(ani#, func$) | rectani_onprocess$(ani#) | function name(sender#) | Fired on every animation frame |
rectani_clearcallbacks#(ani#) | — | — | Disconnect all callbacks |
Complete Examples
Expand / Collapse
let frm# = form#("Expand Demo", 400, 400) form_position#(frm#, 4) let rect# = rectangle#(frm#, 150, 150, 100, 100) rectangle_fill#(rect#, "#3498db") ' Small centered → large centered, with elastic bounce let rectAni# = rectani#(rect#) rectani_startbounds#(rectAni#, 150, 150, 100, 100) rectani_stopbounds#(rectAni#, 50, 50, 300, 300) rectani_duration#(rectAni#, 1.5) rectani_interpolation#(rectAni#, "Elastic") rectani_animationtype#(rectAni#, "Out") rectani_autoreverse#(rectAni#, 1) rectani_loop#(rectAni#, 1) rectani_start(rectAni#) form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Thumbnail to Full Size (with Button Toggle)
let frm# = form#("Thumbnail Demo", 500, 400) form_position#(frm#, 4) let img# = image#(frm#, 20, 20, 80, 80) image_load#(img#, "https://picsum.photos/400/300") ' Animate from thumbnail to full size with overshoot let rectAni# = rectani#(img#) rectani_startbounds#(rectAni#, 20, 20, 80, 80) rectani_stopbounds#(rectAni#, 50, 50, 400, 300) rectani_duration#(rectAni#, 0.8) rectani_interpolation#(rectAni#, "Back") rectani_animationtype#(rectAni#, "Out") let btn# = button#(frm#, "Expand", 20, 320, 100, 40) button_onclick#(btn#, "togglesize") let expanded = 0 form_show(frm#) function togglesize(sender#) if expanded = 0 then rectani_inverse#(rectAni#, 0) rectani_start(rectAni#) expanded = 1 button_text#(btn#, "Collapse") else rectani_inverse#(rectAni#, 1) rectani_start(rectAni#) expanded = 0 button_text#(btn#, "Expand") end if endfunction while form_visible(frm#) = 1 processmessages() end while
Card Flip Effect
let frm# = form#("Card Flip Demo", 400, 300) form_position#(frm#, 4) let card# = rectangle#(frm#, 100, 50, 200, 200) rectangle_fill#(card#, "#e74c3c") rectangle_corners#(card#, 10, 10) ' Collapse horizontally: width → 0, X shifts to center let rectAni# = rectani#(card#) rectani_startbounds#(rectAni#, 100, 50, 200, 200) rectani_stopbounds#(rectAni#, 200, 50, 0, 200) rectani_duration#(rectAni#, 0.5) rectani_interpolation#(rectAni#, "Sinusoidal") rectani_animationtype#(rectAni#, "InOut") rectani_autoreverse#(rectAni#, 1) rectani_loop#(rectAni#, 1) rectani_start(rectAni#) form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Sliding Side Panel
let frm# = form#("Panel Slide Demo", 500, 400) form_position#(frm#, 4) ' Main content area let content# = rectangle#(frm#, 0, 0, 500, 400) rectangle_fill#(content#, "#ecf0f1") ' Side panel (starts off-screen to the left) let panel# = rectangle#(frm#, -200, 0, 200, 400) rectangle_fill#(panel#, "Navy") ' Slide from off-screen to visible let slideAni# = rectani#(panel#) rectani_startbounds#(slideAni#, -200, 0, 200, 400) rectani_stopbounds#(slideAni#, 0, 0, 200, 400) rectani_duration#(slideAni#, 0.4) rectani_interpolation#(slideAni#, "Cubic") rectani_animationtype#(slideAni#, "Out") let btn# = button#(frm#, "Toggle Panel", 250, 180, 120, 40) button_onclick#(btn#, "togglepanel") let panelOpen = 0 form_show(frm#) function togglepanel(sender#) if panelOpen = 0 then rectani_inverse#(slideAni#, 0) rectani_start(slideAni#) panelOpen = 1 else rectani_inverse#(slideAni#, 1) rectani_start(slideAni#) panelOpen = 0 end if endfunction while form_visible(frm#) = 1 processmessages() end while
Move and Resize Image
let frm# = form#("Move Resize Demo", 500, 400) form_position#(frm#, 4) let img# = image#(frm#, 20, 20, 100, 100) image_load#(img#, "https://picsum.photos/200") ' Small in top-left → large in center let rectAni# = rectani#(img#) rectani_startbounds#(rectAni#, 20, 20, 100, 100) rectani_stopbounds#(rectAni#, 100, 50, 300, 300) rectani_duration#(rectAni#, 2.0) rectani_interpolation#(rectAni#, "Cubic") rectani_animationtype#(rectAni#, "InOut") rectani_autoreverse#(rectAni#, 1) rectani_loop#(rectAni#, 1) rectani_start(rectAni#) form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Best Practices
| Practice | Why |
|---|---|
| Use RectAni when position and size change together | Keeps all 4 values perfectly synchronized in one animation |
Use inverse# for expand/collapse toggles | Reuses one animation, inverse=0 expands, inverse=1 collapses |
Use "Cubic" + "Out" for panel slides | Fast entry with gentle deceleration feels natural |
Use "Elastic" + "Out" for bouncy expands | Playful overshoot effect on UI elements |
Use "Back" + "Out" for thumbnail zoom | Slight overshoot creates a satisfying “pop” effect |
Use "Sinusoidal" + "InOut" for card flips | Smooth acceleration and deceleration for width collapse |
| Keep card flip X position = center of card | When width goes to 0, X should be at the card’s center point |
| Use short durations (0.3–0.8s) for UI transitions | Longer animations feel sluggish for interactive elements |
| Use negative X/Y for off-screen panels | Start at -width for left panels, parentWidth for right panels |
Use onfinish for chained animations | Start a second animation when the first completes |
Quick Reference
| Function | Signature | Description |
|---|---|---|
rectani_error / errormsg$ / strerror$ / clearerror | various | Error handling (4) |
rectani#(parent#[, name$]) | rectani#@# / rectani#@#$ | Create (2 overloads) |
rectani_free(ani#) | rectani_free@# | Destroy |
rectani_start / stop / stopatcurrent | various | Playback control (3) |
rectani_startbounds# / startx / starty / startwidth / startheight | various | Start bounds (5) |
rectani_stopbounds# / stopx / stopy / stopwidth / stopheight | various | Stop bounds (5) |
rectani_duration / delay | various | Timing (4) |
rectani_animationtype / interpolation | various | Easing & curves (4) |
rectani_autoreverse / inverse / loop / enabled | various | Behavior flags (8) |
rectani_running / normalizedtime / name$ | various | State queries (3) |
rectani_onfinish / onprocess / clearcallbacks# | various | Events (5) |
44 functions. Part of the Plan9Basic Animation library system.