Repository: ManimCommunity/manim
File: manim/mobject/mobject.py (Python)

Code before:
                    f4 = Text("F").scale(-1)

                    vgroup = VGroup(f1, f2, f3, f4).arrange(6 * RIGHT)
                    self.add(vgroup)

        See also
        --------
        :meth:`move_to`

        """
        self.apply_points_function_about_point(
            lambda points: scale_factor * points, about_point, about_edge
        )
        return self

    def rotate_about_origin(self, angle: float, axis: Vector3D = OUT, axes=[]) -> Self:
        """Rotates the :class:`~.Mobject` about the ORIGIN, which is at [0,0,0]."""
        return self.rotate(angle, axis, about_point=ORIGIN)

    def rotate(
        self,
        angle: float,
        axis: Vector3D = OUT,
        about_point: Point3DLike | None = None,
        *,
        about_edge: Vector3D | None = None,
    ) -> Self:
        """Rotates the :class:`~.Mobject` about a certain point."""
        rot_matrix = rotation_matrix(angle, axis)
        self.apply_points_function_about_point(
            lambda points: np.dot(points, rot_matrix.T), about_point, about_edge
        )
        return self

    def flip(
        self,
        axis: Vector3D = UP,
        *,
        about_point: Point3DLike | None = None,
        about_edge: Vector3D | None = None,
    ) -> Self:
        """Flips/Mirrors an mobject about its center.

        Examples
        --------

        .. manim:: FlipExample
            :save_last_frame:

            class FlipExample(Scene):
                def construct(self):

Review comment (suggestion):
I don't know why, originally, `about_point` was a positional argument not included in `**kwargs`, but it should have been there for consistency.

Now that you're proposing being explicit with these kwargs, I still think that `about_point` should be a keyword argument. It's probably a slightly breaking change, but it's much more consistent with the rest of the code:
```py
    def rotate(
        self,
        angle: float,
        axis: Vector3D = OUT,
        *,
        about_point: Point3DLike | None = None,
        about_edge: Vector3DLike | None = None,
    ) -> Self:
```

Code after:
                    f3 = Text("F").scale(0.5)
                    f4 = Text("F").scale(-1)

                    vgroup = VGroup(f1, f2, f3, f4).arrange(6 * RIGHT)
                    self.add(vgroup)

        See also
        --------
        :meth:`move_to`

        """
        self.apply_points_function_about_point(
            lambda points: scale_factor * points, about_point, about_edge
        )
        return self

    def rotate_about_origin(self, angle: float, axis: Vector3DLike = OUT) -> Self:
        """Rotates the :class:`~.Mobject` about the ORIGIN, which is at [0,0,0]."""
        return self.rotate(angle, axis, about_point=ORIGIN)

    def rotate(
        self,
        angle: float,
        axis: Vector3DLike = OUT,
        *,
        about_point: Point3DLike | None = None,
        about_edge: Vector3DLike | None = None,
    ) -> Self:
        """Rotates the :class:`~.Mobject` around a specified axis and point.

        Parameters
        ----------
        angle
            The angle of rotation in radians. Predefined constants such as ``DEGREES``
            can also be used to specify the angle in degrees.
        axis
            The rotation axis (see :class:`~.Rotating` for more).
        about_point
            The point about which the mobject rotates. If ``None``, rotation occurs around
            the center of the mobject.
        about_edge
            The edge about which to apply the scaling.

        Returns
        -------
        :class:`Mobject`
            ``self`` (for method chaining)


        .. note::
            To animate a rotation, use :class:`~.Rotating` or :class:`~.Rotate`