Animation¶
The Animation dataclass configures how property changes are animated. Animations control the timing curve and duration of transitions when view properties are mutated.
import nib
counter = nib.Text("0", animation=nib.Animation.spring())
def increment():
counter.content = str(int(counter.content) + 1) # Change animates automatically
import threading
import time
import nib
def main(app: nib.App):
app.title = "Animation"
app.icon = nib.SFSymbol("waveform.path")
app.width = 320
square = nib.Rectangle(
fill="#0a84ff",
corner_radius=6,
width=56,
height=56,
animation=nib.Animation.easeInOut(0.6),
)
bar = nib.ProgressView(
value=0.2,
total=1.0,
tint=nib.Color.GREEN,
width=180,
animation=nib.Animation.spring(0.6, 0.5),
)
dot = nib.Circle(
fill="#ff9f0a",
width=56,
height=56,
opacity=1.0,
animation=nib.Animation.linear(0.6),
)
def row(label, view):
return nib.HStack(
controls=[
nib.Text(
label,
font=nib.Font.CAPTION,
foreground_color=nib.Color.SECONDARY,
width=90,
),
view,
],
spacing=12,
)
def pulse():
on = False
while app.is_running:
on = not on
square.corner_radius = 28 if on else 6
bar.value = 0.9 if on else 0.2
dot.opacity = 0.15 if on else 1.0
time.sleep(1.2)
app.on_appear = lambda: threading.Thread(target=pulse, daemon=True).start()
app.build(
nib.VStack(
controls=[
row("easeInOut(0.6)", square),
row("spring(0.6, 0.5)", bar),
row("linear(0.6)", dot),
],
spacing=16,
padding=20,
alignment=nib.Alignment.LEADING,
)
)
nib.run(main)
Constructor¶
Animation(type, duration=None, delay=None, response=None, damping=None)
The Animation dataclass is not typically constructed directly. Use the factory methods below instead.
| Field | Type | Default | Description |
|---|---|---|---|
type |
str |
none | Animation type: "linear", "easeIn", "easeOut", "easeInOut", or "spring". |
duration |
float |
None |
Duration in seconds (for timing-curve animations). |
delay |
float |
None |
Delay before the animation starts, in seconds. |
response |
float |
None |
Spring response time: how quickly the spring settles (spring animations only). |
damping |
float |
None |
Spring damping fraction: how much the spring bounces (spring animations only). |
Factory Methods¶
Animation.linear(duration=0.3)¶
Create a linear animation with constant speed.
anim = nib.Animation.linear(0.5)
| Parameter | Type | Default | Description |
|---|---|---|---|
duration |
float |
0.3 |
Duration in seconds. |
Animation.easeIn(duration=0.3)¶
Create an ease-in animation that starts slow and accelerates.
anim = nib.Animation.easeIn(0.3)
| Parameter | Type | Default | Description |
|---|---|---|---|
duration |
float |
0.3 |
Duration in seconds. |
Animation.easeOut(duration=0.3)¶
Create an ease-out animation that starts fast and decelerates.
anim = nib.Animation.easeOut(0.2)
| Parameter | Type | Default | Description |
|---|---|---|---|
duration |
float |
0.3 |
Duration in seconds. |
Animation.easeInOut(duration=0.3)¶
Create an ease-in-out animation that starts and ends slowly with faster motion in the middle.
anim = nib.Animation.easeInOut(0.4)
| Parameter | Type | Default | Description |
|---|---|---|---|
duration |
float |
0.3 |
Duration in seconds. |
Animation.spring(response=0.3, damping=0.7)¶
Create a spring animation with physics-based timing. Spring animations feel more natural than timing curves.
anim = nib.Animation.spring() # Default spring
anim = nib.Animation.spring(response=0.5, damping=0.6) # Custom spring
| Parameter | Type | Default | Description |
|---|---|---|---|
response |
float |
0.3 |
How quickly the spring settles (lower values = faster). |
damping |
float |
0.7 |
How much the spring bounces. 0.0 = oscillates forever, 1.0 = no bounce (critical damping). |
Presets¶
Nib provides four built-in animation presets as class attributes:
| Preset | Equivalent | Description |
|---|---|---|
Animation.default |
Animation.easeInOut(0.3) |
Standard animation for most UI changes. |
Animation.fast |
Animation.easeOut(0.15) |
Quick animation for responsive feedback. |
Animation.slow |
Animation.easeInOut(0.5) |
Slower animation for emphasis. |
Animation.bouncy |
Animation.spring(0.3, 0.5) |
Bouncy spring animation. |
nib.Text("Quick", animation=nib.Animation.fast)
nib.Text("Bouncy", animation=nib.Animation.bouncy)
Sticky Animations¶
When an animation is set on a view, it becomes "sticky". All future property changes on that view are animated using the same configuration. This means you only need to set the animation once.
import nib
def main(app: nib.App):
# Animation is set once and applies to all future mutations
label = nib.Text("0", font=nib.Font.TITLE, animation=nib.Animation.spring())
def increment():
label.content = str(int(label.content) + 1) # Animates with spring
app.build(
nib.VStack(
controls=[
label,
nib.Button("Increment", action=increment),
],
spacing=12,
padding=16,
)
)
nib.run(main)
Examples¶
Animated counter with numeric text transition¶
import nib
def main(app: nib.App):
count = nib.Text(
"0",
font=nib.Font.system(48, nib.FontWeight.BOLD),
animation=nib.Animation.spring(response=0.4, damping=0.6),
content_transition=nib.ContentTransition.NUMERIC_TEXT,
)
def increment():
count.content = str(int(count.content) + 1)
app.build(
nib.VStack(
controls=[count, nib.Button("Add", action=increment)],
spacing=16,
padding=20,
)
)
nib.run(main)
Animated opacity toggle¶
import nib
def main(app: nib.App):
box = nib.Rectangle(
fill=nib.Color.BLUE,
width=100,
height=100,
corner_radius=12,
animation=nib.Animation.easeInOut(0.4),
)
def toggle():
box.opacity = 0.2 if (box.opacity or 1.0) > 0.5 else 1.0
app.build(
nib.VStack(
controls=[box, nib.Button("Toggle", action=toggle)],
spacing=12,
padding=16,
)
)
nib.run(main)