From 73709188fdad4157f74118042ad75696913dff80 Mon Sep 17 00:00:00 2001 From: Irvanal Haq Date: Sun, 20 Apr 2025 18:18:28 +0700 Subject: [PATCH 1/3] Fix Write() stroke width to scale with font_size or object scale --- manim/animation/creation.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/manim/animation/creation.py b/manim/animation/creation.py index dc3ec69527..4347315413 100644 --- a/manim/animation/creation.py +++ b/manim/animation/creation.py @@ -85,7 +85,7 @@ def construct(self): from manim.mobject.text.text_mobject import Text from manim.scene.scene import Scene -from manim.constants import RIGHT, TAU +from manim.constants import DEFAULT_FONT_SIZE, DEFAULT_STROKE_WIDTH, RIGHT, TAU from manim.mobject.opengl.opengl_surface import OpenGLSurface from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject from manim.utils.color import ManimColor @@ -94,6 +94,7 @@ def construct(self): from ..animation.animation import Animation from ..animation.composition import Succession from ..mobject.mobject import Group, Mobject +from ..mobject.svg.svg_mobject import SVGMobject from ..mobject.types.vectorized_mobject import VMobject from ..utils.bezier import integer_interpolate from ..utils.rate_functions import double_smooth, linear @@ -322,6 +323,7 @@ def construct(self): def __init__( self, vmobject: VMobject | OpenGLVMobject, + stroke_width: float | None = None, rate_func: Callable[[float], float] = linear, reverse: bool = False, **kwargs, @@ -333,11 +335,13 @@ def __init__( run_time, lag_ratio, ) + stroke_width = self._adjust_stroke_width_for_text(vmobject, stroke_width) self.reverse = reverse if "remover" not in kwargs: kwargs["remover"] = reverse super().__init__( vmobject, + stroke_width=stroke_width, rate_func=rate_func, run_time=run_time, lag_ratio=lag_ratio, @@ -358,6 +362,19 @@ def _set_default_config_from_length( lag_ratio = min(4.0 / max(1.0, length), 0.2) return run_time, lag_ratio + def _adjust_stroke_width_for_text( + self, + vmobject: VMobject | OpenGLVMobject, + stroke_width: float | None, + scale_factor: float = 0.25, + ) -> float: + if stroke_width is not None: + return stroke_width + if not isinstance(vmobject, SVGMobject): + return 2.0 # default in DrawBorderThenFill + font_size = getattr(vmobject, "font_size", DEFAULT_FONT_SIZE) + return (font_size / DEFAULT_FONT_SIZE) * DEFAULT_STROKE_WIDTH * scale_factor + def reverse_submobjects(self) -> None: self.mobject.invert(recursive=True) From d3d42044b701e57529cd80abff0b63cc740d07ca Mon Sep 17 00:00:00 2001 From: Irvanal Haq Date: Sun, 20 Apr 2025 18:32:18 +0700 Subject: [PATCH 2/3] add docstring for Write --- manim/animation/creation.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/manim/animation/creation.py b/manim/animation/creation.py index 4347315413..44a8d622d9 100644 --- a/manim/animation/creation.py +++ b/manim/animation/creation.py @@ -294,7 +294,23 @@ def interpolate_submobject( class Write(DrawBorderThenFill): - """Simulate hand-writing a :class:`~.Text` or hand-drawing a :class:`~.VMobject`. + """Simulate hand-writing a text-based mobject, such as :class:`~.Text`, + :class:`~.MarkupText`, :class:`~.Tex`, :class:`~.MathTex`, + or :class:`~.VMobject` in general. + + Parameters + ---------- + vmobject + The VMobject to animate. + stroke_width + Stroke width for drawing. If not given, for SVG-based mobjects (such as :class:`Text`, :class:`MarkupText`, or :class:`MathTex`) + the stroke width is scaled relative to the font size. Others use 2.0. + rate_func + The function defining the animation progress. + reverse + If ``True``, plays the animation in reverse. + **kwargs + Additional arguments passed to the parent class :class:`~.DrawBorderThenFill`. Examples -------- From 7eddf9ea65ed81def6d6c58a367fde9bca2ff95d Mon Sep 17 00:00:00 2001 From: Irvanal Haq Date: Wed, 23 Apr 2025 17:50:42 +0700 Subject: [PATCH 3/3] scale stroke_width if font_size is too small or too big --- manim/animation/creation.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/manim/animation/creation.py b/manim/animation/creation.py index 44a8d622d9..c00404f828 100644 --- a/manim/animation/creation.py +++ b/manim/animation/creation.py @@ -294,17 +294,17 @@ def interpolate_submobject( class Write(DrawBorderThenFill): - """Simulate hand-writing a text-based mobject, such as :class:`~.Text`, - :class:`~.MarkupText`, :class:`~.Tex`, :class:`~.MathTex`, - or :class:`~.VMobject` in general. + """Simulate hand-writing a text-based mobject, such as :class:`~.Text` + and :class:`~.Tex`, or simulate hand-drawing a :class:`~.VMobject`. Parameters ---------- vmobject The VMobject to animate. stroke_width - Stroke width for drawing. If not given, for SVG-based mobjects (such as :class:`Text`, :class:`MarkupText`, or :class:`MathTex`) - the stroke width is scaled relative to the font size. Others use 2.0. + Stroke width for drawing. If not provided, it is scaled based on font size + for text-based mobjects when the font is very small or very large; + otherwise defaults to 2.0. rate_func The function defining the animation progress. reverse @@ -386,10 +386,14 @@ def _adjust_stroke_width_for_text( ) -> float: if stroke_width is not None: return stroke_width - if not isinstance(vmobject, SVGMobject): - return 2.0 # default in DrawBorderThenFill + if not isinstance(vmobject, SVGMobject) or vmobject.height == 0: + return 2 font_size = getattr(vmobject, "font_size", DEFAULT_FONT_SIZE) - return (font_size / DEFAULT_FONT_SIZE) * DEFAULT_STROKE_WIDTH * scale_factor + if font_size < 20 or font_size > 6 * DEFAULT_FONT_SIZE: + # adjust stroke_width if font_size is too small or too big + return (font_size / DEFAULT_FONT_SIZE) * DEFAULT_STROKE_WIDTH * scale_factor + else: + return 2 def reverse_submobjects(self) -> None: self.mobject.invert(recursive=True)