Tweener, 4 years later - A post mortem
Another post that has been a long time in the making.
From the start. Until a few years ago, whenever I needed some kind of animation added to the Flash-based work I developed, I used an ActionScript tweening extension I created called MC Tween. This extension was created strictly according to my own tastes; other great tweening extensions already existed at the time, but I didn’t particularly like any of them, as I considered the API for most of them too abstract for what I needed them for. MC Tween used a prototype-based approach, adding new functionality to already existing Object types such as MovieClips. Apparently a few other people agreed with my syntactical approach to programmatic tweening, so it ended up enjoying quite a popularity for a while.
In 2005, however, I started growing increasingly irritated with MC Tween. While it managed to do its job well, ActionScript syntax and paradigm changes (specially the ones introduced with AS2), coupled with my better understanding of object-oriented programming, made me realize it didn’t quite fit my development workflow very well anymore. What’s more, MC Tween development had begun to grow increasingly stale, and due to its popularity, any sort of experimental feature change was too dangerous to even be considered. It was sort of stuck.
So in june of that year, I started an experiment, creating a new, class-based, tweening extension. Initially, it was instance-based (you created instances of tweens), but it was later changed to a static class that created all your tweenings through a single method call, addTween(), and handled additional features through a few additional methods like stopTween(), getTweens() and such.
The class went through a lot of changes, like having its own name changed (initially called Twina, then Tweener, then ZTweener, then Tweener again), its package moved around (from generic.*, to zeh.easing.*, to caurina.transitions.*) and its API changed a lot, not to mention changing from the instanced approach to a static approach, and other big internal modifications. I think the lesson here - and this is honestly the point of most of this post - is that when you create something for yourself, knowing that no one is going to look or judge the output, much less use it on their own mission-critical work, you allow yourself to be a lot more wrong simply because you’re the only one who has to accept the risk; but, in the process, you find better ways of doing something.
At the time I started this project, Fuse Kit was becoming the most popular tweening extension out there. This was something I did not want to compete with, and I specially enjoyed the freedom of creating something in an iterative fashion, for myself, and changing it to fit my needs on every new project. That’s why Tweener remained under wraps (used only by myself) for quite a while, even though I was using it on every project I had to build for Gringo (at the time).
Tweener was “made public” on January of 2007, almost two years after its first version was created. Nate Chatellier had just joined the team - and created the AS3 version of Tweener - and I thought it wasn’t fair to keep it under wraps forever. And at that point, the API wasn’t likely to change a lot, so input would be appreciated.
Tweener wasn’t something so out of this world, and its API wasn’t anything too brand new either, since the kind of loose approach it took with new tween definition could already be found on several other existing tweening extensions - even AS1-based extensions. Still, it was probably the right syntax at the right time - as it also managed to be quite popular for a while, being even ported to other languages.
That apparently was 4 years ago (judging from the logs, Tweener was started on June 15, 2005). Other tweening extensions exist today - maybe specially popular are Go, TweenLite/TweenMax, GTween, and the new BetweenAS3 - and you know what? It’s that time again. Even if it has a modern AS3 version available, many of the paradigms adopted Tweener are pretty old-fashioned now. I’ve been growing increasingly discontent with it, I’ve learned more, and it’s time to move on.
I could just move on, but I want to have a look back at what worked and what didn’t. Consider this a Tweener post-mortem - my analysis of what I’ve learned these past 4 years and how has ActionScript changed for libraries like Tweener.
So. When moving from AS2 to AS3, there’s one important thing we need to consider: errors, in AS2, are pretty silent. You can try changing properties of a null object and Flash Player will happily oblige. Sure, it won’t work since the object doesn’t even exist, but it won’t give you any sort of error message.
This creates a problem because when you expect something to work tightly, you need several levels of verification to see whether the data you’re getting is what you expect it to be, so you can warn the user otherwise. With Tweener, under AS2, I tried to play it safe for the user: more precisely, I’d check whether objects existed on every update, whether the property being tweened already had a default value.
It turns out that with AS3, this is an unneeded feature. If you try accessing objects that don’t exist, or properties that are not there, the execution of your code will break in all kinds of ways. And this is good - it helps the user understand he’s making something very, very wrong, and that he must fix it.
When ported to AS3, however, Tweener carried many of these AS2 paradigms, so it still has a lot of verifications of that kind. Try to tween the value of a property that doesn’t exist and you’ll see a custom Tweener error, not some Flash Player error.
if (rScopes[0][istr] == undefined) {
printError("The property '" + istr + "' doesn't seem to be a normal object property of " + String(rScopes[0]) + " or a registered special property.");
}
The same thing happens on every iteration of the property update loop - it checks whether the object being updated exists, whether the property exists, etc. Which is to say, Tweener tries too hard. The side effects of this approach are decreased performance and increased file size.
Other compromise that probably has ties with this AS2 way of distrusting the API user is that, internally, Tweener tries to play as safe as possible, giving the user little room to break stuff. One of the biggest examples of this resolution is that, when you create new tweens, Tweener searches for similar tweens (tweens applied to the same object and same properties with overlapping time) so they can be deleted. While this may make sense, since it’s the expected behavior of an animation afterall, this creates two problems - first, it has never been an option, as the overwriting is always enforced. And second, it introduces a huge loss of performance when creating new tweens, specially if you already have too many tweens in place, because of all the tweens and objects it has to check for overlaps first.
I’ve long been fond of this safer approach, but with increasingly complexity of ActionScript, and increasing performance you can tap into as long as you allow yourself to walk on the edge, it becomes too much of a compromise. In the end, it’s better to make things moderately safe, but giving the user the ability to circumvent issues that may arise with default use.
That is all to say, nowadays I believe tweening overwriting should have been off by default, but offered as a feature (not surprisingly, this is the approach that classes like TweenMax take).
Comparing performance of tweening engines recently made this problem more obvious. While it still holds moderately well with actual tween updating time and pretty well with memory consumption, Tweener has a much harder time the higher the number of tweens it has to create; tween creation time gets exponentially higher, since it checks each new tween against the entire list, and with tween numbers in the thousands it’s quite often that just trying to create the new tweens will take more time than the animation itself, just hanging the player for a while.
Now, Tweener uses a single array for its tween list, and this could be resolved by clever AS3-native tricks, like using a Dictionary instead (again, not surprisingly, this is the solution TweenMax uses, and Jack Doyle was actually the first to mention the technique to me). While doing this might have served as a stopgap, the problem still remains - Tweener just tries too hard to play it safe; to guide the user by the hand, giving him no room to explore if he just wants performance and knows what he’s doing.
That’s why, with today’s state of Tweener, I think this is not a question of optimization anymore. Stopgaps could be made, like the removal of a few checks, the addition of some modern AS3 features like a Dictionary for the list, and heck, maybe even Vectors, but I honestly believe that, by design, Tweener is already past its prime, so those changes would be just that, stopgaps.
So it makes no sense to update Tweener anymore. Sure, it works (specially if you don’t need thousands of concurrent tweens), and will continue to work, but in terms of advancements, it has reached a dead-end. There are now better ways to do things - Tweener is close to that, I think, but because it doesn’t have a lot of room to maneuver, it’s best to just leave the project as it is and move on to something else.
But, here’s something.
While I won’t be changing Tweener anymore unless some new, hideous bug shows up, I’ve made a small update - a new version, 1.33.74, is available both at the Google Code project page and at the subversion server. This update keeps the default tweening overwriting, but adds a new parameter, overwrite (that, when set to true, enables the old behavior) and a new static property, autoOvewrite (that changes the default overwriting behavior). Why is that a good thing? Because it’s faster.

