Repository: ManimCommunity/manim
File: manim/renderer/cairo_renderer.py (Python)

Code before:
        self.num_plays += 1

    def update_frame(  # TODO Description in Docstring
        self,
        scene,
        mobjects=None,
        include_submobjects=True,
        ignore_skipping=True,
        **kwargs,
    ):
        """Update the frame.

        Parameters
        ----------
        mobjects: list, optional
            list of mobjects

        background: np.ndarray, optional
            Pixel Array for Background.

        include_submobjects: bool, optional

        ignore_skipping : bool, optional

        **kwargs

        """
        if self.skip_animations and not ignore_skipping:
            return
        if mobjects is None:
            mobjects = list_update(
                scene.mobjects,
                scene.foreground_mobjects,
            )
        if self.static_image is not None:
            self.camera.set_frame_to_background(self.static_image)
        else:
            self.camera.reset()

        kwargs["include_submobjects"] = include_submobjects
        self.camera.capture_mobjects(mobjects, **kwargs)

    def render(self, scene, time, moving_mobjects):
        self.update_frame(scene, moving_mobjects)
        self.add_frame(self.get_frame())

    def get_frame(self):
        """
        Gets the current frame as NumPy array.

        Returns

Review comment (suggestion):
Altogether, the adjective "static" isn't helpful here since an image is already understood to be non-moving media. A better adjective might be "stationary", or "frozen" so it's not confused with static (as in `@staticmethod`) but it's not the image that is stationary/frozen, it's the Animation/the Mobjects in the Animation.
```suggestion
        # Save a image, to avoid rendering non moving objects.
        self.image = self.save_frame_data(scene, scene.static_mobjects)
```

Code after:
            hash_current_animation = get_hash_from_play_call(
                scene, self.camera, scene.animations, scene.mobjects
            )
            if self.file_writer.is_already_cached(hash_current_animation):
                logger.info(
                    f"Animation {self.num_plays} : Using cached data (hash : %(hash_current_animation)s)",
                    {"hash_current_animation": hash_current_animation},
                )
                self.skip_animations = True
        else:
            hash_current_animation = f"uncached_{self.num_plays:05}"

        if self.skip_animations:
            logger.debug(f"Skipping animation {self.num_plays}")
            hash_current_animation = None

        # adding None as a partial movie file will make file_writer ignore the latter.
        self.file_writer.add_partial_movie_file(hash_current_animation)
        self.animations_hashes.append(hash_current_animation)
        logger.debug(
            "List of the first few animation hashes of the scene: %(h)s",
            {"h": str(self.animations_hashes[:5])},
        )

        # Save a static image, to avoid rendering non moving objects.
        self.static_image = self.save_static_frame_data(scene, scene.static_mobjects)

        self.file_writer.begin_animation(not self.skip_animations)
        scene.begin_animations()
        if scene.is_current_animation_frozen_frame():
            self.update_frame(scene)
            # self.duration stands for the total run time of all the animations.
            # In this case, as there is only a wait, it will be the length of the wait.
            self.freeze_current_frame(scene.duration)
        else:
            scene.play_internal()
        self.file_writer.end_animation(not self.skip_animations)

        self.num_plays += 1

    def update_frame(  # TODO Description in Docstring
        self,
        scene,
        mobjects=None,
        include_submobjects=True,
        ignore_skipping=True,
        **kwargs,
    ):
        """Update the frame.

        Parameters