Skip to content

Commit 9016fcf

Browse files
authored
Merge pull request #9 from pop-os/docs
Docs
2 parents a315337 + 960131f commit 9016fcf

File tree

14 files changed

+506
-78
lines changed

14 files changed

+506
-78
lines changed

README.md

Lines changed: 129 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,131 @@
1-
Very much still a WIP. API is mostly final and this can create animations. Just missing large amounts of features to make this useful in any real project.
1+
# COSMIC TIME
2+
## An animation toolkit for Iced-rs/Iced
23

3-
TODOs before release:
4+
> This Project was build for [Cosmic DE](https://github.com/pop-os/cosmic-epoch). Though this will work for any project that depends on [Iced](https://github.com/iced-rs/iced).
5+
6+
7+
The goal of this project is to provide a simple API to build and show
8+
complex animations efficiently in applications built with Iced-rs/Iced.
9+
10+
## Project Goals:
11+
* Full compatibility with Iced and The Elm Architecture.
12+
* Ease of use.
13+
* No math required for any animation.
14+
* No heap allocations in render loop.
15+
* Provide additional animatable widgets.
16+
* Custom widget support (create your own!).
17+
18+
## Overview
19+
To wire cosmic-time into Iced there are five steps to do.
20+
21+
1. Create a [`Timeline`] This is the type that controls the animations.
22+
```rust
23+
struct Counter {
24+
timeline: Timeline
25+
}
26+
27+
// ~ SNIP
28+
29+
impl Application for Counter {
30+
// ~ SNIP
31+
fn new(_flags: ()) -> (Self, Command<Message>) {
32+
(Self { timeline: Timeline::new()}, Command::none())
33+
}
34+
}
35+
```
36+
2. Add at least one animation to your timeline. This can be done in your
37+
Application's `new()` or `update()`, or both!
38+
```rust
39+
static CONTAINER: Lazy<id::Container> = Lazy::new(id::Container::unique);
40+
41+
let animation = chain![
42+
CONTAINER,
43+
container(Duration::ZERO).width(10),
44+
container(Duration::from_secs(10)).width(100)
45+
];
46+
self.timeline.set_chain(animation).start();
47+
48+
```
49+
There are some different things here!
50+
> static CONTAINER: Lazy<id::Container> = Lazy::new(id::Container::unique);
51+
52+
Cosmic Time refers to each animation with an Id. We export our own, but they are
53+
Identical to the widget Id's Iced uses for widget operations.
54+
Each animatable widget needs an Id. And each Id can only refer to one animation.
55+
56+
> let animation = chain![
57+
58+
Cosmic Time refers to animations as [`Chain`]s because of how we build then.
59+
Each [`Keyframe`] is linked together like a chain. The Cosmic Time API doesn't
60+
say "change your width from 10 to 100". We define each state we want the
61+
widget to have `.width(10)` at `Duration::ZERO` then `.width(100)` at
62+
`Duration::from_secs(10)`. Where the `Duration` is the time after the previous
63+
[`keyframe`]. This is why we call the animations chains. We cannot get to the
64+
next state without animating though all previous [`Keyframe`]s.
65+
66+
> self.timeline.set_chain(animation).start();
67+
68+
Then we need to add the animation to the [`Timeline`]. We call this `.set_chain`,
69+
because there can only be one chain per Id.
70+
If we `set_chain` with a different animation with the same Id, the first one is
71+
replaced. This a actually a feature not a bug!
72+
As well you can set multiple animations at once:
73+
`self.timeline.set_chain(animation1).set_chain(animation2).start()`
74+
75+
> .start()
76+
77+
This one function call is important enough that we should look at it specifically.
78+
Cosmic Time is atomic, given the animation state held in the [`Timeline`] at any
79+
given time the global animations will be the exact same. The value used to
80+
calculate any animation's interpolation is global. And we use `.start()` to
81+
sync them together.
82+
Say you have two 5 seconds animations running at the same time. They should end
83+
at the same time right? That all depends on when the widget thinks it's animation
84+
should start. `.start()` tells all pending animations to start at the moment that
85+
`.start()` is called. This guarantees they stay in sync.
86+
IMPORTANT! Be sure to only call `.start()` once per call to `update()`.
87+
The below is incorrect!
88+
```rust
89+
self.timeline.set_chain(animation1).start();
90+
self.timeline.set_chain(animation2).start();
91+
```
92+
That code will compile, but will result in the animations not being in sync.
93+
94+
3. Add the Cosmic time Subscription
95+
```rust
96+
fn subscription(&self) -> Subscription<Message> {
97+
self.timeline.as_subscription::<Event>().map(Message::Tick)
98+
}
99+
```
100+
101+
4. Map the subscription to update the timeline's state:
102+
```rust
103+
fn update(&mut self, message: Message) -> Command<Message> {
104+
match message {
105+
Message::Tick(now) => self.timeline.now(now),
106+
}
107+
}
108+
```
109+
If you skip this step your animations will not progress!
110+
111+
5. Show the widget in your `view()`!
112+
```rust
113+
anim!(CONTIANER, &self.timeline, contents)
114+
```
115+
116+
All done!
117+
There is a bit of wiring to get Cosmic Time working, but after that it's only
118+
a few lines to create rather complex animations!
119+
See the Pong example to see how a full game of pong can be implemented in
120+
only a few lines!
121+
122+
Done:
4123
- [x] No heap allocations in animation render loop
5-
- [x] Compile time type guarentee that animation id will match correct animation to correct widget type.
124+
- [x] Compile time type guarantee that animation id will match correct animation to correct widget type.
6125
- [x] Animatable container widget
7126
- [x] Looping animations
8127
- [x] Animation easing
128+
- [x] test for easing
9129
- [x] add space widget
10130
- [x] add button widget
11131
- [x] add row widget
@@ -14,16 +134,15 @@ TODOs before release:
14134
- [x] Use iced 0.8
15135
- [x] use iced 0.8's framerate subscription
16136
- [x] Add logic for different animation Ease values
17-
- [ ] Documentation
18-
- [ ] Add `Cosmic` cargo feature for compatibility with both iced and System76's temporary fork.
137+
- [x] Documentation
19138
- [x] optimize for `as_subscription` logic
20139
- [x] Add pause for animations
21-
- [ ] Lazy keyframes. (Keyframes that can use the position of a previous (active or not) animation to start another animation.)
140+
- [x] Lazy keyframes. (Keyframes that can use the position of a previous (active or not) animation to start another animation.)
22141

23-
Other TODOs:
24-
- [x] test for easing
142+
TODOs:
143+
- [ ] Add `Cosmic` cargo feature for compatibility with both iced and System76's temporary fork.
144+
- [ ] Low motion accesability detection to disable animations.
25145
- [ ] general animation logic tests
146+
- [ ] Work on web via wasm-unknown-unknown builds
26147
- [ ] physics based animations
27-
- [ ] Low motion accesability detection to disable animations.
28148
- [ ] Figure out what else needs to be on this list
29-
- [ ] Work on web via wasm-unknown-unknown builds

src/keyframes.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ pub use toggler::Toggler;
2525

2626
use crate::Timeline;
2727

28+
/// The macro used to cleanly and efficently build an animation chain.
29+
/// Works for ann Id's that implement `into_chain` and `into_chain_with_children`
2830
#[macro_export]
2931
macro_rules! chain{
3032
($id:expr) => {
@@ -35,6 +37,7 @@ macro_rules! chain{
3537
};
3638
}
3739

40+
/// The macro used to clean up animation's view code.
3841
#[macro_export]
3942
macro_rules! anim{
4043
($id:expr, $($x:expr),+ $(,)?) => {

src/keyframes/button.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ impl Id {
2121
Self(widget::Id::unique())
2222
}
2323

24+
/// Used by [`chain!`] macro
2425
pub fn into_chain(self) -> Chain {
2526
Chain::new(self)
2627
}
2728

29+
/// Used by [`chain!`] macro
2830
pub fn into_chain_with_children(self, children: Vec<Button>) -> Chain {
2931
Chain::with_children(self, children)
3032
}
3133

34+
/// Used by [`anim!`] macro
3235
pub fn as_widget<'a, Message, Renderer>(
3336
self,
3437
timeline: &crate::Timeline,

src/keyframes/column.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ impl Id {
2121
Self(widget::Id::unique())
2222
}
2323

24+
/// Used by [`chain!`] macro
2425
pub fn into_chain(self) -> Chain {
2526
Chain::new(self)
2627
}
2728

29+
/// Used by [`chain!`] macro
2830
pub fn into_chain_with_children(self, children: Vec<Column>) -> Chain {
2931
Chain::with_children(self, children)
3032
}
3133

34+
/// Used by [`anim!`] macro
3235
pub fn as_widget<'a, Message, Renderer>(
3336
self,
3437
timeline: &crate::Timeline,

src/keyframes/container.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ impl Id {
2121
Self(widget::Id::unique())
2222
}
2323

24+
/// Used by [`chain!`] macro
2425
pub fn into_chain(self) -> Chain {
2526
Chain::new(self)
2627
}
2728

29+
/// Used by [`chain!`] macro
2830
pub fn into_chain_with_children(self, children: Vec<Container>) -> Chain {
2931
Chain::with_children(self, children)
3032
}
3133

34+
/// Used by [`anim!`] macro
3235
pub fn as_widget<'a, Message, Renderer>(
3336
self,
3437
timeline: &crate::Timeline,

src/keyframes/helpers.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,97 @@
11
use crate::keyframes::{Button, Column, Container, Row, Space, StyleButton, StyleContainer};
22
use crate::MovementType;
33

4+
/// Create a button keyframe.
5+
/// Needs to be added into a chain. See [`chain!`] macro.
46
pub fn button(at: impl Into<MovementType>) -> Button {
57
Button::new(at)
68
}
79

10+
/// Create a column keyframe.
11+
/// Needs to be added into a chain. See [`chain!`] macro.
812
pub fn column(at: impl Into<MovementType>) -> Column {
913
Column::new(at)
1014
}
1115

16+
/// Create a container keyframe.
17+
/// Needs to be added into a chain. See [`chain!`] macro.
1218
pub fn container(at: impl Into<MovementType>) -> Container {
1319
Container::new(at)
1420
}
1521

22+
/// Create a row keyframe.
23+
/// Needs to be added into a chain. See [`chain!`] macro.
1624
pub fn row(at: impl Into<MovementType>) -> Row {
1725
Row::new(at)
1826
}
1927

28+
/// Create a space keyframe.
29+
/// Needs to be added into a chain. See [`chain!`] macro.
2030
pub fn space(at: impl Into<MovementType>) -> Space {
2131
Space::new(at)
2232
}
2333

34+
/// Create a style_button keyframe.
35+
/// Needs to be added into a chain. See [`chain!`] macro.
2436
pub fn style_button(at: impl Into<MovementType>) -> StyleButton {
2537
StyleButton::new(at)
2638
}
2739

40+
/// Create a style_container keyframe.
41+
/// Needs to be added into a chain. See [`chain!`] macro.
2842
pub fn style_container(at: impl Into<MovementType>) -> StyleContainer {
2943
StyleContainer::new(at)
3044
}
3145

46+
/// A slightly different import to clean up makeing lazy keyframes.
3247
pub mod lazy {
3348
use crate::keyframes::{Button, Column, Container, Row, Space, StyleButton, StyleContainer};
3449
use crate::MovementType;
3550

51+
/// Create a lazy button keyframe.
52+
/// Needs to be added into a chain. See [`chain!`] macro.
3653
pub fn button(at: impl Into<MovementType>) -> Button {
3754
Button::lazy(at)
3855
}
3956

57+
/// Create a lazy column keyframe.
58+
/// Needs to be added into a chain. See [`chain!`] macro.
4059
pub fn column(at: impl Into<MovementType>) -> Column {
4160
Column::lazy(at)
4261
}
4362

63+
/// Create a lazy container keyframe.
64+
/// Needs to be added into a chain. See [`chain!`] macro.
4465
pub fn container(at: impl Into<MovementType>) -> Container {
4566
Container::lazy(at)
4667
}
4768

69+
/// Create a lazy row keyframe.
70+
/// Needs to be added into a chain. See [`chain!`] macro.
4871
pub fn row(at: impl Into<MovementType>) -> Row {
4972
Row::lazy(at)
5073
}
5174

75+
/// Create a lazy space keyframe.
76+
/// Needs to be added into a chain. See [`chain!`] macro.
5277
pub fn space(at: impl Into<MovementType>) -> Space {
5378
Space::lazy(at)
5479
}
5580

81+
/// Create a lazy style_button keyframe.
82+
/// Needs to be added into a chain. See [`chain!`] macro.
5683
pub fn style_button(at: impl Into<MovementType>) -> StyleButton {
5784
StyleButton::lazy(at)
5885
}
5986

87+
/// Create a lazy style_container keyframe.
88+
/// Needs to be added into a chain. See [`chain!`] macro.
6089
pub fn style_container(at: impl Into<MovementType>) -> StyleContainer {
6190
StyleContainer::lazy(at)
6291
}
6392
}
6493

94+
/// A slightly different import to clean up makeing animation Ids.
6595
pub mod id {
6696
pub use crate::keyframes::{
6797
button::Id as Button, column::Id as Column, container::Id as Container, row::Id as Row,

src/keyframes/row.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ impl Id {
2121
Self(widget::Id::unique())
2222
}
2323

24+
/// Used by [`chain!`] macro
2425
pub fn into_chain(self) -> Chain {
2526
Chain::new(self)
2627
}
2728

29+
/// Used by [`chain!`] macro
2830
pub fn into_chain_with_children(self, children: Vec<Row>) -> Chain {
2931
Chain::with_children(self, children)
3032
}
3133

34+
/// Used by [`anim!`] macro
3235
pub fn as_widget<'a, Message, Renderer>(
3336
self,
3437
timeline: &crate::Timeline,

src/keyframes/space.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ impl Id {
2121
Self(widget::Id::unique())
2222
}
2323

24+
/// Used by [`chain!`] macro
2425
pub fn into_chain(self) -> Chain {
2526
Chain::new(self)
2627
}
2728

29+
/// Used by [`chain!`] macro
2830
pub fn into_chain_with_children(self, children: Vec<Space>) -> Chain {
2931
Chain::with_children(self, children)
3032
}
3133

34+
/// Used by [`anim!`] macro
3235
pub fn as_widget(self, timeline: &crate::Timeline) -> widget::Space {
3336
Space::as_widget(self, timeline)
3437
}

src/keyframes/style_button.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,17 @@ impl Id {
2222
Self(widget::Id::unique())
2323
}
2424

25+
/// Used by [`chain!`] macro
2526
pub fn into_chain(self) -> Chain {
2627
Chain::new(self)
2728
}
2829

30+
/// Used by [`chain!`] macro
2931
pub fn into_chain_with_children(self, children: Vec<StyleButton>) -> Chain {
3032
Chain::with_children(self, children)
3133
}
3234

35+
/// Used by [`anim!`] macro
3336
pub fn as_widget<'a, Message, Renderer>(
3437
self,
3538
style: fn(u8) -> <Renderer::Theme as StyleSheet>::Style,

src/keyframes/style_container.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,17 @@ impl Id {
2222
Self(widget::Id::unique())
2323
}
2424

25+
/// Used by [`chain!`] macro
2526
pub fn into_chain(self) -> Chain {
2627
Chain::new(self)
2728
}
2829

30+
/// Used by [`chain!`] macro
2931
pub fn into_chain_with_children(self, children: Vec<StyleContainer>) -> Chain {
3032
Chain::with_children(self, children)
3133
}
3234

35+
/// Used by [`anim!`] macro
3336
pub fn as_widget<'a, Message, Renderer>(
3437
self,
3538
style: fn(u8) -> <Renderer::Theme as StyleSheet>::Style,

0 commit comments

Comments
 (0)