Animation framework


#1

Hello, I have another treat to share!

[size=150]INTRODUCTION[/size]

Juce has grown to become a wonderfully elegant library, capable of (among many other things) extremely attractive user interfaces. However, there is one aspect that has been somewhat overlooked, which is now becoming increasingly apparent; in these times of iOS gadgets and UI reinvention, almost everything is animated. Juce currently provides only minimal in-built support for animation; there is the ComponentAnimator, which can fade or change the bounds of a Component, but anything else you have to do yourself. As such, it’s been something of a mission of mine to create a framework upon which more advanced animation features can be built.
And so, I am posting this, the first working stage of this framework. It’s a powerful set of classes, but this is the first public iteration, providing the foundation; there are some examples of ways it could be used, but by no means a complete picture of the system’s scope. As a result, the demo app is utter crap, but the code shows tantalising glimpse of what can be…

LINK: Animation_v1.zip
This archive contains a jucer project, consisting of the core animation framework files and an utterly lame example app.

[size=150]What there is, what it does, and how it works…[/size]

Here’s a basic overview, in roughly bottom-to-top order (i.e. Low-level core -> higher level interface), illustrating how the system’s layers are built up:

TimingNode provides the ability to create a hierarchy of temporal references, each with their own window of activity and transformation (and each conveniently shifted such that t=0 is directly meaningful to anything using it). When the time changes for one, all children are automatically updated, allowing a root node to act as a clock to drive many systems.

An Animation is a reference counted object (with its own TimingNode), defining some activity which is to be performed over a certain span of time. It has the ability to notify listeners should its activity actually change any data when it updates. This class uses a LoopTransform, which manipulates its own TimingNode’s local time to provide simply looping functionality (e.g. Duration, number of loops, ping-pong, etc). In the animation’s virtual ‘update’ function, the time provided is the transformed looping time, so any behaviour can simply refer to that.

An Animator (also with a TimingNode) can be used to play Animations. Whenever an animation has expired (its running time has passed through its window of activity), it is automatically stopped and removed. This class is abstract, with virtual start/stop functions; when the first animation is added, it will ‘start’, when the last animation is removed, it will ‘stop’. For example, the TimerBasedAnimator will start/stop a timer, ensuring that nothing happens unless animations are present.

An AnimatedObject is a special type of Animator, designed to play animations relevant to some complex structure with many animatable properties. This defines the Animator start/stop behaviour to connect to (or disconnect from) a designated source Animator. Also, it listens to any Animations it may be playing on itself; whenever time has advanced, if any of its active animations have caused changes, it provides an ‘applyChanges’ callback, allowing you to finalise them in complex situations (e.g. To reconstruct an AffineTransform from separated properties such as rotation, scale, etc.).

BasicAnimation is a simplified base for animations that only care about a normalised 0-1 progress value. This is ideal for simple animations where all you want to do is interpolate between two values.

BasicValueAnimation extends this by taking start/end values, and a target Value object to control.

ValueTreeAnimator is a type of AnimatedObject, designed to animate properties in a ValueTree. It has an interface to retrieve a Value for a property by some locator String; the default implementation simply assumes it is a root property identifier, but you can easily extend it to parse it as, for example, a path to some child node’s property. It also has a stupidly simple interface for animating values; simply call ‘animateValueTo’ using a locator string, a target value and a duration, and it will do everything for you (i.e. Locate the specified Value, create a BasicValueAnimation starting with the current value, and start it playing). Also, because of the way Animators are designed, they will automatically start/stop/connect/disconnect/etc… when needed, behind the scenes, so you don’t have to worry about it.

[size=150]Next…[/size]

That’s as far as it has come as of today, but I’m by no means finished - I still have a lot to do; for example, I’m going to add time shaping functionality to BasicAnimation (allowing you to provide a transformation to the 0-1 progress, to easily add things like ease in/out without having to change the actual interpolation). Also, I’d like to put together a ready-made interface for trivially animating all aspects of any Components; as far as I’m concerned, if you have to put any real effort into making your Components animate smoothly, there is something missing. That’s not to discredit Jules’ work though! He’s busy doing far more technically important things, and doing it all like a powerhouse! :slight_smile: All I mean is that there is a hole in the coder-side interface of the UI handling side of things, and I want to see it filled.

As usual, this is all purely for selfish reasons, because I want it to be easy for me - it’s just convenient for you lot that I’m lazy enough to feel the need to do it myself :wink:

Please feel free to mess around with it all, and let me know what you think.

Cheers!

ADDITIONAL IMPORTANT NOTE ABOUT THE DEMO APP:
Seriously, the actual demo is almost not worth running - all it does is resize a button when you click it. It’s the most basic thing I could be arsed putting together to show how these classes could be used. What is interesting (and in fact the entire purpose of this whole exercise) is the code-side interface possibilities for triggering these (or vastly more exciting) animations. Considering these animations can be easily made to control anything, there is crazy potential, and it should be quite straightforward to build upon all this to make any animations utterly trivial to implement and perform.


#2

Nice one :smiley:


#3

Yes, thanks for sharing this haydxn. I might look at using this for some eye candy in my plugins in future…


#4

Almost a year later, editing my post asking for help to get it compiling (I hadn't added the necessary juce modules in Introjucer).

My juce skills are much better now, and these classes look really good for the UI stuff I am planning to implement.

It would be great to have things like this as juce modules / on GitHub, so people can work on stuff together...


#5

Hm… The link is dead. Does anyone still have it / use it?
Thanks


#6

If it was posted in 2011 it would probably need some work to make it compatible with JUCE v5. JUCE does have a basic animation class already.


#7

Yes, but it had this class even back then in 2011. The point is that I don’t want to animate components… I want to animate a content in some off-screen target. For this, it seems that only very generic set of classes is needed with no dependency to the actual rendering engine. The above pretty much seemed to be “it”.


#8

As luck would have it, I downloaded the zip a few years ago and found it in my dev folder.

I never did get around to using it. Would be great to have it as a JUCE module :wink:
Hope it helps you in your project.


#9

Thanks, I will certainly have a look at it and yes, it would be great if JUCE had something like this. One of the reasons why JUCE is such a great library is that there are no external dependencies… You just you the features it contains and usually - it’s enough.


#10

What I meant was that, if you get it working you could publish it as a JUCE module on Github or Bitbucket. RE: external dependencies - I agree to an extent, but also think the big missing piece from the JUCE puzzle is a way to easily discover and include 3rd party modules. E.g. npm, RubyGems, CocoaPods, Rust crates etc.


#11

Yeah, I don’t know why we can’t just feed Projucer a GIT URL and have that module be downloaded to be used globally within projects.

Even if Roli had another repo on github that could host modules or module descriptors. People could submit PR requests to have theirs included. At least they would be in a single location which they could produce some kind of marketplace/repository. Again Projucer could check this to inform users of updates or new packages etc.

Just seems the module system is underused.


#12

@Anima that module library manager idea is pretty brilliant. They have started doing this in Arduino, Max, and Pure Data and it really rocks. Unity game engine has a pretty slick built in asset store (not that I would expect something like that level for JUCE, but maybe something like Max Package Manager would be sweet)