Search code examples
pythonmanim

In Manim, how can I combine FadeIn and FadeOut in one animation?


I'm trying to create an animation that fades in a MathTex and then fades it out, as the text scales up and shifts its position throughout the whole animation.

I know I could make it like this, using two animations with ReplacementTransform:

txt_3_start = MathTex(
            "3",
            color=RED,
            font_size = 1,
        ).set_opacity(0)
        
txt_3_middle = MathTex(
            "3",
            color=GREEN,
            stroke_width = f_z_stroke_width,
            font_size= 1 * 1.5,
        ).shift(RIGHT).set_opacity(1)
        
txt_3_end = MathTex(
            "3",
            color=BLUE,
            font_size= 1 * 1.5 * 1.5,
        ).shift(2*RIGHT).set_opacity(0)
        
        self.play(
            ReplacementTransform(txt_3_start, txt_3_middle, rate_func=linear),
        )
        
        self.play(
            ReplacementTransform(txt_3_middle, txt_3_end, rate_func=linear),
        )

This works fine and has the desired effect.

However I also want another animation to play at the same time, for example a square being written. Therefore, I tried to do the previous two animations in just one animation using Succession like this:

txt_3_anim = Succession(
            ReplacementTransform(txt_3_start, txt_3_middle, rate_func=linear),
            ReplacementTransform(txt_3_middle, txt_3_end, rate_func=linear),
        )

my_square = Square(color = RED, fill_opacity=1, fill_color = BLUE)
        
        self.play(
            Write(my_square),
            txt_3_anim
        )

But when I do that, I get an unexpected behaviour: txt_3_middle appears throughout the whole animation, since it starts until it ends.

I have tried alternatives like using targets and the animate function, but I keep getting the same problem.

Can anyone help? Thanks!


Solution

  • Succession() has that unexpected behaviour. It adds to the scene all objects involved in any of the animations you pase to it (except if those object are part of a "introduction animation", which are those which show the creation of objects).

    Since your animations are not of type "introduction", then Succession() adds to the scene the objects txt_3_start, txt_3_middle, and txt_3_end. The first and last are not visible due to opacity=0, but the middle one has opacity=1 and thus it is visible.

    I cannot think any way of using Succession() without running into this problem. If you make the middle object transparent, then any of the transformations will produce any visible output, since all involved objects are invisible.

    You may write your own Animation class for transforming one object into another, and then into another. But that solution may be overkill for this particular case.

    A simpler solution that can be used here is to play your two transformations in two separate self.play(), as in your first code, and at the same time use an updater for the creation of the square. Like this:

    There is a little helper function, hidden in manim, called turn_animation_into_updater() which can be used to create an updater without needing to write it.

            # Create the updater which will write the square
            my_square = Square(color = RED, fill_opacity=1, fill_color = BLUE)
            self.add(my_square)
            turn_animation_into_updater(Write(my_square, run_time=2))
    
            # the updater will be run during the `self.play()` or `self.wait()` calls
            self.play(
                ReplacementTransform(txt_3_start, txt_3_middle, rate_func=linear),
            )
            self.play(
                ReplacementTransform(txt_3_middle, txt_3_end, rate_func=linear),
            )
    
            )
            # the updater is automatically removed when Write() finishes
    

    This produces the intended animation (I changed the font size you used in your example to 50, to make the text visible here):

    Result