Lottie-web: The `playSegments()` plays the whole animation before playing the segment

Created on 31 Jan 2020  路  9Comments  路  Source: airbnb/lottie-web

Tell us about your environment

  • Browser and Browser Version: MacOS Chrome 79.0.3945.130
  • After Effects Version: N/A

What did you do? Please explain the steps you took before you encountered the problem.
I've created a playground to demonstrate the bug:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="lottie"></div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.5.9/lottie.min.js" type="text/javascript"></script>

<script>
window.animation = window.lottie.loadAnimation({
    container: document.getElementById('lottie'),
    path: 'https://assets8.lottiefiles.com/packages/lf20_kcTWGc.json',
    renderer: 'svg',
    loop: false,
    autoplay: false,
});

</script>
</html>

Now I can use the globally available animation. The animation is stopped at the frame 0;

I want to play the segment:

animation.playSegments([0, 24]);

What did you expect to happen?
I expect animation to play the range 0..24 and stop.

What actually happened? Please include as much _relevant_ detail as possible.
The animation is played entirely before the requested segment plays.

Please provide a download link to the After Effects file that demonstrates the problem.
https://assets8.lottiefiles.com/packages/lf20_kcTWGc.json

Additional details and workaround
It appears that there's a bug with how totalFrames is handled.

I've found at least two ways to overcome the issue:

  1. Resetting the totalFrames:
// BTW 0 does not do the trick as it's considered falsy
animation.totalFrames = 1;
  1. Skipping to the end:
animation.goToAndStop(animation.totalFrames, true);

Sticking with the last one as it feels less hacky, but it would be nice to see an explanation and a fix for this.


This issue is similar to https://github.com/airbnb/lottie-web/issues/318, in which it is advised to wait for the DOMLoaded event, but to be honest, I don't get it. First, in the example above I'm executing the command in the dev console when the animation is definitely loaded and mounted. Second, I'm using the react-lottie package which wraps the animation with React component and plays segments on every props update. In order for it to work, I had to apply my workaround like this:

import Lottie from 'react-lottie';

const Component = ({ animationOptions, segmentsToPlay }) => {
    const animation = useRef(null);

    const onLoaded = () => {
        const { anim } = animation.current;

        anim.goToAndStop(anim.totalFrames, true);
    };

    return (
        <Lottie
            options={animationOptions}
            ref={animation}
            segments={segmentsToPlay}
            eventListeners={[
                {
                    eventName: 'DOMLoaded',
                    callback: onLoaded,
                },
            ]}
        />
    );
};

Most helpful comment

I've added a property initialSegment when loading an animation that should solve this case
https://github.com/airbnb/lottie-web/wiki/loadAnimation-options#initialsegment

All 9 comments

Hi, you probably want to pass the second argument as true
https://github.com/airbnb/lottie-web#playsegmentssegments-forceflag

@bodymovin no, this is intentional, I want the previous segment to finish each time :)
Besides, react-lottie doesn't allow to pass the second parameter to the .playSegments(). I'd need to have a different kind of hack to pass it as true first time only.

So you are proposing that if the animation is paused, playSegments overwrites the current segment but if it is running, it lets the current segment play and then runs the enqueued one?

Now I see what you are trying to say.
I'd say this was not obvious that the animation has a default segment once initially loaded.
But with the case I'm having, how would I tell lottie to initialize stopped at a certain frame and they play segments on demand?

I played a bit more and here's my best solution for now. It gives initial flicker but if the animation is done the way that segments overlap on the edges it allows to reset the initial range on DOMLoaded by using the force flag:

import Lottie from 'react-lottie';

const Component = ({ animationOptions, segmentsToPlay }) => {
    const animation = useRef(null);

    const onLoaded = () => {
        const { anim } = animation.current;

        // Play initial segment
        // Should be a proper range, e.g. [0, 1] or [24, 25]
        // [0, 0] or [24, 24] won't work
        anim.playSegments(segmentsToPlay, true);
    };

    return (
        <Lottie
            options={animationOptions}
            ref={animation}
            segments={segmentsToPlay}
            eventListeners={[
                {
                    eventName: 'DOMLoaded',
                    callback: onLoaded,
                },
            ]}
        />
    );
};

Despite this being a working solution, I still consider this a hack. It would be really helpful to be able to load stopped animation from a certain frame to avoid flicker, i.e. by introducing something like startFromFrame parameter.
It would also make life easier if .playSegments([24, 24], false) would still play just one frame and stop.

If any of this makes sense, I could try to create a PR for any of it.

Hi, Let me think about it. I might directly allow to change the segment before loading the animation so it doesn't get overwritten.
Out of curiosity, why don't you export the animation starting from the frame you need? Is it a dynamic value?

If I get your question right, yes, the initial value can differ. In the case of the animation I attached, it can be either 0 or 24.

I've added a property initialSegment when loading an animation that should solve this case
https://github.com/airbnb/lottie-web/wiki/loadAnimation-options#initialsegment

eventListeners={[
              {
                  eventName: 'DOMLoaded',
                  callback: onLoaded,
              },
          ]}

How? react-lottie does not even have segments or eventListerners props

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cpdt picture cpdt  路  4Comments

casillasluisn12 picture casillasluisn12  路  4Comments

processprocess picture processprocess  路  3Comments

zhengs picture zhengs  路  3Comments

hardy613 picture hardy613  路  4Comments