airbnb / lottie-web

Render After Effects animations natively on Web, Android and iOS, and React Native. http://airbnb.io/lottie/
MIT License
29.86k stars 2.85k forks source link

Add type definitions for events #2920

Closed renspoesse closed 1 year ago

renspoesse commented 1 year ago

Adds types for addEventListener() and related methods. Also documents the drawnFrame event.

renspoesse commented 1 year ago

@bodymovin this implements https://github.com/airbnb/lottie-web/issues/2906.

bodymovin commented 1 year ago

Hey this is great! I have two questions.
Why do you need to replace all the types to interfaces?
What are you using the drawnFrame event for? It is intended as an internal event so I could pass the drawing instructions from the worker to the main thread.

renspoesse commented 1 year ago

This may not be relevant in more recent TypeScript versions, but type aliases for instance used to appear anonymously in error messages, https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#interfaces. Don't feel super strongly though so if you prefer reverting that change, will do.

I was thinking to use drawnFrame to get a measurement of how long each frame takes to render by comparing with a timestamp on enterFrame. To get a quick metric of how close we are to hitting the frame budget in an animation.

bodymovin commented 1 year ago

yes, I'd prefer to keep the PR scoped to the events and keep the types if you don't mind. Regarding the drawnFrame, it makes sense.
Are you using the worker players?

renspoesse commented 1 year ago

In this case I'm trying to get a performance measurement of the regular Canvas renderer for an animation that's heavy on track mattes. So that animators can get an idea of how their animation performs without having to go into the browser's dev tools. Though on Safari at least measuring the difference between enterFrame and drawnFrame doesn't seem to capture this. It's around 5-6ms per frame, whereas painting seems to be the bottleneck:

image

So not sure how useful measuring drawnFrame really is.

renspoesse commented 1 year ago

Would this be because the renderer just produces some instruction set for the canvas, and Safari computes the actual pixels in its compositing step?

bodymovin commented 1 year ago

I don't think it does, since you can add a breakpoint in any part of the code, and you'll see some paints already there, up to where the breakpoint stopped the execution.
It's not a fully reliable test, but I'm almost certain that those paints are synchronous to the execution of the code.
It would be different if you're using the worker, since Safari doesn't support OffscreeCanvas, so I'm collecting a set of instructions in the worker, and flushing them on the drawnFrame event to the main thread.
Dou you get different numbers on Chrome?

renspoesse commented 1 year ago

Interesting:

Browser Time between drawn and enter FPS*
Safari 5-6ms 9
Chrome 9-10ms 55

* Measured by counting enterFrame events per second.

The Chrome FPS makes sense to me; the screen refreshes at 120 Hz but the synchronous rendering takes >8ms. With some additional time for painting and other code there isn't too much of a gap between 10ms and 16ms for rendering at 60 FPS.

Safari seems to be doing a lot of work elsewhere (I'm running Lottie in React, but the page I'm testing with just has the Lottie player and no other code running).

bodymovin commented 1 year ago

Moving all this to the worker would free all that time budget. Even if it will still report 10ms, it's happening on a different thread, so the main thread is virtually not doing anything for Lottie.
But if that's not possible, large masks are expensive to render. The canvas renderer needs to allocate two extra buffers to make sure paintings happen in the right order.
Do you know if the svg numbers differ too much?

renspoesse commented 1 year ago

Yeah but the worker doesn't run in Safari currently (and even if the SVG worker would work, that probably doesn't make a noticeable difference with DOM changes still happening on the main thread).

On SVG this renders at around 45 FPS but becomes too slow in the context of the page we're using the animation. In either case, we've already discussed that the animators will look into less expensive ways to render the animation.

I suppose the main conclusion from this is that the drawn time - enter time method isn't reliable for canvas rendering because it misses a significant portion of work done.

bodymovin commented 1 year ago

anyway, thanks for the PR. I'll merge it. If you want, we can continue the conversation somewhere else.
Curious about why it doesn't work in Safari.

renspoesse commented 1 year ago

Are you referring to the SVG worker not working on Safari? Or to (measuring) the canvas performance. So that I have some info to create an issue where we could discuss further.

bodymovin commented 1 year ago

when you mentioned the worker doesn't run in Safari currently