Crazy to me that animations would have been done on the main thread but that showed how far you can get with kiss. The performance improvement they’re showing is great -17% CPU to display a loading animation down to 0. Before the animation could be interfering with the loading!
> The performance improvement they’re showing is great -17% CPU to display a loading animation down to 0.
It’s not reducing the device CPU cost to zero. It’s moving it to a different process that isn’t captured in the profile. Big difference.
Not blocking the main thread is a clear win though. I’m mildly surprised the work isn’t done in an in-process background thread. But I don’t know that type of detail for iOS.
No. Animations are usually performed by the GPU under the control of a separate process.
"This system framework renders animations out-of-process with GPU hardware acceleration. Animation playback is managed by a separate system process called the “render server”. "
This was actually a really cool trick that was in-place from day 1 and the main reason iOS animations were smooth on fairly anaemic hardware. And smoother than Android, even when the Android system had beefier hardware and a faster graphics stack.
It was also available since at least 2014 when animating with AIR (yes, Flash AS3), along w/ fine-grained control over what was uploaded to the GPU and when, through an API that deployed seamlessly to iOS and Android. There's no reason the nascent Flash mobile plugin wouldn't have supported this too, if it had gotten much past beta, since GPU leveraging was available from Flash in desktop browsers earlier than that.
Keeping the GPU context when switching mobile apps was always a challenge, though, and often the animation state would need to be rebuilt if the context was dropped. I'd assume that's still an issue something like Lottie needs to handle, whether it does so under the hood or not...
On iOS, you schedule animations (and all UI updates, period) on the main thread. iOS is then free to make those happen in a non blocking way. iOS dev 101 is “don't do long synchronous work on the main thread because your app will lose the ability to update its UI for the duration”
Lottie was running the animations on the main thread, via CADisplayLink.
By the way, you can “schedule” animations from any thread if you use CoreAnimation directly. CALayers are thread-safe. You just need to manage the CATransaction yourself.
Also, trying to explain “iOS 101” to Marcel Weiher is a bit rich…
GPUs have no concept of animation. A frame rendered by a GPU has a fixed state, usually computed on the CPU. Until recently, this was usually done on the main thread, because graphics APIs had poor support for being used from multiple threads. I have no idea what AirBNB was doing to fail 60Hz on rather simple scenes with a single thread, but you can rest assured that it is possible without multiple threads or even processes.
The point is that iOS has always used a separate process for computing the GPU state. Android does this on the main thread, which is why Android feels like garbage. And I say this as a former Android developer. Animations on Android feel like peanut butter. They always will until they are moved off the main thread.
No, it has not. If you talked to the GPU through OpenGL, you did it on the main thread. You pass all the state that you computed in that thread. Chances are you computed that state in that thread too.
There are some optimizations regarding e.g. scrolling being computed in a different thread/process (still on the CPU) before compositing (on the GPU) but that is not a requirement for smooth animation.
That's not technically correct(which is always the best kind of correct :) ), HWUI has been multithreaded for quite a long while now. That doesn't prevent apps from doing bad things but it's been possible to do smooth animation on Android since the days of project butter.
Android is the opposite of barebones. It comes loaded with crap, much of it is using "stop the world" garbage collection while also producing lots of garbage. Building on Java is Android's original sin. You could still build an NDK app, talk to OpenGL, and hit 60Hz on low-end devices, years ago, but that's not how most stuff is developed. There are layers upon layers of crap between applications and the hardware, to the point where apparently people have come to believe that you need special OS interfaces to do smooth animation.
The standard path for animation on iOS is that the developer provides new target values (ie the location of something) on the main thread, but the animation and rendering does not block the main thread.
This blog post is about enabling Lottie to use that path.
Core Animation is designed to move work related to playing animations off of the app's main thread. Animations are instead performed by a different process, the OS render server. The UIViews / CALayers / CAAnimations themselves have to be configured on the main thread, but the work to actually play the animation and render each individual frame doesn't happen on the main thread.
It's not isolated to iOS in particular — it's the case in every single GUI framework I've ever dealt with. Android for example would throw an exception if you try touching the views from another thread.
It's a common pattern whenever you don't want the overhead of locks on every single function call. If you're doing anything CPU-intensive, you do it in another thread, synchronize and make API calls in the main thread.
I don't know how deeply animations are tied to the OS API, though.
I’m not, I guess the difference is animation vs UI? From the article, the ios library is set up to run animations off thread on a render server.
>On iOS, the most performant and power-efficient way to play animations is by using Core Animation. *This system framework renders animations out-of-process with GPU hardware acceleration.* Animation playback is managed by a separate system process called the “render server”. This means Core Animation-powered animations don’t contribute to the CPU utilization of the app process itself, and can continue even when its main thread is blocked or busy.
In fact, it's everything else they encourage you to do off the main thread.
Though I expect things like complex animations are exactly sort of thing that ought to be considered an exception to that guideline. Especially ones that have limited or no interactivity, as in these examples.
Suggested? It's required, otherwise behavior is undefined for many APIs. And with the main thread checker you now also get runtime issues when you access such APIs.
It's more shocking to me that Apple hasn't explicitly shifted at least some of its UI frameworks off the main queue in the last 15 years, especially as they've added tools to make it easier. Of course, given the bugs with the parts that are off the main queue, especially in SwiftUI, perhaps that's a good thing.
ComponentKit for Facebook was explicitly built to offload as much ui work as possible to other threads (text sizing being super expensive) and only go back to main to say “here is your new react style model”.
I was very surprised that SwiftUI didn’t do this too.
Right, and only recently did they start providing things like "background-thread image decoding" out of the box. In general you really have to take care that you are marshaling correctly if you bounce between main/background.
macOS not only requires window management on a single thread (common), it requires window management on the actual main thread, i.e., the thread that your program started on. Windows and Linux do not have this limitation. On Windows, you can do window management on any single thread.
There's a screenshot in the blog post that shows "0%" CPU usage. I doubt that Cal wanted to make it seem like animations were "free" but I do want to caution people that just because the GPU is now handling drawing doesn't mean the usual concerns with animations with regards to performance don't apply (I am not going to wade into the UI aspects of when to use animations). Animations are best used in moderation, for short interactions rather than running continuously all the time, even when drawn with graphics hardware. It's nice to push 60 (or 120) fps every once in a while but your app should really not be drawing at all most of the time. That's fewer frames to display in software, and on newer iPhones with ProMotion that's also going to mean fewer display refreshes. Your users, and their batteries, will thank you.
(But really, moving all these things to CoreAnimation is really nice, kudos to all involved!)
Can anyone recommend a course or tutorial series on creating simple 2d bodymovin animations in after effects? I always wanted to use lottie, but never really dived into 2d animations.
Edit: To make it clear: I'm a complete afterfx noob.
If you want a course and are willing to pay for it I can recommend School of Motion — https://www.schoolofmotion.com/courses/after-effects-kicksta... (did not take this one, I took more advanced stuff and it was good). Or just like in SE a good way to learn is to choose what you want to make and then watch tutorials on youtube about that specific topic.
> I always wanted to use lottie, but never really dived into 2d animations.
However, as a person who worked as a motion designer for several years, I must say that creating good animations, especially for lotties limited toolset is not a technical problem, but an artistic one. Making animation feel good is hard and takes a lot of practice. Even more for character animation.
Hijacking thread. Are there any alternatives to AE for those of us that want to animate and export to Lottie but also suffer physical repulsion to Adobe? Is there any serious competition? Lightweight and FOSS are on the wishlist..
It's been a while since I've played with it, but there's also Expressive Animator. I think it used to be FOSS, but isn't anymore. It looks like it has a monthly subscription for Pro now (Lottie exports). About the same price as Adobe, which is a shame.
https://www.expressivesuite.com/expressive-animator/
Hah I have the same question! I've been working on Lottie for over a year, but I've never used After Effects before and don't have it installed. My life would sure be a bit easier if there was a nice lightweight tool for creating and modifying Lottie animations. One useful tool is the lottiefiles.com editor, but its really barebones and only lets you modify colors of layers in existing animations.
Serious competition is the opposite of lightweight and FOSS to be fair.
The most powerful AE competitor(in 2d animation) I've seen is Cavalry. It targets professional motion designers, has neat procedural animation toolset and can export to lottie.
Great work on the new release! I've been using Lottie for a while now and have definitely noticed the performance improvements with the new rendering engine. It's really exciting to see Lottie continue to evolve and improve. Keep up the good work!
That's there to ensure you know how cool and hip they are.
Not only did they just release a thing, that does stuff, and is progress. But they did it over the weekend between surf without breaking a sweat because they are pro. /s
I've only heard of lottie but never really used it so I'm slightly confused with this.
Were these issues present only in the iOS version of the library? or are these issues present across android, web, and RN as well? and will these platforms also get the upgrade?
Amazing that AirBnb's dev team can release something this smooth and advanced but its messaging system is simply unbearable to use. What's up with that?
Maintainer of Lottie for Android here. Because it’s maintained as a passion project on nights and weekends by a few people. This contribution a rare exception in that it was actually funded and built during work hours at Airbnb. I left Airbnb in 2018 but am still the sole maintainer of the Android library, for example.
Animate property of a svg node manually is definitely not a good idea. The overhead is really huge. The browser literally need to redo almost anything from start to render the path and hence the image. And even worse, it also need to synchronize DOM values...etc. Anything you don't care in this use case properly. Let alone the removed node need to be garbage collected, which is also a expensive operation if you even want to do it at 60fps. That is just multi horror movie combined.
Fascinating! I touched AppKit and Core Animation a long time ago and I had no idea this existed. Does this mean the gesture animations in iOS system (such as opening an app on springboard) are drawn by this?
I’m fascinated by AirBnB. So much modern tech business orthodoxy is around leveraging your core value proposition and outsourcing everything else. Yet here is AirBnB with their own iOS rendering framework.
Is it part of their core value prop? Or do they ignore the advice? Or is their success causing them to waste cash on boondoggles like this? Or do these boondoggles help them attract engineering talent for less than they’d otherwise need to pay?
Maintainer of Lottie for Android here. The vast majority of work on Lottie has been a passion project on nights and weekends. This particular contribution is actually the rare exception.
> The vast majority of work on Lottie has been a passion project on nights and weekends.
That's sad. That's really, really sad. I get why you would like to work on such a project, but it's got considerable value for AirBnB. Your work doesn't go to the "community", it goes to a large, unscrupulous, unethical money factory.
1. It’s open sourced, so it goes to both. Either AirBnB sponsor the build and promote it, or the community builds it and AirBnB uses it. I’m not sure why the latter would be better than the former. It’s better for the world than companies keeping all their libraries closed source.
2. AirBnB’s backing probably gives it more reach because it’s more likely to be maintained.
3. It’s up to the OP where they spend their time. I’m guessing they’re compensated in multiple ways for their efforts.
I’m all for calling out negative behaviour by big tech when I see it, but kneejerk “big company bad” type reactions are counter-productive.
1. This is not a common library that fits everywhere. It's pretty specialized. Using its full potential almost requires a commercial environment, because of the design and graphics needed. For everyone else, normal animations are annoying enough.
3. The parent post said: passion project/nights+weekends. That doesn't sound like multiple way compensation.
It's not about negative behavior of big tech, but more of a "grind" mentality gone astray. I can totally understand being (somewhat) proud of a project like this: it looks friggin' good. I also expect a company to grab whatever it can; it's the way of the world, and some companies are quite immoral. But we should not be working on something of considerable value to entities with deep pockets for free, just because it hits those 2010s linked-in bingo words. That's not where your self-worth as engineers should come from.
I used to work for Airbnb. When I left, I lost a few things like admin settings on the repo but they let me maintain it. Not sure what would happen if they didn’t… Nobody there has the time or context to do anything more than a rubber stamp.
The app is their business, erm, core value proposition. They earn their money by claiming to be better at getting a property owner money than anybody else, and getting a tourist a better accommodation. To avoid the latter choosing a hotel (God forbid!), they need all the flashy, infinite-scrolling goodness a native app can offer to get the buyer to stay on their app as long as possible. That app is their life line.
I like it. Obviously don't use it for everything but small UX touches here and there make a brand more likeable to users, in my experience doing frontend and design interviews.
I also think it's over the top and I'm a year or two shy of being a zoomer. Although, I guess being a millennial is considered old by many now.
I just wish developers would make mobile UIs consistent with the OS. The Apollo Reddit client and, surprisingly, the official GitHub app are the only third-party apps that I have that feel/look like "native" iOS apps.
When it's not over-the-top animations, giant UI elements, tutorial modals, or fullscreen pop-ups, it's small details like the (IMO ugly) custom font and the sharp-cornered buttons in the Dropbox app. At least for that particular app, I can just use the built-in Files app, but no such luck for other apps.
UI is more than how things look, it’s also about how they work. Both of those apps do bad things in the pursuit of trying to be consistent with OS UI they don’t understand.
Tasteful uses of libraries like this can add a fair bit of “fun” and friendliness to an app, and younger generations do dig them from my user testing at least. Depends on the app and use case I think.
things like this violate the design principles values by novice and power users. novice users that use something once a week or month may enjoy additional visual cues and animations to be friendly and welcoming. low information density to not overwhelm.
power users that use something every day or many times a day prefer things that are static, fast, and higher information density.
I don’t like the suggestions in the use cases. Like if you didn’t know about cameras and asked, why? And someone showed you all the grotesque images they can capture, as what they think is a beautiful demo. As a bonus, their camera makes them more grotesque with less effort.
> These issues are inherent limitations of using a main-thread-bound rendering architecture.
sorry but bullshit! Sure, multi-threaded rendering can give faster results but the apps AirBnB is making could have easily rendered at 60hz with single threaded software rendering in flash in 1998!
I can only guess that too much abstraction throughout the systems has turned into death by 1000 cuts and their solution, instead of getting rid of the 1000 cuts is to apply more band-aids
You’re ignoring the OS doing other things as well before letting you draw to the screen.
This isn’t a video game where they’re direct drawing to a graphics context with exclusive use of the resources. They’re also setting up native widgets in the background, coordinating data downloads etc..
Unlike a video game where you control the rendering and scheduling to a greater degree, here they’re beholden to when the OS deems it ready to redraw or scheduling of background processes that may move their task to a lower priority.
Yes you can go fast if you don’t factor in the rest of the system, but they designed Lottie to play well within a retained mode UI setup, which has inherent overhead.
I do feel like video games definitely have it harder on this front in general, but tend to have loads of people focused on performance "at all costs", including generating a bunch of messy code to get something shippable.
I also think saying that a retained mode UI has inherent overhead is a bit odd. immediate mode UIs have to rebuild their entire draw graph on each frame! meanwhile retained mode UIs have a bunch of metadata letting them get nice optimization improvements. Translating an object means you might not even need to redraw it!
There is definitely a certain truth to the OS being able to just force you down to a lower priority, but I think we all know that iOS is pushing the top app to as high a priority as possible. Meanwhile the "inherent difficulties" with something like AirBnB (getting data over the wire) are definitely inherent but this is why we talk about placeholders and stuff like that yeah?
But if you're in the business of selling rentals it's hard to have so many engineers focused on the performance of the app (especially when you are in the act of being successful already)
With regards to retained mode overhead, I mean it across multiple forms not just the cost to redraw.
There’s the overhead of pushing updates to the UI layer from your app code, having it trigger an update, which in turn makes it check what other things have updated and what needs to redraw. UIKit is handling all that for you, but as a result you’re not getting full control of when you’re updating. You get pacing issues, where you can’t really guarantee you’re drawing at set intervals either which can lead to pacing stutters since you’re beholden to the apps event loop.
With an immediate mode UI in a game, yes there’s more cost to set up your draws, but you have more direct control of when everything will update because you’re handling the event loop more directly.
As for other priorities, I don’t mean just app priority. I mean intra-app priority. Lottie has to mix in with user code, the app it’s within might schedule a task with a higher QoS priority. It’s not just showing a fixed animation, it’s part of the app interaction model. So it’s easy to get into a situation where the rest of the app introduces stutters inadvertently.
Using CoreAnimation lets you sort of side step that discussion.
And yes I agree games have it harder over all because they have to handle everything. That wasn’t my point really. I think though that games have it easier when it comes to frame timing as a result of being able to control the entire event loop. So it’s easier for a game to reason about and guarantee smoothness of motion than it is for a framework that has to fit into arbitrary applications.
Interesting. Are videogames not beholden to the OS? Are all background processes suspended when SDL is running? Clearly videogames don't have native widgets in the background, nor do they ever "coordinate data downloads" (????)
What an absolutely braindead reply. A telltale sign a comment has almost no thought put into it: when you go into the user's post history and see the first page filled with comments written that very same day. Scatterbrained to the max.
Hey dude I'm gonna give you some unsolicited advice. Lay off the keyboard for a bit, would ya? Maybe go outside for a walk. You are spending way too much time writing comments on the internet. https://youtu.be/FmDFCKVnaRY?t=341
The irony that you’re the one who’s getting worked up about someone else’s internet activity while acting like I’m the one that needs more reality. You’re right your advice is unsolicited, so please kindly keep your issues to yourself.
I’d have been happy to discuss the nature of a UIKit and iOS based app cycle that affects these things, but I won’t with such an insufferable person who has nothing better to do than to contribute nothing other than their own anger out to the world.
I find topics interesting. I comment on said topics. That’s all that matters. Not your opinions. Not your weird hang ups.
It’s the holiday season. Go find someone to love you or share joy with instead of finding people to hate on on the internet. You clearly need it if this is the kind of stuff that gets you raging.
Irrelevant, the apps it's being used for would run fine on a 25yr old machine at 60fps.
You shouldn't need multi-threading to render a few thousand objects and most UI apps of the type Lottie is being used for animate 100 or less at a time.
Note: It's good that Lottie runs faster for its users. My point is only that the entire stack is over engineered and the solutions being used are because the stack is bloated and inefficient
I agree with the general point you're making, but a 1997 computer would not be able to render even just a basic loading spinner at 1170x2532 at 60 FPS. Software rendering would be impossible even with an infinitely fast CPU as it would exceed the bandwidth limit of AGP 1.0, which itself only came out that year. The graphics hardware at the time simply did not support that resolution at any speed.
This is a common problem when people complain about graphics performance and compare to older hardware - we forget how much higher modern screen resolutions are. It's not a smoothly scaling problem either. As often with scaling, you hit problems at particular levels that require a totally new solution to the problem. CPU speeds stagnated whilst screen technologies didn't, hence, complexity.
Yep, same deal with AsyncDisplayKit and the classic "iOS can't handle our scale". Too many cooks. Move along, this isn't the library you're looking for
Yes they are. They’re beholden to whatever your event loop is.
they’re being told when to draw (hence the immediate), so if you suddenly have computation on the same thread that’s blocking OR your thread gets deprioritized , you’ll get stutters.
Immediate mode UIs aren’t very suitable for mobile use though. They don’t have great consideration for battery efficiency, unless you introduce a retained backing of some kind. They’re also not great for accessibility, though that’s mostly just because they’re not native.
Do you have any proof of this or just a gut feeling?
Immediate mode guis do cache stuff, at least Dear ImGUI, one of the most popular Immediate mode guis caches. Further, at least in my mobile usage almost everything I do with my phone re-draws the entire screen. The #1 thing to do is scroll through content. There's very few apps I run where only some tiny thing is getting updated. Maybe my music player.
I don't think it's settled that retained more GUIs are a battery win.
Once you’ve introduced a state based caching and differentiation layer, you’re introducing retention and are entering into hybrid UI. If you don’t have sufficient caching layers to figure out when something has to update, you’re drawing too often killing battery.
Maybe there are fewer purely immediate mode UI libraries today, which muddies the discussion though.
On the note of the apps used, I would say the vast majority of apps I run only have a few elements updating at any given time. Most of them are based on scrolling for navigation but that’s a small part of what I do. Photo viewing and editing, viewing sites, replying to messages or mail, listening to music. Very little is a full screen update, and if it is, UIKit and SwiftUI are caching large amounts of the view objects to keep things snappy and only doing it when they receive input that requires it. Can immediate GUIs do that too? Of course, but again you enter the domain of retention.
You say this with zero proof. Checking 100s of widgets to see if they overlap, updating their damage boxes, drawing the parts of the ones that got overlapped, computing clip bounds for each one, switching graphics contexts, to do all that adds up to "killing the battery"
Retained APIs are like using a binary tree where an Immediate mode GUI is like using a vector. CS principles say the tree should be faster as insert and delete are in O(1) but in reality, cache misses and similar things kill all the perf you supposedly gained by over engineering the solution.
The same is often true of retained mode GUIs vs immediate, especially with all the transparency effects in modern UIs. Computing the minimal amount of parts can requires a ton more CPU than just drawing.
As far as caching = retained, no. The difference between an Immediate Mode and a retained mode API is if you, the user, have to create and maintain a tree of retained API widgets. No one is going to implement an immediate mode API and try to have a text widget that word wraps and expect it to have to compute all the word wrapping every frame.
Except you’d not be doing all those things that you mentioned. Much like you wouldn’t in a game, you’d be constructing some kind of acceleration structure to only update what’s needed.
With an immediate mode GUI, you have to typically draw most of the hierarchy when even a single widget changes unless you maintain a state based cache. You’re inherently calculating construction of more unless you’re also doing the same optimizations that a retained mode system does.
The tree vs vector analogy isn’t correct either because neither mode prescribe a data structure. I know it was meant to be an analogy but I don’t think it really applies because it doesn’t reflect most code bases and frameworks.
Maybe our definitions of immediate vs retained don’t align.
As for metrics, I don’t have any on hand, and that perhaps makes the discussion moot, but we’ve done multiple UI implementations on my projects, and immediate UIs don’t compare favourably for energy use until and unless you introduce a retained backing.
Indeed that’s what interfaces like Flutter and SwiftUI do by exposing a React+immediate style API while working over a retained base.
I wish I could share our metrics, and I recognize there’s no reason for you to take me at my word on that, but we have done significant work in this area to compare systems for our projects. For reference , we often make use of multiple APIs across our different apps like Dear,Imgui and SwiftUI depending on their needs.
Maintainer of Lottie for Android here. I left Airbnb 5 years ago and have maintained the library 100% on nights and weekends for the past 6 years. I know your comment was sarcasm but fyi ;)
This may have been a case of what I call the contrarian dynamic (https://hn.algolia.com/?dateRange=all&page=0&prefix=true&sor...): threads tend to fill up quickly with lazy and dismissive objections because those are the easiest and fastest to write. Then a second wave of "I can't believe how bad the comments are" comments inevitably shows up.
Things eventually balance out as thoughtful users add more interesting comments—they just take longer to appear because they're more work to produce. That's what happened in the current thread.
> Shame on you dang, where the fuck are you?
Don't assume that we see the same things you do. Like other false assumptions, that can lead to mistaken conclusions! In reality, we only see a small portion of what gets posted to HN. There are far too many posts for us to read them all. If you see a post that ought to have been moderated but hasn't been, the likeliest explanation is that we didn't see it. You can help by flagging it or emailing us at hn@ycombinator.com.