On the above graphic, the blue bar means no tween, the orange bar represents Tweener 1.31.74, and the yellow bar means Tweener 1.33.74 with overwriting set to false.
This is not much, but consider this my thank-you for the support, suggestion, lessons, and overall awesomeness I’ve received over the years due to this project. My most grateful thanks not just to people who helped the project more prominently, but to everybody who helped the project in one way or another.
And since this is some sort of closure, even though this doesn’t have much to do with the post, here’s an interesting graphic I’ve been assembling over the years since Tweener has moved to the Google Code website. It compares the percentages of download of stable versions of Tweener based on the version (see the full download count). It’s slow, but we can see how AS3 is slowly dominating the statistics. It doesn’t include the version released today.

Here’s the same graphic, but without normalization.

As a closing note, I must add that, personally, I’m using slightly different approaches to tweening than what was introduced by Tweener. While Tweener still works and will continue to work, my own workflow has changed slightly. I never use special shortcuts for color tweening and stuff anymore, preferring instead to create separate classes and specific functionality via getter/setters, decorators and the like. Should other people be doing that too? Heck if I know, but the reason why I work in things like Tweener in the first place is because I was happy to work on something that would fit my own development flow well, and making it available to other people later if they wanted it. You can even say it’s a bit of a naive thing to do, and that’s part of the reason why it took me so long to make it public, but I prefer to use something that’s tailored to the needs of a person (as long as I agree with that person) instead of something that’s tailored to the needs of everybody. That’s not to say any of the other libraries out there do this - I wouldn’t know - but rather to explain how is my approach to that kind of library and why I prefer to move on instead of keep hammering on something I don’t think has the best approach.
Nowadays, I’m using mixed solutions for tweening: Tweener for some stuff, an experimental tweening engine I’ve built which fits my workflow very well and that I can abuse when I want top performance (because it doesn’t try anything other that I want it to) for others, and a tweening engine built by the folks from Firstborn of which I’ll be contributing to (as soon as I get to the office - from next week on probably) and that I hope I’ll be able to talk more about the future.
To be clear, there won’t be a “Tweener 2″, or anything like that.
And thanks again!
