6 releases
new 0.2.0 | Jan 5, 2025 |
---|---|
0.1.4 | Dec 29, 2024 |
#125 in GUI
549 downloads per month
1MB
714 lines
Dioxus Motion 🚀
A lightweight, cross-platform animation library for Dioxus, designed to bring smooth, flexible animations to your Rust web, desktop, and mobile applications.
🎯 Live Examples
Visit our Example Website to see these animations in action:
- 🌸 Flower Animation
- 📝 Cube Floating Animation
- 🔄 Morphing Shapes
- 📝 Typewriter Effect
- ⚡ Path Animations
Quick Example
use dioxus_motion::prelude::*;
#[component]
fn PulseEffect() -> Element {
let scale = use_motion(1.0f32);
use_effect(move || {
scale.animate_to(
1.2,
AnimationConfig::new(AnimationMode::Spring(Spring {
stiffness: 100.0,
damping: 5.0,
mass: 0.5,
velocity: 1.0
}))
.with_loop(LoopMode::Infinite)
);
});
rsx! {
div {
class: "w-20 h-20 bg-blue-500 rounded-full",
style: "transform: scale({scale.get_value()})"
}
}
}
✨ Features
- Cross-Platform Support: Works on web, desktop, and mobile
- Flexible Animation Configuration
- Custom Easing Functions
- Modular Feature Setup
- Simple, Intuitive API
🛠 Installation
Add to your Cargo.toml
:
[dependencies]
dioxus-motion = { version = "0.2.0", optional = true, default-features = false }
[features]
default = ["web"]
web = ["dioxus/web", "dioxus-motion/web"]
desktop = ["dioxus/desktop", "dioxus-motion/desktop"]
mobile = ["dioxus/mobile", "dioxus-motion/desktop"]
🌐 Platform Support
Choose the right feature for your platform:
web
: For web applications using WASMdesktop
: For desktop and mobile applicationsdefault
: Web support (if no feature specified)
🚀 Quick Start
🔄 Migration Guide (v0.2.0)
Breaking Changes
- Combined
use_value_animation
anduse_transform_animation
intouse_motion
- New animation configuration API
- Updated spring physics parameters
- Changed transform property names
New Animation API
use dioxus_motion::prelude::*;
// Before (v0.1.x)
let mut motion = use_value_animation(Motion::new(0.0).to(100.0));
// After (v0.2.x)
let mut value = use_motion(0.0f32);
value.animate_to(
100.0,
AnimationConfig::new(AnimationMode::Tween(Tween {
duration: Duration::from_secs(2),
easing: easer::functions::Linear::ease_in_out,
}))
);
// Before (v0.1.x)
let mut transform = use_transform_animation(Transform::default());
// After (v0.2.x)
let mut transform = use_motion(Transform::default());
transform.animate_to(
Transform::new(100.0, 0.0, 1.2, 45.0),
AnimationConfig::new(AnimationMode::Spring(Spring {
stiffness: 100.0,
damping: 10.0,
mass: 1.0,
..Default::default()
}))
);
If you were using transform.get_style(), that function is removed to make the library more generic so i recommend building something like
let transform = use_motion(Transform::default());
let transform_style = use_memo(move || {
format!(
"transform: translate({}px, {}px) scale({}) rotate({}deg);",
transform.get_value().x,
transform.get_value().y,
transform.get_value().scale,
transform.get_value().rotation * 180.0 / std::f32::consts::PI
)
});
// and using the memo in the component
rsx! {
div {
class: "...",
style: "{transform_style.read()}",
// ...rest of component...
}
}
🆕 New Features
Loop Modes
.with_loop(LoopMode::Infinite)
.with_loop(LoopMode::Times(3))
Animation Delays
.with_delay(Duration::from_secs(1))
On Complete
.with_on_complete(|| println!("Animation complete!"))
🎓 Advanced Guide: Extending Animations
Implementing the Animatable Trait
The Animatable
trait allows you to animate any custom type.
Defination of Animatable Trait
pub trait Animatable: Copy + 'static {
fn zero() -> Self;
fn epsilon() -> f32;
fn magnitude(&self) -> f32;
fn scale(&self, factor: f32) -> Self;
fn add(&self, other: &Self) -> Self;
fn sub(&self, other: &Self) -> Self;
fn interpolate(&self, target: &Self, t: f32) -> Self;
}
Here's how to implement it:
Custom Position Type
#[derive(Debug, Copy, Clone)]
struct Position {
x: f32,
y: f32,
}
impl Animatable for Position {
fn zero() -> Self {
Position { x: 0.0, y: 0.0 }
}
fn epsilon() -> f32 {
0.001
}
fn magnitude(&self) -> f32 {
(self.x * self.x + self.y * self.y).sqrt()
}
fn scale(&self, factor: f32) -> Self {
Position {
x: self.x * factor,
y: self.y * factor,
}
}
fn add(&self, other: &Self) -> Self {
Position {
x: self.x + other.x,
y: self.y + other.y,
}
}
fn sub(&self, other: &Self) -> Self {
Position {
x: self.x - other.x,
y: self.y - other.y,
}
}
fn interpolate(&self, target: &Self, t: f32) -> Self {
Position {
x: self.x + (target.x - self.x) * t,
y: self.y + (target.y - self.y) * t,
}
}
}
Best Practices
- Zero State: Implement zero() as your type's neutral state
- Epsilon: Choose a small value (~0.001) for animation completion checks
- Magnitude: Return the square root of sum of squares for vector types
- Scale: Multiply all components by the factor
- Add/Sub: Implement component-wise addition/subtraction
- Interpolate: Use linear interpolation for smooth transitions
Common Patterns
Circular Values (e.g., angles)
fn interpolate(&self, target: &Self, t: f32) -> Self {
let mut diff = target.angle - self.angle;
// Ensure shortest path
if diff > PI { diff -= 2.0 * PI; }
if diff < -PI { diff += 2.0 * PI; }
Self { angle: self.angle + diff * t }
}
Normalized Values (e.g., colors)
fn scale(&self, factor: f32) -> Self {
Self {
value: (self.value * factor).clamp(0.0, 1.0)
}
}
🌈 Supported Easing Functions
Leverages the easer
crate, supporting:
- Linear
- Quadratic
- Cubic
- Quartic
- And more!
🤝 Contributing
- Fork the repository
- Create your feature branch
- Commit changes
- Push to the branch
- Create a Pull Request
📄 License
MIT License
🐞 Reporting Issues
Please report issues on the GitHub repository with:
- Detailed description
- Minimal reproducible example
- Platform and feature configuration used
🌟 Motivation
Bringing elegant, performant motion animations to Rust's web and desktop ecosystems with minimal complexity.
Dependencies
~3–12MB
~139K SLoC