ManimCommunity / ManimCommunity/manim
Animations cannot be sequentially composed when working on the same object
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 40.9k
- Forks
- 3.1k
- Avg merge
- 3d 12h
- Merged PRs (30d)
- 25
Description
Description of bug / unexpected behavior
As far as I can, there is no way to easily (even sequentially) compose animations into a new animations, at least if the animations work on the same object. Indeed, I can't find any way to produce an animation anim3 that is the sequential composition of anim1 and anim2, as soon as anim1 and anim2 work an the same object. For instance, if we consider this code (see below for full usable code):
class Intro(Scene):
def construct(self):
libA = Rectangle(color=GREY, stroke_width=0, fill_opacity=1.0,fill_color=GRAY)
libB = Circle(color=RED, stroke_width=0, fill_opacity=1.0,fill_color=RED)
self.play(FadeIn(libA))
# Make libB replace libA while rotating the elements
libB.rotate(-PI/2, axis=(0,1,0))
self.play(Rotate(libA, angle=PI/2, axis=(0,1,0)))
self.play(FadeIn(libB, run_time=1/25),
FadeOut(libA, run_time=1/25)),
self.play(Rotate(libB, angle=PI/2, axis=(0,1,0)))
self.wait()
then the animation plays smoothly :
https://github.com/ManimCommunity/manim/assets/2164118/4f730b46-e91a-4c32-8d64-b8b8abb752eb
but if I merge them all in a single animation (using AnimationGroup that seems to be the only method available as far as I see), then this fails:
from manim import *
class Intro(Scene):
def construct(self):
libA = Rectangle(color=GREY, stroke_width=0, fill_opacity=1.0,fill_color=GRAY)
libB = Circle(color=RED, stroke_width=0, fill_opacity=1.0,fill_color=RED)
self.play(FadeIn(libA))
# Make libB replace libA while rotating the elements
libB.rotate(-PI/2, axis=(0,1,0))
### This fails
self.play(AnimationGroup(
Rotate(libA, angle=PI/2, axis=(0,1,0)),
AnimationGroup(
FadeIn(libB, run_time=1/25),
FadeOut(libA, run_time=1/25)),
Rotate(libB, angle=PI/2, axis=(0,1,0)),
lag_ratio=1))
self.wait()
https://github.com/ManimCommunity/manim/assets/2164118/dd664b66-1b6e-4856-8961-fec5d5d8b6cc
Note that I understand that applying multiple animations on the same object can be challenging if we apply them in parallel… but for sequential composition I don't see any conceptual difficulty.
Expected behavior
I expect animations to be composable trivially. Note that I do not want to use many self.play for many reasons:
- first, the animation is supposed to be abstracted into a library, and asking the user to manually loop over a list of animations is really dirty, I would prefer the user to write only
self.play(myobject.turn_into(my_otherobject)). - then, it is harder to control the easing curves of animations played composed with multiple
self.playas the easing curve would be to be split into multiple pieces - it is even harder to compose this animation with another (independent) animation in parallel, as we would need to cut the parallel animation into multiple sub-animations that last the same time as the sub-animations… ugly.
How to reproduce the issue
Code for reproducing the problem
from manim import *
class Intro(Scene):
def construct(self):
libA = Rectangle(color=GREY, stroke_width=0, fill_opacity=1.0,fill_color=GRAY)
libB = Circle(color=RED, stroke_width=0, fill_opacity=1.0,fill_color=RED)
self.play(FadeIn(libA))
# Make libB replace libA while rotating the elements
libB.rotate(-PI/2, axis=(0,1,0))
### This fails
self.play(AnimationGroup(
Rotate(libA, angle=PI/2, axis=(0,1,0)),
AnimationGroup(
FadeIn(libB, run_time=1/25),
FadeOut(libA, run_time=1/25)),
Rotate(libB, angle=PI/2, axis=(0,1,0)),
lag_ratio=1))
self.wait()
You might also want to see a related discussion on discord https://discord.com/channels/581738731934056449/1142285601232662538
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the minimal reproduction in the issue and inspect AnimationGroup and self.play behavior for sequential animations targeting the same object. Use the expected behavior and the linked discussion to define the composition semantics; done means the reproducer works as one composable animation while retaining parallel-animation control.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- computer-graphics
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100