-
Notifications
You must be signed in to change notification settings - Fork 414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FEAT: Animation DSL - Initial commit #5062
base: master
Are you sure you want to change the base?
Conversation
FYI team uses a set of prefixes to classify commits |
I added FEAT to the description. Thanks @GalenIvanov ! |
Thanks for PR and especially the docs. I haven't gotten to the effects part yet, so preliminary thoughts... I can see there's a lot of work ahead.
Minor things:
|
I then tried to prerender it:
But that fails with
|
@hiiamboris Regarding 14 - apparently I have forgotten about lit-words in |
Why should |
It needs to know some of the Draw commands, due to the subpixel precision (automatic 10x upscale ot the lienar values and |
I see. What if it scaled all pairs and some selected numbers like line-width and circle radii, and skipped everything else? |
Yes, it's possible to look only for these special cases. But it still has to keep track of words (Draw commands) without knowing their meaning, for the tween targets. |
Isn't |
I like the idea of important options being exposed at VID level directly, e.g: I also think, that we should use grouping by using blocks, where it makes sense. In other words - how can I distinguish, how many of the following elements are affected? Is that till the next start sequence?
|
@pekr Yes, each
|
|
Text-fx.red demo, window isn't quite wide enough. anim-block: has 720, needs 750 all over. |
|
@ne1uno Yes, DPI - but I think it's a Draw issue. |
@hiiamboris 15 - the first error is a Draw error. After that the Draw block is cleared and the tween target of scale (scale x) could not be found. |
@hiiamboris Thank you once again for your constructive comments! I think fixed more of the issues:
|
Great, thanks!! Seeing that like Bolek you like the manual labor of specifying function locals, I run the global words check on simple animation:
Output is:
Obviously, |
Please also optimize |
@hiiamboris all the leaks are not function locals though, some are |
What optimization are you referring to @hiiamboris. I can't tell from finding |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I needed to click submit for comments to be visible.
modules/view/Animate.red
Outdated
tween: function [ | ||
{Interpolates a value between value1 and value2 at time t | ||
in the stretch start .. start + duration using easing function ease} | ||
target [word! any-path!] {the word or path to set} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
target
argument is excessive. tween path ...
is the same thing as path: tween ...
.
To be easy on event generation I'm using maybe word: value
setter
modules/view/Animate.red
Outdated
t [number!] {Current time} | ||
ease [function!] {Easing function} | ||
][ | ||
end-t: duration * 1.09 + start ; depends on the easing! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The moment I saw this magic number it occurred to me it's the cause of time-fx glitch when window is moved. All it took is to remove this line and t <= end-t
condition.
modules/view/Animate.red
Outdated
if 3 = length? val2 [val2: val2 + 0.0.0.0] | ||
val: val1 | ||
repeat n length? val1 [ | ||
val/:n: to integer! val1/:n + (val2/:n - val1/:n * ease t - start / duration) % 256 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usage of %
isn't correct here is it? Some tweening functions would exceed the max value and bounce around it, so we should just clip the value between 0 and 255.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OTOH the whole repeat
is not needed here, since tuple arithmetic is good enough as it is to interpolate tuples:
t-norm: ease t - start / duration
val: add val1 * (1 - t-norm) val2 * t-norm
Then you don't need to turn 3-tuples into 4-tuples, and you don't need a special case for tuples at all: it works for them and for numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hiiamboris Thanks for all the comments! I'll go through all of them.
modules/view/Animate.red
Outdated
] | ||
][ | ||
val: val1 + (val2 - val1 * ease t - start / duration) | ||
if integer? val1 [val: to integer! val] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generic to val1 val
will be faster than a conditional.
modules/view/Animate.red
Outdated
start [number!] {Start of the time period} | ||
duration [number!] {Duration of the time period} | ||
t [number!] {Current time} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all of tween
calls can be rewritten from tween .. start duration t ..
into tween .. t - start / duration ..
, to make it more general and lessen the number of arguments. Do I have to tie animation to time? What if I'm making an animation editor, and want it to simply spit out a frame based on the slider
value (0 to 1)? In this case I would have to invent time only to make it work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want tween
to be a global function, so it could be used with arbitrary GUI elements. For that it has to be general.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if I'm making an animation editor, and want it to simply spit out a frame based on the slider value (0 to 1)?
This ties directly to both Bret Victor refs and time travel. The general slider/replay concept also applies to event streaming and things like session replay. For those there may be both manual and synthetic time. e.g. playing back a session of API calls and animating against the time that was stored for them.
exit | ||
] | ||
|
||
insert-event-func :anim-on-time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to insert the same function on every animate
invocation, eventually blocking the event loop from any useful work and multiplying the amount of work animate
performs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hiiamboris very good point. I searched R2 code, knowing I had hit this same issue. Almost 800 files contained insert-event-func
, with many dupes of course. Wow. Here's what I had in one IOS support file, for a specific event func:
use [evt-func-installed?] [
evt-func-installed?: func [fn] [
found? find system/view/screen-face/feel/event-funcs :fn
]
insert-my-view-event-func: does [
if not evt-func-installed? :view-evt-func [
insert-event-func :view-evt-func
]
]
remove-my-view-event-func: does [
if evt-func-installed? :view-evt-func [
remove-event-func :view-evt-func
]
]
]
Other apps just had the core bit directly
if not find system/view/screen-face/feel/event-funcs :evt-func [
insert-event-func :evt-func
]
|
||
; global event handler | ||
anim-on-time: func [face event][ | ||
if event/type = 'time [process-timeline] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is global handler, we should take care to have minimal footprint on performance and ensure we stop when there's nothing to animate. It's unclear to me how it works here, maybe timeline
becomes empty and process-timeline
exits soon?
Possibly. Hard to tell in 2K LOC ;) |
I also thought maybe this check should be embedded into |
If it's the same func, absolutely. There is no reason to add the same func more than once. It's a mezz so is an easy change. Let's confirm with @dockimbel and @qtxie, so we're all on the same page. |
That saves @GalenIvanov from having to change it too. :^) |
@hiiamboris I optimized |
So, regarding
I would have proposed including it from the bottom of |
Animate is an experimental animation dialect. It's main goal is to provide the programmers with an easy declarartive way to describe simple animation as an extenson to Draw. It also provides mechanism for animating arbitrary word! or path! values.