diff --git a/docs/html b/docs/html
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 5b607e9c8b..d0a2410c8b 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -4,4 +4,5 @@ sphinx>=7.3
sphinx-copybutton
sphinxext-opengraph
sphinx-design
+sphinx-togglebutton
sphinx-reredirects
diff --git a/docs/rtd-requirements.txt b/docs/rtd-requirements.txt
index 3220975d34..083a9af9a7 100644
--- a/docs/rtd-requirements.txt
+++ b/docs/rtd-requirements.txt
@@ -1,2 +1,3 @@
jupyterlab
sphinxcontrib-programoutput
+sphinx-design
diff --git a/docs/skip-manim b/docs/skip-manim
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docs/source/_static/AdventureManim.png b/docs/source/_static/AdventureManim.png
new file mode 100644
index 0000000000..754145a9a8
Binary files /dev/null and b/docs/source/_static/AdventureManim.png differ
diff --git a/docs/source/adventure/basics.rst b/docs/source/adventure/basics.rst
new file mode 100644
index 0000000000..cfd5088605
--- /dev/null
+++ b/docs/source/adventure/basics.rst
@@ -0,0 +1,696 @@
+******************************************************
+An Adventure through Manim's Features and Capabilities
+******************************************************
+
+.. image:: ../_static/AdventureManim.png
+ :align: center
+
+
+**Authors:** `Tristan Schulz `__ and `Aarush Deshpande `__
+
+.. note:: This is a work in progress guide and might not be complete at this point
+
+##############
+What to expect
+##############
+This guide will take you on a Tour through the features and capabilities of Manim. The goal is to give you a good overview of what Manim can do and how to use it. It is not meant to be a complete reference, but rather a starting point for your own explorations.
+
+The goal of this guide is to give you a clear path from the basics of Manim to a finished animation. It will not go into detail about the inner workings of Manim, but rather focus on the practical aspects of using it.
+At the end of this guide you should be able to create your own animations and have a good understanding of how to use Manim.
+
+.. warning::
+ Please note that this guide is only for Manim and expects basic knowledge about programming with Python. If you are new to Python you should first learn the basics of Python before you start with Manim.
+ You can find a full introduction to Python here: https://docs.python.org/3/tutorial/
+
+ You can still follow this guide with basic knowledge of Python, but you will have to learn some Python basics along the way in order to understand the code examples.
+
+#################
+What are Mobjects
+#################
+
+Mobjects are the basic building blocks of Manim. They are the objects that are animated and displayed on the screen.
+Mobjects can be anything from simple shapes to complex 3D objects. They can be animated, moved, rotated, scaled and much more.
+In this guide we will focus on the 2D Mobjects, but the same principles apply to 3D Mobjects as well.
+
+.. manim:: MobjectsFloating
+ :hide_source:
+
+ class MobjectsFloating(Scene):
+ def construct(self):
+ c = Circle()
+ s = Square()
+ t = Triangle()
+ c.shift(UP)
+ t.shift(LEFT*3+DOWN)
+ s.shift(RIGHT*3+DOWN)
+ self.add(c, s, t)
+ timer = ValueTracker(0)
+ c.add_updater(lambda m: m.move_to(UP+0.2*DOWN*np.sin(timer.get_value()+1)))
+ s.add_updater(lambda m: m.move_to(RIGHT*3+DOWN+0.3*DOWN*np.sin(timer.get_value()+2)))
+ t.add_updater(lambda m: m.move_to(LEFT*3+DOWN+0.3*DOWN*np.sin(timer.get_value()+4)))
+ self.add(timer)
+ self.play(timer.animate.set_value(2*np.pi), run_time=5, rate_func=linear)
+
+
+
+For a list of all Mobjects you can look at the :doc:`/reference_index/mobjects` Documentation Page. There are many more to explore and you can even create your own Mobjects, which we will cover later.
+
+
+.. manim:: PredefinedMobjects
+ :save_last_frame:
+ :hide_source:
+
+ class PredefinedMobjects(Scene):
+ def construct(self):
+ c = Circle()
+ s = Square().set_color(GREEN)
+ t = Triangle()
+ graph = FunctionGraph(lambda x: np.sin(x))
+ axis = Axes()
+ par = ParametricFunction(lambda t: np.array([np.cos(3*t), np.sin(2*t), 0]), [0, 2*np.pi])
+ mat = Matrix([["\\pi", 0], [0, 1]])
+ chart = BarChart(
+ values=[-5, 40, -10, 20, -3],
+ bar_names=["one", "two", "three", "four", "five"],
+ y_range=[-20, 50, 10],
+ y_length=6,
+ x_length=10,
+ x_axis_config={"font_size": 36},
+ ).shift(RIGHT/2)
+ func = lambda pos: ((pos[0] * UR + pos[1] * LEFT) - pos) / 3
+ vecfield = ArrowVectorField(func,x_range=[-3,3],y_range=[-3,3])
+ cross = VGroup(
+ Line(UP + LEFT, DOWN + RIGHT),
+ Line(UP + RIGHT, DOWN + LEFT))
+ a = Circle().set_color(RED).scale(0.5)
+ b = cross.set_color(BLUE).scale(0.5)
+ t3 = MobjectTable(
+ [[a.copy(),b.copy(),a.copy()],
+ [b.copy(),a.copy(),a.copy()],
+ [a.copy(),b.copy(),b.copy()]])
+ t3.add(Line(
+ t3.get_corner(DL), t3.get_corner(UR)
+ ).set_color(RED))
+
+ group = [c, s, t, graph, axis, par, mat, chart, vecfield, t3]
+ names = ["Circle", "Square", "Triangle", "FunctionGraph", "Axes", "ParametricFunction", "Matrix", "BarChart" ,"ArrowVectorField", "MobjectTable"]
+ zipped = zip(group, names)
+ combined = []
+ for mob, name in zipped:
+ square = Square()
+ name = Text(name).scale(0.5)
+ mob.scale_to_fit_width(square.get_width())
+ square.scale(1.2)
+ name.next_to(square, DOWN)
+ group = VGroup(mob, name, square)
+ combined.append(group)
+
+ all = VGroup(*combined).arrange_in_grid(buff=1,rows=2).scale(0.8).to_edge(UP)
+ dots = MathTex("\\dots").next_to(all, DOWN, buff=1)
+ self.add(all, dots)
+
+.. note::
+ The type of Mobject that is used most of the time is the `VMobject`. This is a Mobject that is made up of `VectorizedPoints`. These are points that are defined by their coordinates and can be connected by lines or curves.
+ Every time we talk about Mobjects in this guide we mean VMobjects, unless we state otherwise.
+
+=============================
+Mobjects and their Attributes
+=============================
+
+In order to display Mobjects in your animations you need to add them to the scene. You can do this by calling ``self.add(mobject)`` in the ``construct`` method of your scene.
+This tells Manim that you want to display the Mobject in your scene.
+
+.. manim:: CreatingMobjects
+ :save_last_frame:
+
+ class CreatingMobjects(Scene):
+ def construct(self):
+ c = Circle()
+ self.add(c)
+
+This will be the basic structure of all your animations. You will create Mobjects and add them to the scene. Then you can animate them and change their properties.
+Try the "Make Interactive" Button and see if you can create a `Square` instead of a `Circle`.
+
+The first line is the name of your scene, in this case it is ``CreatingMobjects``. It inherits from ``Scene``: as we explore later, you'll find examples where we inherit from
+class other than ``Scene`` to gain access to more specialized methods. Your animation must take place in the ``construct`` method of your scene, otherwise it will not render.
+
+You can run this scene on your local machine by saving it in a file called ``my_first_scene.py`` and running ``manim -pqm my_first_scene.py`` in the terminal.
+
+------------------
+Mobject Attributes
+------------------
+
+Mobjects also posses many attributes that you can change. For example you can change the color of a Mobject by calling ``mobject.set_color(color)`` or scale it by calling ``mobject.scale(factor)``.
+
+The basic attributes are the ``points``, ``fill_color``, ``fill_opacity``, ``stroke_color``, ``stroke_opacity``, ``stroke_width``.
+The ``points`` define the outline of the Mobject, whereas the color attributes define how this outline is displayed.
+
+A full list of the attributes of :class:`VMobject` can be found in the :doc:`../reference/manim.mobject.types.vectorized_mobject.VMobject` Documentation Page. Please note that depending
+on the type of Mobject you are using, there might be additional attributes, which are listed on the corresponding documentation page.
+
+-------------------
+Changing the Points
+-------------------
+
+Most of the function that you will use in Manim will be functions that change the points of a Mobject. For example ``mobject.shift(direction)`` will move the Mobject in the given direction.
+On the other hand, ``mobject.rotate(angle)`` will rotate the Mobject by the given angle.
+
+.. manim:: MobjectPoints
+ :save_last_frame:
+
+ class MobjectPoints(Scene):
+ def construct(self):
+ c = Circle()
+ s = Square()
+ t = Triangle()
+
+ c.shift(3*LEFT)
+ s.rotate(PI/4)
+ t.shift(3*RIGHT)
+
+ self.add(c, s, t)
+
+------------------
+Changing the Color
+------------------
+
+Changing the color works in the same way but instead of modifying it you can set it to a new value. For example ``mobject.set_fill(color=color)`` will set the fill color of the Mobject to the given color.
+
+You can also pass in attributes through the constructor of the Mobject. For example ``Circle(fill_color=RED)`` will create a circle with a red fill color.
+For a list of parameters that you can pass you can always visit the corresponding Documentation Page in the Reference Manual.
+
+.. manim:: MobjectColor
+ :save_last_frame:
+
+ class MobjectColor(Scene):
+ def construct(self):
+ c = Circle(fill_color=YELLOW).shift(3*LEFT)
+ s = Square()
+ t = Triangle().shift(3*RIGHT)
+
+ c.set_fill(color=RED).set_opacity(1)
+ s.set_stroke(color=GREEN)
+ t.set_color(color=BLUE).set_opacity(0.5)
+
+ self.add(c, s, t)
+
+
+-------------------
+Test your Knowledge
+-------------------
+
+Now that you saw the basic ways to change Mobjects, try to reproduce the following Image. You can use the "Make Interactive" Button of the above Scene to get started.
+
+.. manim:: TestYourKnowledge1
+ :save_last_frame:
+ :hide_source:
+
+ class TestYourKnowledge1(Scene):
+ def construct(self):
+ c = Circle(fill_color=RED,stroke_color=GREEN).shift(3*LEFT)
+ s = Square(fill_color=GREEN,stroke_color=BLUE).set_opacity(0.2)
+ t = Triangle(fill_color=RED,stroke_opacity=0).shift(RIGHT)
+
+ c.set_fill(color=RED).set_opacity(1)
+ s.set_stroke(color=GREEN)
+ t.set_color(color=BLUE).set_opacity(0.5)
+
+ self.add(c, s, t)
+
+
+###################
+Animations in Manim
+###################
+
+Now that we looked long enough at static Images, let's get to the fun part of Manim. Animations!
+Animations are at the core of Manim and are what makes it so powerful. You can animate almost anything in Manim and you can do it in many different ways.
+In this section we will look at the different ways to animate Mobjects and how to control the animations.
+
+.. manim:: Manimations1
+ :hide_source:
+
+ class Manimations1(Scene):
+ def construct(self):
+ c = Circle().shift(UP).set_color(RED)
+ s = Square().shift(LEFT*3)
+ t = Triangle().shift(RIGHT*3)
+ l = MathTex(r"\mathbf{M}").shift(DOWN).set_fill(opacity=0).set_stroke(color=WHITE, opacity=1, width=5).scale(4)
+ self.play(AnimationGroup(Create(c), GrowFromCenter(s), Write(l), FadeIn(t), lag_ratio=0.2))
+ group = VGroup(l,c, s, t)
+ self.play(group.animate.arrange(RIGHT))
+ self.play(group.animate.arrange(DOWN))
+ self.play(group.animate.arrange_in_grid(buff=1,rows=2))
+ self.play(Unwrite(group))
+
+
+
+================================
+Introduction to Basic Animations
+================================
+
+There are multiple ways to animate the addition and removal of mobjects from the scene. The most common ways to introduce mobjects is with ``FadeIn`` or ``Create``,
+and the most common ways to remove objects from the scene are their counterparts: ``FadeOut`` and ``Uncreate``.
+
+.. manim:: BasicAnimations
+
+ class BasicAnimations(Scene):
+ def construct(self):
+ c1 = Circle().shift(2*LEFT)
+ c2 = Circle().shift(2*RIGHT)
+ self.play(FadeIn(c1), Create(c2))
+ self.play(FadeOut(c1), Uncreate(c2))
+
+--------
+Runtimes
+--------
+
+You can adjust the duration of each animation individually, or you can set a duration for all in animations in a ``Scene.play`` call.
+
+.. manim:: AnimationRuntimes
+
+ class AnimationRuntimes(Scene):
+ def construct(self):
+ c = Circle().shift(2*LEFT)
+ s = Square().shift(2*RIGHT)
+ # set animation runtimes individually
+ self.play(Create(c, run_time=2), Create(s, run_time=1))
+ # in this call, the individual runtimes of each animation
+ # are overridden by the runtime in the self.play call
+ self.play(FadeOut(c, run_time=2), FadeOut(s, run_time=1), run_time=1.5)
+
+--------------
+Rate Functions
+--------------
+A rate function allows you to adjust the speed at an animation proceeds.
+
+.. manim:: RateFunctionsExample
+
+ class RateFunctionsExample(Scene):
+ def construct(self):
+ c1 = Circle().shift(2*LEFT)
+ c2 = Circle().shift(2*RIGHT)
+ self.play(
+ Create(c1, rate_func=rate_functions.linear),
+ Create(c2, rate_func=rate_functions.ease_in_sine),
+ run_time=5
+ )
+
+You can see all of the current ones below:
+
+.. manim:: AllRateFunctions
+ :hide_source:
+
+ class AllRateFunctions(Scene):
+ def construct(self):
+ time_progress = ValueTracker(0)
+ func_grid = VGroup()
+ exclude = ["wraps", "bezier", "sigmoid", "unit_interval", "zero", "not_quite_there", "squish_rate_func"]
+ rate_funcs = list(filter(
+ lambda t: str(t[1])[:10] == "`__ and `Aarush Deshpande `__
+
+.. note:: This is a work in progress guide and might not be complete at this point
+
+############
+Introduction
+############
+Throughout this guide, we'll walk you through how to create a simple 30 second video about vector addition. If you don't
+already know what that is, it's recommended you watch `this `_ video
+by the original creator of manim, 3Blue1Brown.
+
+The next step is figuring out how the project should look: what content should it cover, in what order, etc. In this
+tutorial, we'll focus on two parts of vector addition: the algebraic way, and the geometric way. For the algebraic way,
+we'll show two vectors (as matrices) being added, and give a short explanation. After that we'll show the typical tip-to-tail
+method for adding vectors graphically. Of course, choosing good examples is very important to help the viewer understand.
+In our case, we'll use the two vectors :math:`v_1\equiv\langle 2, 1\rangle` and :math:`v_2\equiv\langle 0,-3 \rangle`.
+
+################
+Vector Addition
+################
+
+We'll start with the basic setup needed for every manim video.
+To do this, we can use the manim cli to speed stuff up. In the terminal,
+run::
+
+ manim init project VectorAddition
+
+This should create a folder called ``VectorAddition`` with the basic setup.
+
+.. hint::
+
+ You may want to open this folder in your IDE (like VS Code, or PyCharm).
+
+You will have a ``manim.cfg`` file, where you configuration will be stored, and a ``main.py`` script.
+The ``main.py`` script is where you will write your scenes.
+
+If you did it correctly, running the python file with ``manim -p main.py`` should render a scene
+with a circle being created:
+
+.. manim:: CreateCircle
+ :hide_source:
+
+ class CreateCircle(Scene):
+ def construct(self):
+ circle = Circle()
+ circle.set_fill(PINK, opacity=0.5)
+
+ square = Square()
+ square.flip(RIGHT)
+ square.rotate(-3 * TAU / 8)
+
+ self.play(Create(square))
+ self.play(Transform(square, circle))
+ self.play(FadeOut(square))
+
+============
+Introduction
+============
+First we need to introduce the viewer to what we're going to talk about. Ideally,
+it would be an interesting hook, but for the sake of learning the library we will
+stick with a simple text-based intro. Try to recreate the following:
+
+.. manim:: AdventureIntro
+ :hide_source:
+ :ref_classes: Tex Text Write Unwrite Create
+
+ class AdventureIntro(Scene):
+ def construct(self):
+ intro = Text("Let's try to add two vectors!")
+ # put an r"" instead of a normal string so we don't have any special characters like \n
+ vec_txts = Tex(r"We'll use $\boldsymbol{\vec{v}_1}=(2, 2)$ and $\boldsymbol{\vec{v}_2}=(0, -3)$")
+ self.play(Create(intro))
+ self.wait(1)
+ # "grey out" the intro and shift it upwards as we write the second line
+ self.play(intro.animate.shift(2*UP).set_opacity(0.5), Write(vec_txts))
+ self.wait(1)
+ self.play(Unwrite(intro), Unwrite(vec_txts), run_time=.5)
+ self.wait(0.2)
+
+
+.. admonition:: Authors solution
+ :class: dropdown
+
+ .. code-block:: python
+
+ class AdventureIntro(Scene):
+ def construct(self):
+ intro = Text("Let's try to add two vectors!")
+ # put an r"" instead of a normal string so we don't have any special characters like \n
+ vec_txts = Tex(
+ r"We'll use $\boldsymbol{\vec{v}_1}=(2, 2)$ and $\boldsymbol{\vec{v}_2}=(0, -3)$"
+ )
+ self.play(Create(intro))
+ self.wait(1)
+ # "grey out" the intro and shift it upwards as we write the second line
+ self.play(intro.animate.shift(2 * UP).set_opacity(0.5), Write(vec_txts))
+ self.wait(1)
+ self.play(Unwrite(intro), Unwrite(vec_txts), run_time=0.5)
+ self.wait(0.2)
+
+============================
+Algebraic vector addition
+============================
+
+Then, let's show the viewer how vector addition between two vectors is done algebraically.
+Once again, try to recreate the following:
+
+
+.. manim:: AlgebraicAddition
+ :hide_source:
+ :ref_classes: Title MathTex Paragraph Tex Text Write Unwrite Create FadeIn
+
+ class AlgebraicAddition(Scene):
+
+ def construct(self):
+ title = Title("Vector Addition Algebraically")
+
+ v1x, v1y = (2, 2)
+ v2x, v2y = (0, -3)
+ math = MathTex(r"""
+ \begin{bmatrix} %(v1x)d \\ %(v1y)d \end{bmatrix}
+ +\begin{bmatrix} %(v2x)d \\ %(v2y)d \end{bmatrix}
+ """ % {
+ 'v1x': v1x,
+ 'v2x': v2x,
+ 'v1y': v1y,
+ 'v2y': v2y
+ }).shift(DOWN)
+
+ resultant_vector = r"=\begin{bmatrix} %(x)d \\ %(y)d \end{bmatrix}" % {
+ 'x': v1x+v2x,
+ 'y': v1y+v2y
+ }
+ math_with_answer = MathTex(
+ math.get_tex_string()+resultant_vector
+ ).move_to(math.get_center())
+
+ self.play(Write(math), FadeIn(title))
+ self.wait(2)
+ self.play(
+ math.animate.shift(2*UP).set_opacity(0.5),
+ Write(math_with_answer)
+ )
+ conclusion = Paragraph("As you can see,\nYou add each component individually").to_edge(DOWN)
+ self.play(Write(conclusion))
+ self.wait(2)
+ self.play(Unwrite(math), Unwrite(math_with_answer), Unwrite(conclusion), Unwrite(title))
+
+Hints
+-----
+
+Use :class:`.Title` to display the title at the top of the Scene.
+
+Use :class:`.MathTex` to represent the matrices, and try not to hardcode the values into the LaTeX string. Instead, you can use python string formatting and numpy vector addition, which will make it easier to change the vectors later if we need to.
+
+.. code-block:: python
+
+ v1x, v1y = (2, 2)
+ v2x, v2y = ...
+ math = MathTex(r"""
+ ... %(v1x)d \\ %(v1y)d ...
+ + ... %(v2x)d \\ %(v2y)d ...
+ """ % {
+ 'v1x': v1x,
+ 'v2x': v2x,
+ 'v1y': v1y,
+ 'v2y': v2y
+ })
+
+.. admonition:: Authors solution
+ :class: dropdown
+
+ .. code-block:: python
+
+ class AlgebraicAddition(Scene):
+
+ def construct(self):
+ title = Title("Vector Addition Algebraically")
+
+ v1x, v1y = (2, 2)
+ v2x, v2y = (0, -3)
+ math = MathTex(r"""
+ \begin{bmatrix} %(v1x)d \\ %(v1y)d \end{bmatrix}
+ +\begin{bmatrix} %(v2x)d \\ %(v2y)d \end{bmatrix}
+ """ % {
+ 'v1x': v1x,
+ 'v2x': v2x,
+ 'v1y': v1y,
+ 'v2y': v2y
+ }).shift(DOWN)
+
+ resultant_vector = r"=\begin{bmatrix} %(x)d \\ %(y)d \end{bmatrix}" % {
+ 'x': v1x+v2x,
+ 'y': v1y+v2y
+ }
+ math_with_answer = MathTex(
+ math.get_tex_string()+resultant_vector
+ ).move_to(math.get_center())
+
+ self.play(Write(math), FadeIn(title))
+ self.wait(2)
+ self.play(
+ math.animate.shift(2*UP).set_opacity(0.5),
+ Write(math_with_answer)
+ )
+ conclusion = Paragraph("As you can see,\nYou add each component individually").to_edge(DOWN)
+ self.play(Write(conclusion))
+ self.wait(2)
+ self.play(Unwrite(math), Unwrite(math_with_answer), Unwrite(conclusion), Unwrite(title))
+
+============================
+Geometric vector addition
+============================
+
+Lastly, let's show the vector addition geometrically. Try your best to reconstruct the following:
+
+.. manim:: GeometricAddition
+ :hide_source:
+ :ref_classes: Title MathTex Paragraph Tex Text Write Unwrite Create FadeIn NumberPlane Arrow AnimationGroup ReplacementTransform VGroup
+
+ class VectorGroup(VGroup):
+ def __init__(
+ self, start, end, labelname: str,
+ vector_color: ParsableManimColor, direction = RIGHT,
+ plane: NumberPlane | None = None, **kwargs
+ ) -> None:
+ if plane is not None:
+ # if using a plane convert from plane units
+ # to Munits
+ start = plane.c2p(*start)
+ end = plane.c2p(*end)
+
+ self.vector = Arrow(
+ start,
+ end,
+ color=vector_color,
+ buff=0
+ )
+ self.label = MathTex(labelname, color=vector_color)
+
+ def label_updater(m: MathTex, d=direction):
+ m.next_to(self.vector, direction=d, **kwargs)
+
+ self.label.add_updater(label_updater, call_updater=True)
+ super().__init__(self.vector, self.label, **kwargs)
+
+ @override_animation(Create)
+ def _create_vec_write_label(self) -> AnimationGroup:
+ return AnimationGroup(
+ Create(self.vector),
+ Write(self.label),
+ lag_ratio=0
+ )
+
+ @override_animation(Uncreate)
+ def _uncreate_vec_unwrite_label(self) -> AnimationGroup:
+ return AnimationGroup(
+ Uncreate(self.vector),
+ Unwrite(self.label),
+ lag_ratio=0
+ )
+
+ class GeometricAddition(Scene):
+ def construct(self):
+ title = Text("Now let's take a look at it geometrically")
+ self.play(Write(title))
+ self.wait(2)
+ self.play(Unwrite(title))
+
+ plane = NumberPlane()
+
+ sum_point = (2, -1, 0)
+
+ v1 = VectorGroup(
+ ORIGIN,
+ (2, 2, 0),
+ r"\boldsymbol{\vec{v}_1}",
+ RED,
+ direction=UP,
+ plane=plane
+ )
+
+ v2 = VectorGroup(
+ ORIGIN,
+ (0, -3, 0),
+ r"\boldsymbol{\vec{v}_2}",
+ YELLOW,
+ direction=LEFT,
+ plane=plane
+ )
+
+ v1moved = VectorGroup(
+ (0, -3, 0),
+ sum_point,
+ r"\boldsymbol{\vec{v}_1}",
+ v1.vector.get_color(),
+ plane=plane
+ )
+
+ v2moved = VectorGroup(
+ (2, 2, 0),
+ sum_point,
+ r"\boldsymbol{\vec{v}_2}",
+ v2.vector.get_color(),
+ plane=plane
+ )
+
+ sum_vec = VectorGroup(
+ ORIGIN,
+ sum_point,
+ r"\boldsymbol{\vec{v}_1}+\boldsymbol{\vec{v}_2}",
+ ORANGE,
+ direction=DOWN,
+ plane=plane
+ )
+
+ self.play(Create(plane), Create(v1))
+ self.wait(0.5)
+ self.play(Create(v2))
+ self.wait()
+
+ # animate movement of vectors
+ self.play(
+ Succession(
+ ReplacementTransform(v1.copy(), v1moved),
+ ReplacementTransform(v2.copy(), v2moved)
+ )
+ )
+ self.wait()
+ # draw sum vector
+ self.play(Create(sum_vec))
+ self.wait()
+ self.play(*[
+ Uncreate(x)
+ for x in (
+ plane,
+ v1,
+ v2,
+ v1moved,
+ v2moved,
+ sum_vec
+ )
+ ])
+
+Hints
+-----
+
+Use :class:`.NumberPlane` to define the cartesian plane.
+
+Use :class:`.Arrow` for the vectors.:
+
+To make sure the label of the vector and the vector shift together, you can define a custom :class:`.VGroup` subclass.
+Take a look at the decorator :func:`.override_animation` to override the :class:`.Create` and :class:`.Uncreate` animations, it will come in handy when animating the subclass.
+
+.. code-block:: python
+
+ class VectorGroup(VGroup):
+ def __init__(
+ ...
+ ) -> None:
+ ...
+
+ @override_animation(Create)
+ def _create_vec_write_label(self) -> AnimationGroup:
+ return AnimationGroup(
+ ...
+ )
+
+ @override_animation(Uncreate)
+ def _uncreate_vec_unwrite_label(self) -> AnimationGroup:
+ return AnimationGroup(
+ ...
+ )
+
+.. admonition:: Authors solution
+ :class: dropdown
+
+ .. code-block:: python
+
+ class VectorGroup(VGroup):
+ def __init__(
+ self, start, end, labelname: str,
+ vector_color: ParsableManimColor, direction = RIGHT,
+ plane: NumberPlane | None = None, **kwargs
+ ) -> None:
+ if plane is not None:
+ # if using a plane convert from plane units
+ # to Munits
+ start = plane.c2p(*start)
+ end = plane.c2p(*end)
+
+ self.vector = Arrow(
+ start,
+ end,
+ color=vector_color,
+ buff=0
+ )
+ self.label = MathTex(labelname, color=vector_color)
+
+ def label_updater(m: MathTex, d=direction):
+ m.next_to(self.vector, direction=d, **kwargs)
+
+ self.label.add_updater(label_updater, call_updater=True)
+ super().__init__(self.vector, self.label, **kwargs)
+
+ @override_animation(Create)
+ def _create_vec_write_label(self) -> AnimationGroup:
+ return AnimationGroup(
+ Create(self.vector),
+ Write(self.label),
+ lag_ratio=0
+ )
+
+ @override_animation(Uncreate)
+ def _uncreate_vec_unwrite_label(self) -> AnimationGroup:
+ return AnimationGroup(
+ Uncreate(self.vector),
+ Unwrite(self.label),
+ lag_ratio=0
+ )
+
+ class GeometricAddition(Scene):
+ def construct(self):
+ title = Text("Now let's take a look at it geometrically")
+ self.play(Write(title))
+ self.wait(2)
+ self.play(Unwrite(title))
+
+ plane = NumberPlane()
+
+ sum_point = (2, -1, 0)
+
+ v1 = VectorGroup(
+ ORIGIN,
+ (2, 2, 0),
+ r"\boldsymbol{\vec{v}_1}",
+ RED,
+ direction=UP,
+ plane=plane
+ )
+
+ v2 = VectorGroup(
+ ORIGIN,
+ (0, -3, 0),
+ r"\boldsymbol{\vec{v}_2}",
+ YELLOW,
+ direction=LEFT,
+ plane=plane
+ )
+
+ v1moved = VectorGroup(
+ (0, -3, 0),
+ sum_point,
+ r"\boldsymbol{\vec{v}_1}",
+ v1.vector.get_color(),
+ plane=plane
+ )
+
+ v2moved = VectorGroup(
+ (2, 2, 0),
+ sum_point,
+ r"\boldsymbol{\vec{v}_2}",
+ v2.vector.get_color(),
+ plane=plane
+ )
+
+ sum_vec = VectorGroup(
+ ORIGIN,
+ sum_point,
+ r"\boldsymbol{\vec{v}_1}+\boldsymbol{\vec{v}_2}",
+ ORANGE,
+ direction=DOWN,
+ plane=plane
+ )
+
+ self.play(Create(plane), Create(v1))
+ self.wait(0.5)
+ self.play(Create(v2))
+ self.wait()
+
+ # animate movement of vectors
+ self.play(
+ Succession(
+ ReplacementTransform(v1.copy(), v1moved),
+ ReplacementTransform(v2.copy(), v2moved)
+ )
+ )
+ self.wait()
+ # draw sum vector
+ self.play(Create(sum_vec))
+ self.wait()
+ self.play(*[
+ Uncreate(x)
+ for x in (
+ plane,
+ v1,
+ v2,
+ v1moved,
+ v2moved,
+ sum_vec
+ )
+ ])
+
+
+
+################
+The Final Result
+################
+Putting it all together, we can render the final result.
+
+.. include:: vector_addition.rst
diff --git a/docs/source/adventure/vector_addition.rst b/docs/source/adventure/vector_addition.rst
new file mode 100644
index 0000000000..7a4293e4e7
--- /dev/null
+++ b/docs/source/adventure/vector_addition.rst
@@ -0,0 +1,179 @@
+.. manim:: Adventure
+ :hide_source:
+
+ class VectorGroup(VGroup):
+ def __init__(
+ self, start, end, labelname: str,
+ vector_color: ParsableManimColor, direction = RIGHT,
+ plane: NumberPlane | None = None, **kwargs
+ ) -> None:
+ if plane is not None:
+ # if using a plane convert from plane units
+ # to Munits
+ start = plane.c2p(*start)
+ end = plane.c2p(*end)
+
+ self.vector = Arrow(
+ start,
+ end,
+ color=vector_color,
+ buff=0
+ )
+ self.label = MathTex(labelname, color=vector_color)
+
+ def label_updater(m: MathTex, d=direction):
+ m.next_to(self.vector, direction=d, **kwargs)
+
+ self.label.add_updater(label_updater, call_updater=True)
+ super().__init__(self.vector, self.label, **kwargs)
+
+ @override_animation(Create)
+ def _create_vec_write_label(self) -> AnimationGroup:
+ return AnimationGroup(
+ Create(self.vector),
+ Write(self.label),
+ lag_ratio=0
+ )
+
+ @override_animation(Uncreate)
+ def _uncreate_vec_unwrite_label(self) -> AnimationGroup:
+ return AnimationGroup(
+ Uncreate(self.vector),
+ Unwrite(self.label),
+ lag_ratio=0
+ )
+ class Adventure(Scene):
+ """Goal: Make an example showcasing manim's features"""
+
+ def construct(self) -> None:
+ intro = Text("Let's try to add two vectors!")
+ vec_txts = Tex(r"We'll use $\boldsymbol{\vec{v}_1}=(2, 2)$ and $\boldsymbol{\vec{v}_2}=(0, -3)$")
+ self.play(Create(intro))
+ self.wait(1)
+ self.play(intro.animate.shift(2*UP).set_opacity(0.5), Write(vec_txts))
+ self.wait(1)
+ self.play(Unwrite(intro), Unwrite(vec_txts), run_time=.5)
+ self.wait(0.2)
+
+ self.show_addition_math()
+ self.wait(0.2)
+ self.show_vector_addition()
+
+ outro = Text("Thanks for watching!")
+ self.play(Create(outro))
+ self.wait()
+
+ def show_addition_math(self) -> None:
+ title = Title("Vector Addition Algebraically")
+
+ v1x, v1y = (2, 2)
+ v2x, v2y = (0, -3)
+ math = MathTex(r"""
+ \begin{bmatrix} %(v1x)d \\ %(v1y)d \end{bmatrix}
+ +\begin{bmatrix} %(v2x)d \\ %(v2y)d \end{bmatrix}
+ """ % {
+ 'v1x': v1x,
+ 'v2x': v2x,
+ 'v1y': v1y,
+ 'v2y': v2y
+ }).shift(DOWN)
+
+ resultant_vector = r"=\begin{bmatrix} %(x)d \\ %(y)d \end{bmatrix}" % {
+ 'x': v1x+v2x,
+ 'y': v1y+v2y
+ }
+ math_with_answer = MathTex(
+ math.get_tex_string()+resultant_vector
+ ).move_to(math.get_center())
+
+ self.play(Write(math), FadeIn(title))
+ self.wait(2)
+ self.play(
+ math.animate.shift(2*UP).set_opacity(0.5),
+ Write(math_with_answer)
+ )
+ conclusion = Paragraph("As you can see,\nYou add each component individually").to_edge(DOWN)
+ self.play(Write(conclusion))
+ self.wait(2)
+ self.play(Unwrite(math), Unwrite(math_with_answer), Unwrite(conclusion), Unwrite(title))
+
+ def show_vector_addition(self) -> None:
+ title = Text("Now let's take a look at it geometrically")
+ self.play(Write(title))
+ self.wait(2)
+ self.play(Unwrite(title))
+
+ plane = NumberPlane()
+
+ sum_point = (2, -1, 0)
+
+ v1 = VectorGroup(
+ ORIGIN,
+ (2, 2, 0),
+ r"\boldsymbol{\vec{v}_1}",
+ RED,
+ direction=UP,
+ plane=plane
+ )
+
+ v2 = VectorGroup(
+ ORIGIN,
+ (0, -3, 0),
+ r"\boldsymbol{\vec{v}_2}",
+ YELLOW,
+ direction=LEFT,
+ plane=plane
+ )
+
+ v1moved = VectorGroup(
+ (0, -3, 0),
+ sum_point,
+ r"\boldsymbol{\vec{v}_1}",
+ v1.vector.get_color(),
+ plane=plane
+ )
+
+ v2moved = VectorGroup(
+ (2, 2, 0),
+ sum_point,
+ r"\boldsymbol{\vec{v}_2}",
+ v2.vector.get_color(),
+ plane=plane
+ )
+
+ sum_vec = VectorGroup(
+ ORIGIN,
+ sum_point,
+ r"\boldsymbol{\vec{v}_1}+\boldsymbol{\vec{v}_2}",
+ ORANGE,
+ direction=DOWN,
+ plane=plane
+ )
+
+ self.play(Create(plane), Create(v1))
+ self.wait(0.5)
+ self.play(Create(v2))
+ self.wait()
+
+ # animate movement of vectors
+ self.play(
+ Succession(
+ ReplacementTransform(v1.copy(), v1moved),
+ ReplacementTransform(v2.copy(), v2moved)
+ )
+ )
+ self.wait()
+ # draw sum vector
+ self.play(Create(sum_vec))
+ self.wait()
+ self.play(*[
+ Uncreate(x)
+ for x in (
+ plane,
+ v1,
+ v2,
+ v1moved,
+ v2moved,
+ sum_vec
+ )
+ ])
diff --git a/docs/source/conf.py b/docs/source/conf.py
index a4a092441d..f8bde72f7b 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -51,6 +51,7 @@
"sphinx.ext.inheritance_diagram",
"sphinxcontrib.programoutput",
"myst_parser",
+ "sphinx_togglebutton",
"sphinx_design",
"sphinx_reredirects",
]
diff --git a/docs/source/contributing/docs/admonitions.rst b/docs/source/contributing/docs/admonitions.rst
index c1b66bc258..8300afc817 100644
--- a/docs/source/contributing/docs/admonitions.rst
+++ b/docs/source/contributing/docs/admonitions.rst
@@ -85,4 +85,22 @@ Attention
.. attention::
A attention
+Dropdown
+~~~~~~~~~
+
+.. code-block:: rest
+
+ .. admonition:: A dropdown
+ :class: dropdown
+
+ A dropdown
+
+Make sure you leave a line between ":class:" and the text below, otherwise the dropdown won't render.
+
+.. admonition:: A dropdown
+ :class: dropdown
+
+ A dropdown
+
+
You can find further information about Admonitions here: https://pradyunsg.me/furo/reference/admonitions/
diff --git a/docs/source/tutorials_guides.rst b/docs/source/tutorials_guides.rst
index 05b318230b..276bb489ab 100644
--- a/docs/source/tutorials_guides.rst
+++ b/docs/source/tutorials_guides.rst
@@ -7,4 +7,5 @@ Tutorials & Guides
tutorials/index
guides/index
+ adventure/index
faq/index
diff --git a/poetry.lock b/poetry.lock
index 576d568faf..82e4824646 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,10 +1,9 @@
-# This file is automatically @generated by Poetry and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
[[package]]
name = "alabaster"
version = "0.7.16"
description = "A light, configurable Sphinx theme"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -16,7 +15,6 @@ files = [
name = "anyio"
version = "4.8.0"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
-category = "main"
optional = true
python-versions = ">=3.9"
files = [
@@ -39,7 +37,6 @@ trio = ["trio (>=0.26.1)"]
name = "appnope"
version = "0.1.4"
description = "Disable App Nap on macOS >= 10.9"
-category = "main"
optional = true
python-versions = ">=3.6"
files = [
@@ -51,7 +48,6 @@ files = [
name = "argon2-cffi"
version = "23.1.0"
description = "Argon2 for Python"
-category = "main"
optional = true
python-versions = ">=3.7"
files = [
@@ -72,7 +68,6 @@ typing = ["mypy"]
name = "argon2-cffi-bindings"
version = "21.2.0"
description = "Low-level CFFI bindings for Argon2"
-category = "main"
optional = true
python-versions = ">=3.6"
files = [
@@ -110,7 +105,6 @@ tests = ["pytest"]
name = "arrow"
version = "1.3.0"
description = "Better dates & times for Python"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -124,13 +118,12 @@ types-python-dateutil = ">=2.8.10"
[package.extras]
doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"]
-test = ["dateparser (>=1.0.0,<2.0.0)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (>=3.0.0,<4.0.0)"]
+test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"]
[[package]]
name = "asttokens"
version = "3.0.0"
description = "Annotate AST trees with source code positions"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -146,7 +139,6 @@ test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"]
name = "async-lru"
version = "2.0.4"
description = "Simple LRU cache for asyncio"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -161,7 +153,6 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""}
name = "attrs"
version = "24.3.0"
description = "Classes Without Boilerplate"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -181,7 +172,6 @@ tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
name = "audioop-lts"
version = "0.2.1"
description = "LTS Port of Python audioop"
-category = "main"
optional = false
python-versions = ">=3.13"
files = [
@@ -224,7 +214,6 @@ files = [
name = "av"
version = "13.1.0"
description = "Pythonic bindings for FFmpeg's libraries."
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -277,7 +266,6 @@ files = [
name = "babel"
version = "2.16.0"
description = "Internationalization utilities"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -292,7 +280,6 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"]
name = "beautifulsoup4"
version = "4.12.3"
description = "Screen-scraping library"
-category = "main"
optional = false
python-versions = ">=3.6.0"
files = [
@@ -314,7 +301,6 @@ lxml = ["lxml"]
name = "bleach"
version = "6.2.0"
description = "An easy safelist-based HTML-sanitizing tool."
-category = "main"
optional = true
python-versions = ">=3.9"
files = [
@@ -333,7 +319,6 @@ css = ["tinycss2 (>=1.1.0,<1.5)"]
name = "certifi"
version = "2024.12.14"
description = "Python package for providing Mozilla's CA Bundle."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -345,7 +330,6 @@ files = [
name = "cffi"
version = "1.17.1"
description = "Foreign Function Interface for Python calling C code."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -425,7 +409,6 @@ pycparser = "*"
name = "cfgv"
version = "3.4.0"
description = "Validate configuration and produce human readable error messages."
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -437,7 +420,6 @@ files = [
name = "charset-normalizer"
version = "3.4.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -539,7 +521,6 @@ files = [
name = "click"
version = "8.1.8"
description = "Composable command line interface toolkit"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -554,7 +535,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
name = "cloup"
version = "3.0.5"
description = "Adds features to Click: option groups, constraints, subcommand sections and help themes."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -569,7 +549,6 @@ click = ">=8.0,<9.0"
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
-category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
@@ -581,7 +560,6 @@ files = [
name = "comm"
version = "0.2.2"
description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -599,7 +577,6 @@ test = ["pytest"]
name = "contourpy"
version = "1.3.0"
description = "Python library for calculating contours of 2D quadrilateral grids"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -684,7 +661,6 @@ test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist"
name = "coverage"
version = "7.6.10"
description = "Code coverage measurement for Python"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -762,7 +738,6 @@ toml = ["tomli"]
name = "cryptography"
version = "43.0.3"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -812,7 +787,6 @@ test-randomorder = ["pytest-randomly"]
name = "cycler"
version = "0.12.1"
description = "Composable style cycles"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -828,7 +802,6 @@ tests = ["pytest", "pytest-cov", "pytest-xdist"]
name = "cython"
version = "3.0.11"
description = "The Cython compiler for writing C extensions in the Python language."
-category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
files = [
@@ -904,7 +877,6 @@ files = [
name = "dearpygui"
version = "2.0.0"
description = "DearPyGui: A simple Python GUI Toolkit"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -936,7 +908,6 @@ files = [
name = "debugpy"
version = "1.8.12"
description = "An implementation of the Debug Adapter Protocol for Python"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -972,7 +943,6 @@ files = [
name = "decorator"
version = "5.1.1"
description = "Decorators for Humans"
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -984,7 +954,6 @@ files = [
name = "defusedxml"
version = "0.7.1"
description = "XML bomb protection for Python stdlib modules"
-category = "main"
optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
@@ -996,7 +965,6 @@ files = [
name = "deprecated"
version = "1.2.15"
description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
-category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
files = [
@@ -1014,7 +982,6 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "jinja2 (>=3.0.3,<3.1.0)", "
name = "distlib"
version = "0.3.9"
description = "Distribution utilities"
-category = "dev"
optional = false
python-versions = "*"
files = [
@@ -1026,7 +993,6 @@ files = [
name = "docutils"
version = "0.20.1"
description = "Docutils -- Python Documentation Utilities"
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -1038,7 +1004,6 @@ files = [
name = "exceptiongroup"
version = "1.2.2"
description = "Backport of PEP 654 (exception groups)"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1053,7 +1018,6 @@ test = ["pytest (>=6)"]
name = "execnet"
version = "2.1.1"
description = "execnet: rapid multi-Python deployment"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -1068,7 +1032,6 @@ testing = ["hatch", "pre-commit", "pytest", "tox"]
name = "executing"
version = "2.1.0"
description = "Get the currently executing AST node of a frame, and other information"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1083,7 +1046,6 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth
name = "fastjsonschema"
version = "2.21.1"
description = "Fastest Python implementation of JSON schema"
-category = "main"
optional = true
python-versions = "*"
files = [
@@ -1098,7 +1060,6 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc
name = "filelock"
version = "3.16.1"
description = "A platform independent file lock."
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -1115,7 +1076,6 @@ typing = ["typing-extensions (>=4.12.2)"]
name = "fonttools"
version = "4.55.3"
description = "Tools to manipulate font files"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -1189,7 +1149,6 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
name = "fqdn"
version = "1.4.0"
description = "Validate fully-qualified domain names compliant to RFC 1035 and the preferred form in RFC 3686 s. 2."
-category = "main"
optional = true
python-versions = "*"
files = [
@@ -1201,7 +1160,6 @@ files = [
name = "furo"
version = "2023.9.10"
description = "A clean customisable Sphinx documentation theme."
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -1219,7 +1177,6 @@ sphinx-basic-ng = "*"
name = "gitdb"
version = "4.0.12"
description = "Git Object Database"
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -1234,7 +1191,6 @@ smmap = ">=3.0.1,<6"
name = "gitpython"
version = "3.1.44"
description = "GitPython is a Python library used to interact with Git repositories"
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -1253,7 +1209,6 @@ test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit",
name = "glcontext"
version = "3.0.0"
description = "Portable Headless OpenGL Context"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1327,7 +1282,6 @@ files = [
name = "h11"
version = "0.14.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
-category = "main"
optional = true
python-versions = ">=3.7"
files = [
@@ -1339,7 +1293,6 @@ files = [
name = "httpcore"
version = "1.0.7"
description = "A minimal low-level HTTP client."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1354,14 +1307,13 @@ h11 = ">=0.13,<0.15"
[package.extras]
asyncio = ["anyio (>=4.0,<5.0)"]
http2 = ["h2 (>=3,<5)"]
-socks = ["socksio (>=1.0.0,<2.0.0)"]
+socks = ["socksio (==1.*)"]
trio = ["trio (>=0.22.0,<1.0)"]
[[package]]
name = "httpx"
version = "0.28.1"
description = "The next generation HTTP client."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1372,21 +1324,20 @@ files = [
[package.dependencies]
anyio = "*"
certifi = "*"
-httpcore = ">=1.0.0,<2.0.0"
+httpcore = "==1.*"
idna = "*"
[package.extras]
brotli = ["brotli", "brotlicffi"]
-cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"]
+cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
http2 = ["h2 (>=3,<5)"]
-socks = ["socksio (>=1.0.0,<2.0.0)"]
+socks = ["socksio (==1.*)"]
zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "identify"
version = "2.6.5"
description = "File identification library for Python"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -1401,7 +1352,6 @@ license = ["ukkonen"]
name = "idna"
version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -1416,7 +1366,6 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2
name = "imagesize"
version = "1.4.1"
description = "Getting image size from png/jpeg/jpeg2000/gif file"
-category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
@@ -1428,7 +1377,6 @@ files = [
name = "importlib-metadata"
version = "8.5.0"
description = "Read metadata from Python packages"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1452,7 +1400,6 @@ type = ["pytest-mypy"]
name = "importlib-resources"
version = "6.5.2"
description = "Read resources from Python packages"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -1475,7 +1422,6 @@ type = ["pytest-mypy"]
name = "iniconfig"
version = "2.0.0"
description = "brain-dead simple config-ini parsing"
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -1487,7 +1433,6 @@ files = [
name = "ipykernel"
version = "6.29.5"
description = "IPython Kernel for Jupyter"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1501,7 +1446,7 @@ comm = ">=0.1.1"
debugpy = ">=1.6.5"
ipython = ">=7.23.1"
jupyter-client = ">=6.1.12"
-jupyter-core = ">=4.12,<5.0.0 || >=5.1.0"
+jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0"
matplotlib-inline = ">=0.1"
nest-asyncio = "*"
packaging = "*"
@@ -1521,7 +1466,6 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio
name = "ipython"
version = "8.18.1"
description = "IPython: Productive Interactive Computing"
-category = "main"
optional = true
python-versions = ">=3.9"
files = [
@@ -1559,7 +1503,6 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pa
name = "isoduration"
version = "20.11.0"
description = "Operations with ISO 8601 durations"
-category = "main"
optional = true
python-versions = ">=3.7"
files = [
@@ -1574,7 +1517,6 @@ arrow = ">=0.15.0"
name = "isort"
version = "5.13.2"
description = "A Python utility / library to sort Python imports."
-category = "dev"
optional = false
python-versions = ">=3.8.0"
files = [
@@ -1589,7 +1531,6 @@ colors = ["colorama (>=0.4.6)"]
name = "isosurfaces"
version = "0.1.2"
description = "Construct isolines/isosurfaces over a 2D/3D scalar field defined by a function (not a uniform grid)"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1604,7 +1545,6 @@ numpy = "*"
name = "jedi"
version = "0.19.2"
description = "An autocompletion tool for Python that can be used for text editors."
-category = "main"
optional = true
python-versions = ">=3.6"
files = [
@@ -1624,7 +1564,6 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"]
name = "jinja2"
version = "3.1.5"
description = "A very fast and expressive template engine."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1642,7 +1581,6 @@ i18n = ["Babel (>=2.7)"]
name = "json5"
version = "0.10.0"
description = "A Python implementation of the JSON5 data format."
-category = "main"
optional = true
python-versions = ">=3.8.0"
files = [
@@ -1657,7 +1595,6 @@ dev = ["build (==1.2.2.post1)", "coverage (==7.5.3)", "mypy (==1.13.0)", "pip (=
name = "jsonpointer"
version = "3.0.0"
description = "Identify specific nodes in a JSON document (RFC 6901)"
-category = "main"
optional = true
python-versions = ">=3.7"
files = [
@@ -1669,7 +1606,6 @@ files = [
name = "jsonschema"
version = "4.23.0"
description = "An implementation of JSON Schema validation for Python"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1699,7 +1635,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-
name = "jsonschema-specifications"
version = "2024.10.1"
description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
-category = "main"
optional = true
python-versions = ">=3.9"
files = [
@@ -1714,7 +1649,6 @@ referencing = ">=0.31.0"
name = "jupyter-client"
version = "8.6.3"
description = "Jupyter protocol implementation and client libraries"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1724,7 +1658,7 @@ files = [
[package.dependencies]
importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""}
-jupyter-core = ">=4.12,<5.0.0 || >=5.1.0"
+jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0"
python-dateutil = ">=2.8.2"
pyzmq = ">=23.0"
tornado = ">=6.2"
@@ -1738,7 +1672,6 @@ test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pyt
name = "jupyter-core"
version = "5.7.2"
description = "Jupyter core package. A base package on which Jupyter projects rely."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1759,7 +1692,6 @@ test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"
name = "jupyter-events"
version = "0.11.0"
description = "Jupyter Event System library"
-category = "main"
optional = true
python-versions = ">=3.9"
files = [
@@ -1785,7 +1717,6 @@ test = ["click", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.19.0)", "p
name = "jupyter-lsp"
version = "2.2.5"
description = "Multi-Language Server WebSocket proxy for Jupyter Notebook/Lab server"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1801,7 +1732,6 @@ jupyter-server = ">=1.1.2"
name = "jupyter-server"
version = "2.15.0"
description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications."
-category = "main"
optional = true
python-versions = ">=3.9"
files = [
@@ -1814,7 +1744,7 @@ anyio = ">=3.1.0"
argon2-cffi = ">=21.1"
jinja2 = ">=3.0.3"
jupyter-client = ">=7.4.4"
-jupyter-core = ">=4.12,<5.0.0 || >=5.1.0"
+jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0"
jupyter-events = ">=0.11.0"
jupyter-server-terminals = ">=0.4.4"
nbconvert = ">=6.4.4"
@@ -1838,7 +1768,6 @@ test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0,<9)", "pytest-console
name = "jupyter-server-terminals"
version = "0.5.3"
description = "A Jupyter Server Extension Providing Terminals."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1858,7 +1787,6 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (>
name = "jupyterlab"
version = "4.3.4"
description = "JupyterLab computational environment"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1894,7 +1822,6 @@ upgrade-extension = ["copier (>=9,<10)", "jinja2-time (<0.3)", "pydantic (<3.0)"
name = "jupyterlab-pygments"
version = "0.3.0"
description = "Pygments theme using JupyterLab CSS variables"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1906,7 +1833,6 @@ files = [
name = "jupyterlab-server"
version = "2.27.3"
description = "A set of server components for JupyterLab and JupyterLab like applications."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -1933,7 +1859,6 @@ test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-v
name = "kiwisolver"
version = "1.4.7"
description = "A fast implementation of the Cassowary constraint solver"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -2057,7 +1982,6 @@ files = [
name = "manimpango"
version = "0.6.0"
description = "Bindings for Pango for using with Manim."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2088,7 +2012,6 @@ files = [
name = "mapbox-earcut"
version = "1.0.3"
description = "Python bindings for the mapbox earcut C++ polygon triangulation library"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -2140,7 +2063,6 @@ numpy = "*"
name = "markdown-it-py"
version = "3.0.0"
description = "Python port of markdown-it. Markdown parsing, done right!"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2165,7 +2087,6 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
name = "markupsafe"
version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -2236,7 +2157,6 @@ files = [
name = "matplotlib"
version = "3.9.4"
description = "Python plotting package"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -2302,7 +2222,6 @@ dev = ["meson-python (>=0.13.1,<0.17.0)", "numpy (>=1.25)", "pybind11 (>=2.6,!=2
name = "matplotlib-inline"
version = "0.1.7"
description = "Inline Matplotlib backend for Jupyter"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -2317,7 +2236,6 @@ traitlets = "*"
name = "mdit-py-plugins"
version = "0.4.2"
description = "Collection of plugins for markdown-it-py"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -2337,7 +2255,6 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
name = "mdurl"
version = "0.1.2"
description = "Markdown URL utilities"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2349,7 +2266,6 @@ files = [
name = "mistune"
version = "3.1.0"
description = "A sane and fast Markdown parser with useful plugins and renderers"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -2364,7 +2280,6 @@ typing-extensions = {version = "*", markers = "python_version < \"3.11\""}
name = "moderngl"
version = "5.12.0"
description = "ModernGL: High performance rendering for Python 3"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2429,7 +2344,6 @@ headless = ["glcontext (>=3.0.0)"]
name = "moderngl-window"
version = "3.1.1"
description = "A cross platform helper library for ModernGL making window creation and resource loading simple"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -2465,7 +2379,6 @@ trimesh = ["trimesh (>=3.2.6)"]
name = "myst-parser"
version = "2.0.0"
description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser,"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -2492,7 +2405,6 @@ testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4,
name = "nbclient"
version = "0.10.2"
description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor."
-category = "main"
optional = true
python-versions = ">=3.9.0"
files = [
@@ -2502,7 +2414,7 @@ files = [
[package.dependencies]
jupyter-client = ">=6.1.12"
-jupyter-core = ">=4.12,<5.0.0 || >=5.1.0"
+jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0"
nbformat = ">=5.1"
traitlets = ">=5.4"
@@ -2515,7 +2427,6 @@ test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=
name = "nbconvert"
version = "7.16.5"
description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -2553,7 +2464,6 @@ webpdf = ["playwright"]
name = "nbformat"
version = "5.10.4"
description = "The Jupyter Notebook format"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -2564,7 +2474,7 @@ files = [
[package.dependencies]
fastjsonschema = ">=2.15"
jsonschema = ">=2.6"
-jupyter-core = ">=4.12,<5.0.0 || >=5.1.0"
+jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0"
traitlets = ">=5.1"
[package.extras]
@@ -2575,7 +2485,6 @@ test = ["pep440", "pre-commit", "pytest", "testpath"]
name = "nest-asyncio"
version = "1.6.0"
description = "Patch asyncio to allow nested event loops"
-category = "main"
optional = true
python-versions = ">=3.5"
files = [
@@ -2587,7 +2496,6 @@ files = [
name = "networkx"
version = "3.2.1"
description = "Python package for creating and manipulating graphs and networks"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -2606,7 +2514,6 @@ test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"]
name = "nodeenv"
version = "1.9.1"
description = "Node.js virtual environment builder"
-category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
@@ -2618,7 +2525,6 @@ files = [
name = "notebook"
version = "7.3.2"
description = "Jupyter Notebook - A web-based notebook environment for interactive computing"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -2642,7 +2548,6 @@ test = ["importlib-resources (>=5.0)", "ipykernel", "jupyter-server[test] (>=2.4
name = "notebook-shim"
version = "0.2.4"
description = "A shim layer for notebook traits and config"
-category = "main"
optional = true
python-versions = ">=3.7"
files = [
@@ -2660,7 +2565,6 @@ test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync"
name = "numpy"
version = "2.0.2"
description = "Fundamental package for array computing in Python"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -2715,7 +2619,6 @@ files = [
name = "numpy"
version = "2.2.2"
description = "Fundamental package for array computing in Python"
-category = "main"
optional = false
python-versions = ">=3.10"
files = [
@@ -2780,7 +2683,6 @@ files = [
name = "overrides"
version = "7.7.0"
description = "A decorator to automatically detect mismatch when overriding a method."
-category = "main"
optional = true
python-versions = ">=3.6"
files = [
@@ -2792,7 +2694,6 @@ files = [
name = "packaging"
version = "24.2"
description = "Core utilities for Python packages"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2804,7 +2705,6 @@ files = [
name = "pandocfilters"
version = "1.5.1"
description = "Utilities for writing pandoc filters in python"
-category = "main"
optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
@@ -2816,7 +2716,6 @@ files = [
name = "parso"
version = "0.8.4"
description = "A Python Parser"
-category = "main"
optional = true
python-versions = ">=3.6"
files = [
@@ -2832,7 +2731,6 @@ testing = ["docopt", "pytest"]
name = "pexpect"
version = "4.9.0"
description = "Pexpect allows easy control of interactive console applications."
-category = "main"
optional = true
python-versions = "*"
files = [
@@ -2847,7 +2745,6 @@ ptyprocess = ">=0.5"
name = "pillow"
version = "11.1.0"
description = "Python Imaging Library (Fork)"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -2936,7 +2833,6 @@ xmp = ["defusedxml"]
name = "platformdirs"
version = "4.3.6"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2953,7 +2849,6 @@ type = ["mypy (>=1.11.2)"]
name = "pluggy"
version = "1.5.0"
description = "plugin and hook calling mechanisms for python"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -2969,7 +2864,6 @@ testing = ["pytest", "pytest-benchmark"]
name = "pre-commit"
version = "3.8.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -2988,7 +2882,6 @@ virtualenv = ">=20.10.0"
name = "prometheus-client"
version = "0.21.1"
description = "Python client for the Prometheus monitoring system."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -3001,14 +2894,13 @@ twisted = ["twisted"]
[[package]]
name = "prompt-toolkit"
-version = "3.0.48"
+version = "3.0.49"
description = "Library for building powerful interactive command lines in Python"
-category = "main"
optional = true
-python-versions = ">=3.7.0"
+python-versions = ">=3.8.0"
files = [
- {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"},
- {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"},
+ {file = "prompt_toolkit-3.0.49-py3-none-any.whl", hash = "sha256:03b25a442496d1aeabcb4b8b8e94563ac6a8eff56467837367206a733c61c2de"},
+ {file = "prompt_toolkit-3.0.49.tar.gz", hash = "sha256:372cfcbff483cd5fac6f7870d21face30f1e2f217c6906721616fb1be778774d"},
]
[package.dependencies]
@@ -3018,7 +2910,6 @@ wcwidth = "*"
name = "psutil"
version = "5.9.8"
description = "Cross-platform lib for process and system monitoring in Python."
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
files = [
@@ -3047,7 +2938,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
name = "psutil-wheels"
version = "5.8.0"
description = "Cross-platform lib for process and system monitoring in Python."
-category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
@@ -3073,7 +2963,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "unittest2", "wmi"]
name = "ptyprocess"
version = "0.7.0"
description = "Run a subprocess in a pseudo terminal"
-category = "main"
optional = true
python-versions = "*"
files = [
@@ -3085,7 +2974,6 @@ files = [
name = "pure-eval"
version = "0.2.3"
description = "Safely evaluate AST nodes without side effects"
-category = "main"
optional = true
python-versions = "*"
files = [
@@ -3100,7 +2988,6 @@ tests = ["pytest"]
name = "py"
version = "1.11.0"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
-category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
@@ -3112,7 +2999,6 @@ files = [
name = "pycairo"
version = "1.27.0"
description = "Python interface for cairo"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -3133,7 +3019,6 @@ files = [
name = "pycparser"
version = "2.22"
description = "C parser in Python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3145,7 +3030,6 @@ files = [
name = "pydub"
version = "0.25.1"
description = "Manipulate audio with an simple and easy high level interface"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -3157,7 +3041,6 @@ files = [
name = "pygithub"
version = "2.5.0"
description = "Use the full Github API v3"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -3175,21 +3058,19 @@ urllib3 = ">=1.26.0"
[[package]]
name = "pyglet"
-version = "2.1.0"
+version = "2.1.1"
description = "pyglet is a cross-platform games and multimedia package."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
- {file = "pyglet-2.1.0-py3-none-any.whl", hash = "sha256:ed2ff5b9eeacf845d019f9768b01c811ebe167372dcb699146e59da2c4666e0b"},
- {file = "pyglet-2.1.0.tar.gz", hash = "sha256:50c5a82203f1ffd56990d225315035b37aacba7510f8f65c4b10a7301be788c8"},
+ {file = "pyglet-2.1.1-py3-none-any.whl", hash = "sha256:30562bfe9971a9ebeb6bb826f2c0d1649dd3d41bc8109ecc103425621f54c802"},
+ {file = "pyglet-2.1.1.tar.gz", hash = "sha256:47f49890a00e9fefc4d0ea74dc5b9d6b9be1c5455bb5746b2df118012cfa3124"},
]
[[package]]
name = "pyglm"
version = "2.7.3"
description = "OpenGL Mathematics library for Python"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -3280,7 +3161,6 @@ files = [
name = "pygments"
version = "2.19.1"
description = "Pygments is a syntax highlighting package written in Python."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3295,7 +3175,6 @@ windows-terminal = ["colorama (>=0.4.6)"]
name = "pyjwt"
version = "2.10.1"
description = "JSON Web Token implementation in Python"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -3316,7 +3195,6 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
name = "pynacl"
version = "1.5.0"
description = "Python binding to the Networking and Cryptography (NaCl) library"
-category = "dev"
optional = false
python-versions = ">=3.6"
files = [
@@ -3343,7 +3221,6 @@ tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"]
name = "pyobjc-core"
version = "11.0"
description = "Python<->ObjC Interoperability Module"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3360,7 +3237,6 @@ files = [
name = "pyobjc-framework-cocoa"
version = "11.0"
description = "Wrappers for the Cocoa frameworks on macOS"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -3380,7 +3256,6 @@ pyobjc-core = ">=11.0"
name = "pyparsing"
version = "3.2.1"
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -3395,7 +3270,6 @@ diagrams = ["jinja2", "railroad-diagrams"]
name = "pytest"
version = "8.3.4"
description = "pytest: simple powerful testing with Python"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -3418,7 +3292,6 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments
name = "pytest-cov"
version = "4.1.0"
description = "Pytest plugin for measuring coverage."
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -3437,7 +3310,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale
name = "pytest-forked"
version = "1.6.0"
description = "run tests in isolated forked subprocesses"
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -3453,7 +3325,6 @@ pytest = ">=3.10"
name = "pytest-xdist"
version = "2.5.0"
description = "pytest xdist plugin for distributed testing and loop-on-failing modes"
-category = "dev"
optional = false
python-versions = ">=3.6"
files = [
@@ -3475,7 +3346,6 @@ testing = ["filelock"]
name = "python-dateutil"
version = "2.9.0.post0"
description = "Extensions to the standard Python datetime module"
-category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
files = [
@@ -3490,7 +3360,6 @@ six = ">=1.5"
name = "python-json-logger"
version = "3.2.1"
description = "JSON Log Formatter for the Python Logging Package"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -3508,7 +3377,6 @@ dev = ["backports.zoneinfo", "black", "build", "freezegun", "mdx_truly_sane_list
name = "pywin32"
version = "308"
description = "Python for Window Extensions"
-category = "main"
optional = true
python-versions = "*"
files = [
@@ -3536,7 +3404,6 @@ files = [
name = "pywinpty"
version = "2.0.14"
description = "Pseudo terminal support for Windows from Python."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -3552,7 +3419,6 @@ files = [
name = "pyyaml"
version = "6.0.2"
description = "YAML parser and emitter for Python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3615,7 +3481,6 @@ files = [
name = "pyzmq"
version = "26.2.0"
description = "Python bindings for 0MQ"
-category = "main"
optional = true
python-versions = ">=3.7"
files = [
@@ -3737,7 +3602,6 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""}
name = "referencing"
version = "0.36.1"
description = "JSON Referencing + Python"
-category = "main"
optional = true
python-versions = ">=3.9"
files = [
@@ -3754,7 +3618,6 @@ typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""}
name = "requests"
version = "2.32.3"
description = "Python HTTP for Humans."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3776,7 +3639,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
name = "rfc3339-validator"
version = "0.1.4"
description = "A pure python RFC3339 validator"
-category = "main"
optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
@@ -3791,7 +3653,6 @@ six = "*"
name = "rfc3986-validator"
version = "0.1.1"
description = "Pure python rfc3986 validator"
-category = "main"
optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
@@ -3803,7 +3664,6 @@ files = [
name = "rich"
version = "13.9.4"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
-category = "main"
optional = false
python-versions = ">=3.8.0"
files = [
@@ -3823,7 +3683,6 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
name = "rpds-py"
version = "0.22.3"
description = "Python bindings to Rust's persistent data structures (rpds)"
-category = "main"
optional = true
python-versions = ">=3.9"
files = [
@@ -3936,7 +3795,6 @@ files = [
name = "ruff"
version = "0.9.2"
description = "An extremely fast Python linter and code formatter, written in Rust."
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -3964,7 +3822,6 @@ files = [
name = "scipy"
version = "1.13.1"
description = "Fundamental algorithms for scientific computing in Python"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -4007,7 +3864,6 @@ test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "po
name = "scipy"
version = "1.15.1"
description = "Fundamental algorithms for scientific computing in Python"
-category = "main"
optional = false
python-versions = ">=3.10"
files = [
@@ -4065,7 +3921,6 @@ test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis
name = "screeninfo"
version = "0.7"
description = "Fetch location and size of physical screens."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -4080,7 +3935,6 @@ pyobjc-framework-Cocoa = {version = "*", markers = "sys_platform == \"darwin\""}
name = "send2trash"
version = "1.8.3"
description = "Send file to trash natively under Mac OS X, Windows and Linux"
-category = "main"
optional = true
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
files = [
@@ -4097,8 +3951,7 @@ win32 = ["pywin32"]
name = "setuptools"
version = "75.8.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
-category = "main"
-optional = true
+optional = false
python-versions = ">=3.9"
files = [
{file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"},
@@ -4112,13 +3965,12 @@ cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
enabler = ["pytest-enabler (>=2.2)"]
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"]
-type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.14.0,<1.15.0)", "pytest-mypy"]
+type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"]
[[package]]
name = "six"
version = "1.17.0"
description = "Python 2 and 3 compatibility utilities"
-category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
files = [
@@ -4130,7 +3982,6 @@ files = [
name = "skia-pathops"
version = "0.8.0.post2"
description = "Python access to operations on paths using the Skia library"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4189,7 +4040,6 @@ testing = ["coverage", "pytest", "pytest-randomly", "pytest-xdist"]
name = "smmap"
version = "5.0.2"
description = "A pure Python implementation of a sliding window memory map manager"
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -4201,7 +4051,6 @@ files = [
name = "sniffio"
version = "1.3.1"
description = "Sniff out which async library your code is running under"
-category = "main"
optional = true
python-versions = ">=3.7"
files = [
@@ -4213,7 +4062,6 @@ files = [
name = "snowballstemmer"
version = "2.2.0"
description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
-category = "dev"
optional = false
python-versions = "*"
files = [
@@ -4225,7 +4073,6 @@ files = [
name = "soupsieve"
version = "2.6"
description = "A modern CSS selector implementation for Beautiful Soup."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4237,7 +4084,6 @@ files = [
name = "sphinx"
version = "7.4.7"
description = "Python documentation generator"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -4274,7 +4120,6 @@ test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools
name = "sphinx-basic-ng"
version = "1.0.0b2"
description = "A modern skeleton for Sphinx themes."
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -4292,7 +4137,6 @@ docs = ["furo", "ipython", "myst-parser", "sphinx-copybutton", "sphinx-inline-ta
name = "sphinx-copybutton"
version = "0.5.2"
description = "Add a copy button to each of your code cells."
-category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -4311,7 +4155,6 @@ rtd = ["ipython", "myst-nb", "sphinx", "sphinx-book-theme", "sphinx-examples"]
name = "sphinx-design"
version = "0.6.1"
description = "A sphinx extension for designing beautiful, view size responsive web components."
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -4337,7 +4180,6 @@ theme-sbt = ["sphinx-book-theme (>=1.1,<2.0)"]
name = "sphinx-reredirects"
version = "0.1.5"
description = "Handles redirects for moved pages in Sphinx documentation projects"
-category = "dev"
optional = false
python-versions = ">=3.5"
files = [
@@ -4348,11 +4190,30 @@ files = [
[package.dependencies]
sphinx = ">=7.1"
+[[package]]
+name = "sphinx-togglebutton"
+version = "0.3.2"
+description = "Toggle page content and collapse admonitions in Sphinx."
+optional = false
+python-versions = "*"
+files = [
+ {file = "sphinx-togglebutton-0.3.2.tar.gz", hash = "sha256:ab0c8b366427b01e4c89802d5d078472c427fa6e9d12d521c34fa0442559dc7a"},
+ {file = "sphinx_togglebutton-0.3.2-py3-none-any.whl", hash = "sha256:9647ba7874b7d1e2d43413d8497153a85edc6ac95a3fea9a75ef9c1e08aaae2b"},
+]
+
+[package.dependencies]
+docutils = "*"
+setuptools = "*"
+sphinx = "*"
+wheel = "*"
+
+[package.extras]
+sphinx = ["matplotlib", "myst-nb", "numpy", "sphinx-book-theme", "sphinx-design", "sphinx-examples"]
+
[[package]]
name = "sphinxcontrib-applehelp"
version = "2.0.0"
description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -4369,7 +4230,6 @@ test = ["pytest"]
name = "sphinxcontrib-devhelp"
version = "2.0.0"
description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -4386,7 +4246,6 @@ test = ["pytest"]
name = "sphinxcontrib-htmlhelp"
version = "2.1.0"
description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -4403,7 +4262,6 @@ test = ["html5lib", "pytest"]
name = "sphinxcontrib-jsmath"
version = "1.0.1"
description = "A sphinx extension which renders display math in HTML via JavaScript"
-category = "dev"
optional = false
python-versions = ">=3.5"
files = [
@@ -4418,7 +4276,6 @@ test = ["flake8", "mypy", "pytest"]
name = "sphinxcontrib-programoutput"
version = "0.17"
description = "Sphinx extension to include program output"
-category = "dev"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
files = [
@@ -4433,7 +4290,6 @@ Sphinx = ">=1.7.0"
name = "sphinxcontrib-qthelp"
version = "2.0.0"
description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -4450,7 +4306,6 @@ test = ["defusedxml (>=0.7.1)", "pytest"]
name = "sphinxcontrib-serializinghtml"
version = "2.0.0"
description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)"
-category = "dev"
optional = false
python-versions = ">=3.9"
files = [
@@ -4467,7 +4322,6 @@ test = ["pytest"]
name = "sphinxext-opengraph"
version = "0.9.1"
description = "Sphinx Extension to enable OGP support"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -4482,7 +4336,6 @@ sphinx = ">=4.0"
name = "srt"
version = "3.5.3"
description = "A tiny library for parsing, modifying, and composing SRT files."
-category = "main"
optional = false
python-versions = ">=2.7"
files = [
@@ -4493,7 +4346,6 @@ files = [
name = "stack-data"
version = "0.6.3"
description = "Extract data from python stack frames and tracebacks for informative displays"
-category = "main"
optional = true
python-versions = "*"
files = [
@@ -4513,7 +4365,6 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
name = "svgelements"
version = "1.9.6"
description = "Svg Elements Parsing"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -4525,7 +4376,6 @@ files = [
name = "terminado"
version = "0.18.1"
description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -4547,7 +4397,6 @@ typing = ["mypy (>=1.6,<2.0)", "traitlets (>=5.11.1)"]
name = "tinycss2"
version = "1.4.0"
description = "A tiny CSS parser"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -4566,7 +4415,6 @@ test = ["pytest", "ruff"]
name = "tomli"
version = "2.2.1"
description = "A lil' TOML parser"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4608,7 +4456,6 @@ files = [
name = "tornado"
version = "6.4.2"
description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -4629,7 +4476,6 @@ files = [
name = "tqdm"
version = "4.67.1"
description = "Fast, Extensible Progress Meter"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -4651,7 +4497,6 @@ telegram = ["requests"]
name = "traitlets"
version = "5.14.3"
description = "Traitlets Python configuration system"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -4667,7 +4512,6 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,
name = "types-decorator"
version = "0.1.7"
description = "Typing stubs for decorator"
-category = "dev"
optional = false
python-versions = "*"
files = [
@@ -4679,7 +4523,6 @@ files = [
name = "types-docutils"
version = "0.21.0.20241128"
description = "Typing stubs for docutils"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -4691,7 +4534,6 @@ files = [
name = "types-pillow"
version = "10.2.0.20240822"
description = "Typing stubs for Pillow"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -4703,7 +4545,6 @@ files = [
name = "types-pygments"
version = "2.19.0.20250107"
description = "Typing stubs for Pygments"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -4719,7 +4560,6 @@ types-setuptools = "*"
name = "types-python-dateutil"
version = "2.9.0.20241206"
description = "Typing stubs for python-dateutil"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -4731,7 +4571,6 @@ files = [
name = "types-setuptools"
version = "75.8.0.20250110"
description = "Typing stubs for setuptools"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -4743,7 +4582,6 @@ files = [
name = "typing-extensions"
version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4755,7 +4593,6 @@ files = [
name = "uri-template"
version = "1.3.0"
description = "RFC 6570 URI Template Processor"
-category = "main"
optional = true
python-versions = ">=3.7"
files = [
@@ -4770,7 +4607,6 @@ dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake
name = "urllib3"
version = "2.3.0"
description = "HTTP library with thread-safe connection pooling, file post, and more."
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -4788,7 +4624,6 @@ zstd = ["zstandard (>=0.18.0)"]
name = "virtualenv"
version = "20.29.1"
description = "Virtual Python Environment builder"
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -4809,7 +4644,6 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess
name = "watchdog"
version = "6.0.0"
description = "Filesystem events monitoring"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -4852,7 +4686,6 @@ watchmedo = ["PyYAML (>=3.10)"]
name = "wcwidth"
version = "0.2.13"
description = "Measures the displayed width of unicode strings in a terminal"
-category = "main"
optional = true
python-versions = "*"
files = [
@@ -4864,7 +4697,6 @@ files = [
name = "webcolors"
version = "24.11.1"
description = "A library for working with the color formats defined by HTML and CSS."
-category = "main"
optional = true
python-versions = ">=3.9"
files = [
@@ -4876,7 +4708,6 @@ files = [
name = "webencodings"
version = "0.5.1"
description = "Character encoding aliases for legacy web content"
-category = "main"
optional = true
python-versions = "*"
files = [
@@ -4888,7 +4719,6 @@ files = [
name = "websocket-client"
version = "1.8.0"
description = "WebSocket client for Python with low level API options"
-category = "main"
optional = true
python-versions = ">=3.8"
files = [
@@ -4901,11 +4731,24 @@ docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx-rtd-theme (>=1.1.0)"]
optional = ["python-socks", "wsaccel"]
test = ["websockets"]
+[[package]]
+name = "wheel"
+version = "0.45.1"
+description = "A built-package format for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"},
+ {file = "wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729"},
+]
+
+[package.extras]
+test = ["pytest (>=6.0.0)", "setuptools (>=65)"]
+
[[package]]
name = "wrapt"
version = "1.17.2"
description = "Module for decorators, wrappers and monkey patching."
-category = "dev"
optional = false
python-versions = ">=3.8"
files = [
@@ -4994,7 +4837,6 @@ files = [
name = "zipp"
version = "3.21.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -5017,4 +4859,4 @@ jupyterlab = ["jupyterlab", "notebook"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.9"
-content-hash = "8be7f23224cbc3e1f01562c0a17e83deb11c7146862e332cd0d8f0dff54becde"
+content-hash = "6e501589f64dd263e44daa5c72e251ad8abc0cf1ce0bea8cbf667a316bb0d21f"
diff --git a/pyproject.toml b/pyproject.toml
index 9b2360f236..096c24d767 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -92,6 +92,7 @@ Sphinx = "^7.2.6"
sphinx-copybutton = "^0.5.2"
sphinxcontrib-programoutput = "^0.17"
sphinxext-opengraph = "^0.9.1"
+sphinx-togglebutton = "^0.3.2"
types-decorator = "^0.1.7"
types-Pillow = "^10.1.0.2"
types-Pygments = "^2.17.0.0"