├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md ├── dependabot.yml └── workflows │ └── python-package.yml ├── .gitignore ├── README.md ├── examples ├── data_science_example.py ├── data_science_plugin.py └── hello_world.py ├── manim_studio ├── __init__.py ├── __main__.py ├── api.py ├── input_widgets │ ├── __init__.py │ ├── color_picker.py │ └── range_slider.py ├── mobject_picker.py ├── preview.py ├── syntax_highlighting.py ├── utils.py └── window.py ├── poetry.lock ├── pyproject.toml └── tests ├── __init__.py └── test_startup.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [MathItYT] 4 | patreon: MathLike 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: Test Manim Studio 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ["3.9", "3.10", "3.11", "3.12"] 20 | 21 | steps: 22 | - uses: actions/checkout@v3 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v3 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install Ubuntu dependencies 28 | run: | 29 | sudo apt update 30 | sudo apt install -y build-essential python3-dev libcairo2-dev libpango1.0-dev ffmpeg texlive-full 31 | sudo apt-get install -y xvfb libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xinput0 libxcb-xfixes0 32 | sudo apt install -y xvfb x11-utils libxkbcommon-x11-0 33 | sudo apt-get install -y '^libxcb.*-dev' libx11-xcb-dev libglu1-mesa-dev libxrender-dev libxi-dev libxkbcommon-dev libxkbcommon-x11-dev 34 | sudo apt install -y python3-qtpy 35 | - name: Install Python dependencies 36 | run: | 37 | python -m pip install pytest 38 | python -m pip install . 39 | - name: Test with pytest 40 | env: 41 | QT_DEBUG_PLUGINS: 1 42 | QT_QPA_PLATFORM: xcb 43 | run: | 44 | sudo xvfb-run --auto-servernum --server-num=1 --server-args="-screen 1 1920x1080x24 -ac +extension GLX" `which pytest` 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | 162 | # Manim 163 | media/ 164 | *.mp4 165 | 166 | # Manim Studio 167 | *_generated.py 168 | 169 | # Makefile 170 | Makefile -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Manim Studio 2 | 3 | ![Manim Studio](https://raw.githubusercontent.com/MathItYT/manim-studio/main/logo.png) 4 | 5 | Manim Studio is a Manim plugin to live-preview animations rendered with Cairo, and also it's useful for many other things! 6 | 7 | ## Features 8 | - [x] Live preview Manim animations made with Cairo. 9 | - [x] Work with Manim Mobject using the GUI. 10 | - [x] Export to a Python file the code of the animation. 11 | - [x] A live cell to interactively insert code into the scene. 12 | - [x] Create animations with the GUI. 13 | - [ ] Create animations with AI. 14 | - [ ] Collaborate with other people in the same project. 15 | 16 | ## Requirements to install 17 | ### Install with `git` 18 | - Installed Python 3. 19 | - Installed Manim. 20 | - Installed PyQt6. 21 | - Installed Git. 22 | 23 | ### Install with `pip` 24 | `pip` installs all the requirements automatically, but you must have Python 3 installed. 25 | 26 | ## Steps to use 27 | The documentation is not available by the moment, but it will be soon. 28 | 29 | You can run Manim Studio in a new scene, but also in a scene that you've been working before with code. 30 | 31 | If you want to work in a completely new scene, you must run: 32 | 33 | ```console 34 | foo@bar:~$ manim-studio 35 | ``` 36 | 37 | If you want to work in a scene that you've been working before with code, 38 | you must run: 39 | 40 | ```console 41 | foo@bar:~$ manim-studio --file FILE --scene SCENE_CLASS_NAME 42 | ``` 43 | 44 | To save your progress, you must click on `Generate Python File` button. 45 | 46 | If you want to continue later, you must save your progress and 47 | run Manim Studio using the generated Python file and its respective 48 | scene class. 49 | 50 | You can also render a video by clicking `Render Video File`. 51 | 52 | ## Contributing 53 | If you want to contribute to Manim Studio, you can do it by forking the repository and making a pull request. You can also contribute by reporting bugs or suggesting new features. 54 | 55 | ## License 56 | This project is licensed under the MIT License. See [LICENSE](LICENSE) for more details. 57 | -------------------------------------------------------------------------------- /examples/data_science_example.py: -------------------------------------------------------------------------------- 1 | from manim import * 2 | from manim_studio import hold_on 3 | import random 4 | 5 | 6 | def noise(k: int, noise_factor: float = 0.5): 7 | return k+((random.random()*2)-1)*noise_factor 8 | 9 | 10 | class DataScienceExample(Scene): 11 | def construct(self): 12 | self.plane = NumberPlane( 13 | x_range=[-10, 10, 1], 14 | y_range=[-10, 10, 1], 15 | x_length=6, 16 | y_length=6, 17 | background_line_style={"stroke_opacity": 0.5, "stroke_color": TEAL} 18 | ) 19 | labels = self.plane.get_axis_labels("X", "Y") 20 | self.play(Create(self.plane), DrawBorderThenFill(labels)) 21 | self.n = 100 22 | self.noise_factor = 0.5 23 | self.generate_points(100, first_time=True) 24 | 25 | hold_on(self, locals()) 26 | 27 | def generate_points(self, n: int, noise_factor: float = 0.5, first_time: bool = False): 28 | f = np.vectorize(lambda k: noise(k, noise_factor)) 29 | x = f(np.linspace(-10, 10, n)) 30 | y = f(np.linspace(-10, 10, n)) 31 | points = VGroup(*[Dot(self.plane.coords_to_point(i, j)) for i, j in zip(x, y)]) 32 | points.shuffle() 33 | if first_time: 34 | self.play(LaggedStartMap(lambda m: FadeIn(m, scale=0.5), points, run_time=1)) 35 | else: 36 | self.remove(*self.points) 37 | self.add(points) 38 | self.points = points 39 | 40 | def setup_deepness(self): 41 | self.deepness = 0 42 | -------------------------------------------------------------------------------- /examples/data_science_plugin.py: -------------------------------------------------------------------------------- 1 | from manim_studio import ManimStudioAPI 2 | from manim_studio.window import Window 3 | from manim_studio.input_widgets.range_slider import RangeSlider 4 | 5 | 6 | CODE = "self.generate_points(int(self.n), self.noise_factor)" 7 | 8 | 9 | def main(cls: type[ManimStudioAPI]): 10 | print("Hello from Data Science Plugin for Manim Studio!") 11 | 12 | 13 | def init_widgets(window: Window): 14 | n_slider = RangeSlider("n", 100, 1, 1000, 1, window.width()) 15 | n_slider.expression_editor.setPlainText(CODE) 16 | n_slider.expression_editor.setDisabled(True) 17 | n_slider.expression_selector.setDisabled(True) 18 | noise_factor_slider = RangeSlider("noise_factor", 0.5, 0, 1, 0.01, window.width()) 19 | noise_factor_slider.expression_editor.setPlainText(CODE) 20 | noise_factor_slider.expression_editor.setDisabled(True) 21 | noise_factor_slider.expression_selector.setDisabled(True) 22 | window.input_widgets_zone.widget().layout().addWidget(n_slider) 23 | window.input_widgets_zone.widget().layout().addWidget(noise_factor_slider) 24 | -------------------------------------------------------------------------------- /examples/hello_world.py: -------------------------------------------------------------------------------- 1 | from manim import * 2 | from manim_studio import hold_on 3 | 4 | 5 | class ExampleScene(Scene): 6 | def construct(self): 7 | self.text = Text("Hello, World!") 8 | self.play(Write(self.text)) 9 | hold_on(self, locals()) 10 | 11 | def setup_deepness(self): 12 | self.deepness = 0 13 | -------------------------------------------------------------------------------- /manim_studio/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import ManimStudioAPI, hold_on 2 | -------------------------------------------------------------------------------- /manim_studio/__main__.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from pathlib import Path 3 | from types import ModuleType 4 | from threading import Thread 5 | 6 | from PyQt6.QtWidgets import QApplication 7 | 8 | from manim import Scene 9 | from manim._config import config 10 | 11 | from .api import ManimStudioAPI 12 | from .utils import import_module_by_name_or_path, import_from_file 13 | from .window import Window 14 | 15 | 16 | def main(): 17 | parser = argparse.ArgumentParser() 18 | parser.add_argument("--file", help="The file to open") 19 | parser.add_argument("--scene", help="The scene to open") 20 | parser.add_argument("--plugins", nargs="*", help="The plugins to load") 21 | parser.add_argument("--timeout", type=float, 22 | help="The timeout of Manim Studio in seconds") 23 | parser.add_argument( 24 | "--consider_studio_time", 25 | action="store_true", 26 | help="Whether to consider Manim Studio time" 27 | ) 28 | args = parser.parse_args() 29 | 30 | if args.scene and not args.file: 31 | raise ValueError( 32 | "You must provide a file when providing a scene to use.") 33 | 34 | if args.consider_studio_time: 35 | ManimStudioAPI.consider_studio_time = True 36 | 37 | path_to_file = Path(args.file) if args.file else None 38 | 39 | module = import_from_file(path_to_file) if path_to_file else None 40 | 41 | scene_class: type[Scene] = getattr(module, args.scene) if module else Scene 42 | plugins = args.plugins or [] 43 | plugins: list[ModuleType] = [ 44 | import_module_by_name_or_path(plugin) 45 | for plugin in plugins 46 | ] 47 | config.write_to_movie = False 48 | 49 | app = QApplication([]) 50 | screen = app.primaryScreen() 51 | window_size = screen.size() 52 | window_size_as_tuple = (window_size.width(), window_size.height()) 53 | ManimStudioAPI.enabled = True 54 | scene = scene_class() 55 | ManimStudioAPI(scene, module, path_to_file, plugins, args.timeout) 56 | window = Window( 57 | window_size_as_tuple, 58 | ManimStudioAPI.scene, 59 | ) 60 | scene.code = None 61 | path_to_file = str(path_to_file) if path_to_file else None 62 | scene.setup_deepness() 63 | thread = Thread(target=scene.render, daemon=True) 64 | thread.start() 65 | window.showMaximized() 66 | app.exec() 67 | 68 | 69 | if __name__ == "__main__": 70 | main() 71 | -------------------------------------------------------------------------------- /manim_studio/api.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Union, Any 4 | from types import ModuleType 5 | from time import time 6 | 7 | import manim 8 | 9 | from PyQt6.QtCore import pyqtSignal, QObject 10 | from PyQt6.QtWidgets import QWidget 11 | 12 | 13 | def hold_on(scene: manim.Scene, locals_dict: dict[str, Any]): 14 | """Hold the scene until the user executes something on Manim Studio.""" 15 | if not ManimStudioAPI.enabled: 16 | return 17 | if ManimStudioAPI.scene.deepness > 0: 18 | ManimStudioAPI.scene.deepness -= 1 19 | return 20 | ManimStudioAPI.scope.update(locals_dict) 21 | if ManimStudioAPI.consider_studio_time: 22 | frames_waited = 0 23 | if scene.code: 24 | ManimStudioAPI.codes.append("") 25 | if ManimStudioAPI.timeout is not None: 26 | time_now = time() 27 | if ManimStudioAPI.time_running > ManimStudioAPI.timeout: 28 | ManimStudioAPI.signals_wrapper.close_window_signal.emit() 29 | return 30 | while scene.code is None: 31 | scene.wait(1 / scene.camera.frame_rate, frozen_frame=False) 32 | if ManimStudioAPI.consider_studio_time: 33 | frames_waited += 1 34 | if ManimStudioAPI.timeout is not None: 35 | ManimStudioAPI.time_running += time() - time_now 36 | time_now = time() 37 | if ManimStudioAPI.time_running > ManimStudioAPI.timeout: 38 | ManimStudioAPI.signals_wrapper.close_window_signal.emit() 39 | return 40 | if ManimStudioAPI.consider_studio_time: 41 | ManimStudioAPI.codes.append( 42 | f"self.wait({frames_waited / scene.camera.frame_rate})") 43 | ManimStudioAPI.execute(scene.code) 44 | hold_on(scene, {}) 45 | 46 | 47 | class SignalsWrapper(QObject): 48 | """A signal to print text in the GUI.""" 49 | print_signal = pyqtSignal(str) 50 | show_error_signal = pyqtSignal(Exception) 51 | close_window_signal = pyqtSignal() 52 | 53 | 54 | class ManimStudioAPI: 55 | """The API for Manim Studio""" 56 | enabled: bool = False 57 | supported_mobjects: dict[str, type[manim.Mobject]] = { 58 | "Circle": manim.Circle, 59 | "Regular Polygon": manim.RegularPolygon, 60 | "Line": manim.Line, 61 | "MathTex": manim.MathTex, 62 | "Text": manim.Text 63 | } 64 | supported_animations: dict[str, type[manim.Animation]] = { 65 | "Fade In": manim.FadeIn, 66 | "Fade Out": manim.FadeOut, 67 | "Grow From Center": manim.GrowFromCenter, 68 | "Shrink To Center": manim.ShrinkToCenter, 69 | "Draw Border Then Fill": manim.DrawBorderThenFill, 70 | "Create": manim.Create, 71 | "Uncreate": manim.Uncreate, 72 | "Write": manim.Write, 73 | "Transform": manim.Transform, 74 | "Replacement Transform": manim.ReplacementTransform 75 | } 76 | consider_studio_time: bool = False 77 | max_list_length: int = 50 78 | 79 | def __new__( 80 | cls, 81 | scene: manim.Scene, 82 | module: Union[ModuleType, None], 83 | path_to_file: Union[str, None], 84 | plugins: list[ModuleType], 85 | timeout: Union[int, None] 86 | ) -> ManimStudioAPI: 87 | if not cls.enabled: 88 | return 89 | cls.scene = scene 90 | cls.states_to_undo: list[dict[str, Any]] = [] 91 | cls.states_to_redo: list[dict[str, Any]] = [] 92 | cls.codes_to_redo: list[str] = [] 93 | cls.signals_wrapper = SignalsWrapper() 94 | cls.plugins: dict[str, ModuleType] = {} 95 | cls.scope = globals().copy() 96 | cls.scope["self"] = scene 97 | cls.update_scope_with_module(manim) 98 | cls.path_to_file = path_to_file 99 | cls.timeout = timeout 100 | cls.time_running = 0.0 101 | 102 | if type(scene) == manim.Scene: 103 | def new_construct(): 104 | hold_on(scene, {}) 105 | scene.construct = new_construct 106 | 107 | def setup_deepness(): 108 | scene.deepness = 0 109 | scene.setup_deepness = setup_deepness 110 | 111 | if module is not None: 112 | cls.update_scope_with_module(module) 113 | 114 | for plugin in plugins: 115 | cls.add_plugin(plugin) 116 | 117 | cls.codes = [] 118 | 119 | return super().__new__(cls) 120 | 121 | @classmethod 122 | def print(cls, *args): 123 | """Print the given arguments in the GUI.""" 124 | if cls.enabled: 125 | cls.signals_wrapper.print_signal.emit( 126 | " ".join(map(str, args))) 127 | print(*args) 128 | 129 | @classmethod 130 | def execute(cls, code: str): 131 | """Execute the given code in the scope of the scene. 132 | 133 | Warning 134 | ------- 135 | The code is executed directly. This means that it can be dangerous to 136 | use this method with untrusted code. Use it at your own risk. 137 | """ 138 | cls.scene.code = None 139 | state = cls.scene.__dict__.copy() 140 | try: 141 | exec(code, cls.scope) 142 | except Exception as e: 143 | cls.scene.__dict__ = state 144 | cls.signals_wrapper.show_error_signal.emit(e) 145 | else: 146 | cls.codes.append(code) 147 | cls.states_to_undo.append(state) 148 | cls.states_to_redo.clear() 149 | 150 | @classmethod 151 | def undo(cls): 152 | """Undo the last change in the scene.""" 153 | if len(cls.states_to_undo) == 0: 154 | return 155 | cls.states_to_redo.append(cls.scene.__dict__.copy()) 156 | cls.scene.__dict__ = cls.states_to_undo.pop() 157 | cls.codes_to_redo.append(cls.codes.pop()) 158 | cls.codes_to_redo.append(cls.codes.pop()) 159 | if len(cls.states_to_redo) == cls.max_list_length: 160 | cls.states_to_redo.pop(0) 161 | 162 | @classmethod 163 | def redo(cls): 164 | """Redo the last change in the scene.""" 165 | if len(cls.states_to_redo) == 0: 166 | return 167 | cls.states_to_undo.append(cls.scene.__dict__.copy()) 168 | cls.scene.__dict__ = cls.states_to_redo.pop() 169 | cls.codes.append(cls.codes_to_redo.pop()) 170 | cls.codes.append(cls.codes_to_redo.pop()) 171 | if len(cls.states_to_undo) == cls.max_list_length: 172 | cls.states_to_undo.pop(0) 173 | 174 | @classmethod 175 | def update_scope_with_module(cls, module: ModuleType): 176 | """Update the scope of the scene with the given module. 177 | It is useful to add new variables or functions that you want to use. 178 | """ 179 | cls.scope.update(module.__dict__) 180 | 181 | @classmethod 182 | def is_in_scope(cls, name: str): 183 | """Return whether the given name is in the scope of the scene.""" 184 | return name in cls.scope 185 | 186 | @classmethod 187 | def add_plugin( 188 | cls, 189 | plugin: ModuleType 190 | ): 191 | """Add a plugin to Manim Studio application. 192 | 193 | Parameters 194 | ---------- 195 | plugin : ModuleType 196 | The module of the plugin to add. It must contain a :code:`main` function 197 | that will be called with the API as the only argument.""" 198 | if not hasattr(plugin, "main"): 199 | raise ValueError("The plugin must have a 'main' function") 200 | if not callable(plugin.main): 201 | raise ValueError( 202 | "The 'main' function of the plugin must be callable") 203 | if plugin.main.__code__.co_argcount != 1: 204 | raise ValueError( 205 | "The 'main' function of the plugin must take exactly one argument") 206 | cls.plugins[plugin.__name__] = plugin 207 | 208 | @classmethod 209 | def run_plugin( 210 | cls, 211 | plugin_name: str 212 | ): 213 | """Run the plugin with the given name.""" 214 | if plugin_name not in cls.plugins: 215 | raise ValueError(f"The plugin '{plugin_name}' does not exist") 216 | cls.plugins[plugin_name].main(cls) 217 | 218 | @classmethod 219 | def get_all_code(cls): 220 | """Return all the code executed in the application.""" 221 | return "\n".join(cls.codes) 222 | -------------------------------------------------------------------------------- /manim_studio/input_widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MathItYT/manim-studio/fcd4496a64255a8dd6e91303d1000e9781ba6957/manim_studio/input_widgets/__init__.py -------------------------------------------------------------------------------- /manim_studio/input_widgets/color_picker.py: -------------------------------------------------------------------------------- 1 | from PyQt6.QtWidgets import ( 2 | QColorDialog, 3 | QGroupBox, 4 | QLabel, 5 | QVBoxLayout, 6 | QComboBox, 7 | QPlainTextEdit, 8 | QMessageBox 9 | ) 10 | from PyQt6.QtGui import QColor 11 | 12 | from manim import VMobject, Mobject 13 | 14 | from ..api import ManimStudioAPI 15 | from ..mobject_picker import MobjectPicker 16 | from ..utils import make_snake_case 17 | 18 | 19 | class ColorPicker(QGroupBox): 20 | def __init__(self, name: str, window_width: int, *args, **kwargs): 21 | super().__init__(*args, **kwargs) 22 | self.name = name 23 | self.window_width = window_width 24 | layout = QVBoxLayout() 25 | self.setLayout(layout) 26 | self.label = QLabel(f"{name}: RGBA(255, 255, 255, 255)") 27 | layout.addWidget(self.label) 28 | 29 | self.color_dialog = QColorDialog() 30 | self.color_dialog.currentColorChanged.connect(self.execute_expression) 31 | self.color_dialog.setOption( 32 | QColorDialog.ColorDialogOption.ShowAlphaChannel, True) 33 | self.color_dialog.setOption( 34 | QColorDialog.ColorDialogOption.NoButtons, True) 35 | self.color_dialog.setOption( 36 | QColorDialog.ColorDialogOption.DontUseNativeDialog, True) 37 | layout.addWidget(self.color_dialog) 38 | 39 | expression_label = QLabel("Expression") 40 | layout.addWidget(expression_label) 41 | self.expression_selector = QComboBox() 42 | self.expression_selector.addItems([ 43 | "Set Fill Color", 44 | "Set Stroke Color", 45 | "Custom Expression" 46 | ]) 47 | self.expression_selector.setCurrentIndex(2) 48 | self.expression_selector.currentIndexChanged.connect( 49 | self.update_expression) 50 | self.expression_editor = QPlainTextEdit() 51 | self.expression_editor.setPlaceholderText( 52 | "Enter a valid Python expression") 53 | layout.addWidget(self.expression_selector) 54 | layout.addWidget(self.expression_editor) 55 | self.color_dialog.currentColorChanged.connect(self.execute_expression) 56 | self.color_dialog.setCurrentColor(QColor(255, 255, 255, 255)) 57 | 58 | def execute_expression(self, color: QColor): 59 | self.label.setText(f"{self.name}: RGBA({color.red()}, " 60 | f"{color.green()}, {color.blue()}, {color.alpha()})") 61 | expression = self.expression_editor.toPlainText() 62 | value = f"ManimColor(({color.redF()}, " \ 63 | f"{color.greenF()}, {color.blueF()}))" 64 | ManimStudioAPI.scene.code = f""" 65 | self.{make_snake_case(self.name)} = {value} 66 | self.{make_snake_case(self.name)}_opacity = {color.alphaF()} 67 | {expression} 68 | """.strip() 69 | 70 | def update_expression(self, index: int): 71 | if index == 2: 72 | self.expression_editor.setReadOnly(False) 73 | return 74 | self.expression_editor.setReadOnly(True) 75 | mobject_name = MobjectPicker( 76 | self.window_width, 77 | ManimStudioAPI.scene.camera, 78 | Mobject 79 | ).wait_for_selection() 80 | if mobject_name is None: 81 | QMessageBox.warning( 82 | self, 83 | "Invalid Input", 84 | "You must enter a valid mobject's name, " 85 | "the expression will not be updated" 86 | ) 87 | self.expression_editor.setReadOnly(False) 88 | self.expression_selector.setCurrentIndex(2) 89 | return 90 | mobject_name = mobject_name[0] 91 | if self.expression_selector.currentIndex() in range(2) and not isinstance(getattr(ManimStudioAPI.scene, mobject_name), VMobject): 92 | QMessageBox.warning( 93 | self, 94 | "Invalid Input", 95 | "The mobject's name must correspond to a VMobject with option" 96 | f"{self.expression_selector.currentText()}, " 97 | "the expression will not be updated" 98 | ) 99 | self.expression_editor.setReadOnly(False) 100 | self.expression_selector.setCurrentIndex(2) 101 | return 102 | self.expression_editor.setReadOnly(True) 103 | if self.expression_selector.currentIndex() == 0: 104 | self.expression_editor.setPlainText( 105 | f"self.{mobject_name}" 106 | f".set_fill(color=self.{make_snake_case(self.name)}, " 107 | f"opacity=self.{make_snake_case(self.name)}_opacity)" 108 | ) 109 | elif self.expression_selector.currentIndex() == 1: 110 | self.expression_editor.setPlainText( 111 | f"self.{mobject_name}" 112 | f".set_stroke(color=self.{make_snake_case(self.name)}, " 113 | f"opacity=self.{make_snake_case(self.name)}_opacity)" 114 | ) 115 | self.execute_expression(self.color_dialog.currentColor()) 116 | -------------------------------------------------------------------------------- /manim_studio/input_widgets/range_slider.py: -------------------------------------------------------------------------------- 1 | from PyQt6.QtWidgets import ( 2 | QSlider, 3 | QGroupBox, 4 | QLabel, 5 | QVBoxLayout, 6 | QHBoxLayout, 7 | QPlainTextEdit, 8 | QComboBox, 9 | QMessageBox 10 | ) 11 | from PyQt6.QtCore import pyqtSignal, Qt 12 | 13 | from manim import Mobject, VMobject 14 | 15 | from ..api import ManimStudioAPI 16 | from ..mobject_picker import MobjectPicker 17 | from ..utils import make_snake_case 18 | 19 | 20 | class DoubleSlider(QSlider): 21 | doubleValueChanged = pyqtSignal(float) 22 | 23 | def __init__(self, decimals: int = 3, *args, **kwargs): 24 | super().__init__(*args, **kwargs) 25 | self._multi = 10 ** decimals 26 | 27 | self.valueChanged.connect(self.emitDoubleValueChanged) 28 | 29 | def emitDoubleValueChanged(self): 30 | value = float(super().value())/self._multi 31 | self.doubleValueChanged.emit(value) 32 | 33 | def value(self) -> float: 34 | return float(super().value()) / self._multi 35 | 36 | def setMinimum(self, value: float): 37 | return super().setMinimum(int(value * self._multi)) 38 | 39 | def setMaximum(self, value: float): 40 | return super().setMaximum(int(value * self._multi)) 41 | 42 | def setSingleStep(self, value: float): 43 | return super().setSingleStep(int(value * self._multi)) 44 | 45 | def singleStep(self) -> float: 46 | return float(super().singleStep()) / self._multi 47 | 48 | def setValue(self, value: float): 49 | super().setValue(int(value * self._multi)) 50 | 51 | 52 | class RangeSlider(QGroupBox): 53 | def __init__( 54 | self, 55 | name: str, 56 | value: float, 57 | min_val: float, 58 | max_val: float, 59 | single_step: float, 60 | window_width: int, 61 | *args, 62 | **kwargs 63 | ): 64 | super().__init__(*args, **kwargs) 65 | self.name = name 66 | self.window_width = window_width 67 | 68 | step = single_step 69 | decimals = 0 70 | while step < 1: 71 | step *= 10 72 | decimals += 1 73 | 74 | self.slider = DoubleSlider(decimals=decimals) 75 | self.slider.setOrientation(Qt.Orientation.Horizontal) 76 | 77 | self.min_label = QLabel(str(min_val)) 78 | self.max_label = QLabel(str(max_val)) 79 | self.min_val = min_val 80 | self.max_val = max_val 81 | 82 | self.slider.setMinimum(min_val) 83 | self.slider.setMaximum(max_val) 84 | self.slider.setSingleStep(single_step) 85 | self.slider.setValue(value) 86 | 87 | layout = QVBoxLayout() 88 | self.setLayout(layout) 89 | self.label = QLabel(f"{name}: {value}") 90 | layout.addWidget(self.label) 91 | slider_layout = QHBoxLayout() 92 | slider_layout.addWidget(self.min_label) 93 | slider_layout.addWidget(self.slider) 94 | slider_layout.addWidget(self.max_label) 95 | layout.addLayout(slider_layout) 96 | 97 | expression_label = QLabel("Expression") 98 | layout.addWidget(expression_label) 99 | self.expression_selector = QComboBox() 100 | self.expression_selector.addItems([ 101 | "Set Stroke Width", 102 | "Set Fill Opacity", 103 | "Set Stroke Opacity", 104 | "Set Height", 105 | "Set Width", 106 | "Custom Expression" 107 | ]) 108 | self.expression_selector.setCurrentIndex(5) 109 | self.expression_selector.currentIndexChanged.connect( 110 | self.update_expression) 111 | self.expression_editor = QPlainTextEdit() 112 | self.expression_editor.setPlaceholderText( 113 | "Enter a valid Python expression") 114 | layout.addWidget(self.expression_selector) 115 | layout.addWidget(self.expression_editor) 116 | self.slider.doubleValueChanged.connect(self.execute_expression) 117 | 118 | def execute_expression(self, value: float): 119 | self.label.setText(f"{self.name}: {value}") 120 | expression = self.expression_editor.toPlainText() 121 | ManimStudioAPI.scene.code = f""" 122 | self.{make_snake_case(self.name)} = {value} 123 | {expression} 124 | """.strip() 125 | 126 | def update_expression(self): 127 | if self.expression_selector.currentIndex() == 5: 128 | self.expression_editor.setReadOnly(False) 129 | return 130 | self.expression_editor.setReadOnly(True) 131 | mobject_name = MobjectPicker( 132 | self.window_width, 133 | ManimStudioAPI.scene.camera, 134 | Mobject 135 | ).wait_for_selection() 136 | if mobject_name is None: 137 | QMessageBox.warning( 138 | self, 139 | "Invalid Input", 140 | "You must enter a valid mobject's name, " 141 | "the expression will not be updated" 142 | ) 143 | self.expression_editor.setReadOnly(False) 144 | self.expression_selector.setCurrentIndex(5) 145 | return 146 | mobject_name = mobject_name[0] 147 | if self.expression_selector.currentIndex() in range(3) and not isinstance(getattr(ManimStudioAPI.scene, mobject_name), VMobject): 148 | QMessageBox.warning( 149 | self, 150 | "Invalid Input", 151 | "The mobject's name must correspond to a VMobject with option" 152 | f"{self.expression_selector.currentText()}, " 153 | "the expression will not be updated" 154 | ) 155 | self.expression_editor.setReadOnly(False) 156 | self.expression_selector.setCurrentIndex(5) 157 | return 158 | self.expression_editor.setReadOnly(True) 159 | if self.expression_selector.currentIndex() == 0: 160 | self.expression_editor.setPlainText( 161 | f"self.{mobject_name}" 162 | f".set_stroke(width=self.{make_snake_case(self.name)})" 163 | ) 164 | elif self.expression_selector.currentIndex() == 1: 165 | self.expression_editor.setPlainText( 166 | f"self.{mobject_name}" 167 | f".set_fill(opacity=self.{make_snake_case(self.name)})" 168 | ) 169 | elif self.expression_selector.currentIndex() == 2: 170 | self.expression_editor.setPlainText( 171 | f"self.{mobject_name}" 172 | f".set_stroke(opacity=self.{make_snake_case(self.name)})" 173 | ) 174 | elif self.expression_selector.currentIndex() == 3: 175 | self.expression_editor.setPlainText( 176 | f"self.{mobject_name}" 177 | f".scale_to_fit_height(self.{make_snake_case(self.name)})" 178 | ) 179 | elif self.expression_selector.currentIndex() == 4: 180 | self.expression_editor.setPlainText( 181 | f"self.{mobject_name}" 182 | f".scale_to_fit_width(self.{make_snake_case(self.name)})" 183 | ) 184 | self.execute_expression(self.slider.value()) 185 | -------------------------------------------------------------------------------- /manim_studio/mobject_picker.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | from copy import copy 3 | 4 | from PyQt6.QtWidgets import QDialog, QGridLayout, QPushButton 5 | from PyQt6.QtGui import QIcon, QPixmap 6 | from PyQt6.QtCore import QSize 7 | 8 | from manim import Mobject, Camera 9 | 10 | from PIL.ImageQt import ImageQt 11 | 12 | from .api import ManimStudioAPI 13 | 14 | 15 | class MobjectPicker(QDialog): 16 | def __init__( 17 | self, 18 | window_width: int, 19 | camera: Camera, 20 | mobject_class: type[Mobject] 21 | ): 22 | super().__init__() 23 | self.setLayout(QGridLayout()) 24 | self.selected_mobject = None 25 | self.setWindowTitle("Mobject Picker") 26 | aspect_ratio = camera.frame_width / camera.frame_height 27 | 28 | self.mobjects_available = {k: v 29 | for k, v in ManimStudioAPI.scene.__dict__.items() 30 | if isinstance(v, mobject_class)} 31 | 32 | for i, (name, mobject) in enumerate(self.mobjects_available.items()): 33 | icon = QIcon(QPixmap.fromImage(ImageQt(mobject.get_image(Camera( 34 | frame_width=camera.frame_width, 35 | frame_height=camera.frame_height, 36 | background_color=camera.background_color, 37 | pixel_width=camera.pixel_width, 38 | pixel_height=camera.pixel_height 39 | ))))) 40 | button = QPushButton(icon, None) 41 | button.setIconSize( 42 | QSize(window_width // 3, int(window_width // 3 / aspect_ratio))) 43 | button.setFixedSize(window_width // 3, 44 | int(window_width // 3 / aspect_ratio)) 45 | self.layout().addWidget(button, i // 3, i % 3) 46 | button.clicked.connect(self.get_select_mobject_func(name)) 47 | 48 | def get_select_mobject_func(self, name: str): 49 | def select_mobject(): 50 | self.selected_mobject = name, self.mobjects_available[name] 51 | self.close() 52 | return select_mobject 53 | 54 | def wait_for_selection(self) -> Union[tuple[str, Mobject], None]: 55 | self.exec() 56 | return self.selected_mobject 57 | -------------------------------------------------------------------------------- /manim_studio/preview.py: -------------------------------------------------------------------------------- 1 | from PyQt6.QtWidgets import QLabel, QComboBox, QInputDialog, QMessageBox 2 | from PyQt6.QtGui import QMouseEvent 3 | 4 | from manim import ( 5 | Scene, 6 | Circle, 7 | RegularPolygon, 8 | Line, 9 | MathTex, 10 | Text, 11 | Mobject, 12 | DL, 13 | UR 14 | ) 15 | 16 | import numpy as np 17 | 18 | from .api import ManimStudioAPI 19 | from .utils import qt_coords_to_manim_coords, make_snake_case 20 | 21 | 22 | class Preview(QLabel): 23 | def __init__( 24 | self, 25 | window_size: tuple[int, int], 26 | mobject_picker_combobox: QComboBox, 27 | scene: Scene 28 | ): 29 | super().__init__() 30 | self.saved_state = None 31 | self.setting_radius = None 32 | self.setting_line_start = None 33 | self.setting_line_end = None 34 | self.mobject_to_put = None 35 | self.setting_mathtex_size = None 36 | self.mathtex_string = None 37 | self.setting_text_size = None 38 | self.text_string = None 39 | self.scene = scene 40 | self.mobject_picker_combobox = mobject_picker_combobox 41 | self.setMouseTracking(True) 42 | 43 | window_width, window_height = window_size 44 | max_width = window_width // 2 45 | max_height = window_height // 2 46 | pixel_width, pixel_height = scene.camera.pixel_width, scene.camera.pixel_height 47 | aspect_ratio = pixel_width / pixel_height 48 | 49 | if aspect_ratio > max_width / max_height: 50 | width = max_width 51 | height = int(max_width / aspect_ratio) 52 | else: 53 | width = int(max_height * aspect_ratio) 54 | height = max_height 55 | 56 | self.setFixedSize(width, height) 57 | 58 | def add_mobject(self, mobject: Mobject): 59 | if isinstance(mobject, Circle): 60 | self.setting_radius = mobject 61 | return 62 | if isinstance(mobject, RegularPolygon): 63 | number_of_sides = QInputDialog.getInt( 64 | self, "Set number of sides", "Enter the number of sides (default: 6)")[0] 65 | number_of_sides = number_of_sides or 6 66 | side_length = QInputDialog.getDouble( 67 | self, "Set side length", "Enter the side length (default: 1)")[0] 68 | side_length = side_length or 1 69 | # Using radius formula given the side length and number of sides 70 | radius = side_length / (2 * np.sin(np.pi / number_of_sides)) 71 | mobject = RegularPolygon( 72 | number_of_sides, radius=radius).move_to(mobject.get_center()) 73 | name = QInputDialog.getText( 74 | self, "Set name", "Enter the mobject's name (default: reg_poly)")[0] 75 | name = make_snake_case(name) or "reg_poly" 76 | self.scene.__dict__ = self.saved_state 77 | self.saved_state = None 78 | ManimStudioAPI.scene.code = f""" 79 | self.{name} = RegularPolygon({number_of_sides}, radius={radius}).move_to(RIGHT*{mobject.get_x()} + UP*{mobject.get_y()}) 80 | self.add(self.{name}) 81 | """.strip() 82 | self.mobject_picker_combobox.setDisabled(False) 83 | return 84 | if isinstance(mobject, Line): 85 | self.setting_line_start = mobject 86 | return 87 | if isinstance(mobject, MathTex): 88 | center = mobject.get_center() 89 | error = True 90 | while error: 91 | try: 92 | text = QInputDialog.getText( 93 | self, "Set text", "Enter the text (default: x^2)")[0] 94 | text = text or "x^2" 95 | mobject.become(MathTex(text).move_to(center)) 96 | except (ValueError, RuntimeError): 97 | QMessageBox.critical( 98 | self, "Error", "Invalid LaTeX code, try again") 99 | else: 100 | error = False 101 | QMessageBox.information( 102 | self, "Info", "LaTeX rendered successfully") 103 | self.setting_mathtex_size = mobject 104 | self.mathtex_string = text 105 | return 106 | if isinstance(mobject, Text): 107 | center = mobject.get_center() 108 | text = QInputDialog.getText( 109 | self, "Set text", "Enter the text (default: T)")[0] 110 | text = text or "T" 111 | mobject.become(Text(text).move_to(center)) 112 | self.setting_text_size = mobject 113 | self.text_string = text 114 | return 115 | 116 | def mouseMoveEvent(self, a0: QMouseEvent) -> None: 117 | super().mouseMoveEvent(a0) 118 | if ( 119 | not self.mobject_to_put 120 | and not self.setting_radius 121 | and not self.setting_line_start 122 | and not self.setting_line_end 123 | and not self.setting_mathtex_size 124 | and not self.setting_text_size 125 | ): 126 | return 127 | qt_coords = a0.globalPosition() 128 | frame_x, frame_y = qt_coords_to_manim_coords( 129 | self.scene, 130 | qt_coords.x(), 131 | qt_coords.y(), 132 | self.x(), 133 | self.y(), 134 | self.width(), 135 | self.height() 136 | ) 137 | frame_pos = np.array([frame_x, frame_y, 0]) 138 | if self.setting_radius: 139 | center = self.setting_radius.get_center() 140 | radius = np.linalg.norm(frame_pos - center) 141 | self.setting_radius.become(Circle(radius=radius).move_to(center)) 142 | self.setting_radius.radius = radius 143 | return 144 | if self.setting_line_start: 145 | self.setting_line_start.put_start_and_end_on( 146 | frame_pos, self.setting_line_start.get_end()) 147 | return 148 | if self.setting_line_end: 149 | self.setting_line_end.put_start_and_end_on( 150 | self.setting_line_end.get_start(), frame_pos) 151 | return 152 | if self.setting_mathtex_size: 153 | center = self.setting_mathtex_size.get_center() 154 | self.setting_mathtex_size.scale_to_fit_height( 155 | 2 * abs(frame_y - self.setting_mathtex_size.get_y())) 156 | self.setting_mathtex_size.move_to(center) 157 | return 158 | if self.setting_text_size: 159 | center = self.setting_text_size.get_center() 160 | self.setting_text_size.scale_to_fit_height( 161 | 2 * abs(frame_y - self.setting_text_size.get_y())) 162 | self.setting_text_size.move_to(center) 163 | return 164 | if isinstance(self.mobject_to_put, type): 165 | self.saved_state = self.scene.__dict__.copy() 166 | if self.mobject_to_put == Circle: 167 | self.mobject_to_put = Circle() 168 | elif self.mobject_to_put == RegularPolygon: 169 | self.mobject_to_put = RegularPolygon(6) 170 | elif self.mobject_to_put == Line: 171 | self.mobject_to_put = Line(DL, UR) 172 | elif self.mobject_to_put == MathTex: 173 | self.mobject_to_put = MathTex("x^2") 174 | elif self.mobject_to_put == Text: 175 | self.mobject_to_put = Text("T") 176 | self.scene.add(self.mobject_to_put) 177 | self.mobject_to_put.move_to(frame_pos) 178 | 179 | def mousePressEvent(self, a0: QMouseEvent) -> None: 180 | super().mousePressEvent(a0) 181 | if ( 182 | not self.mobject_to_put 183 | and not self.setting_radius 184 | and not self.setting_line_start 185 | and not self.setting_line_end 186 | and not self.setting_mathtex_size 187 | and not self.setting_text_size 188 | ): 189 | return 190 | if self.setting_radius: 191 | circle = self.setting_radius 192 | self.setting_radius = None 193 | name = QInputDialog.getText( 194 | self, "Set name", "Enter the circle's name (default: circ)")[0] 195 | name = make_snake_case(name) or "circ" 196 | self.scene.__dict__ = self.saved_state 197 | self.saved_state = None 198 | ManimStudioAPI.scene.code = f""" 199 | self.{name} = Circle(radius={circle.radius}).move_to(RIGHT*{circle.get_x()} + UP*{circle.get_y()}) 200 | self.add(self.{name}) 201 | """.strip() 202 | self.mobject_picker_combobox.setDisabled(False) 203 | return 204 | if self.setting_line_start: 205 | self.setting_line_end = self.setting_line_start 206 | self.setting_line_start = None 207 | return 208 | if self.setting_line_end: 209 | line = self.setting_line_end 210 | self.setting_line_end = None 211 | name = QInputDialog.getText( 212 | self, "Set name", "Enter the line's name (default: line)")[0] 213 | name = make_snake_case(name) or "line" 214 | self.scene.__dict__ = self.saved_state 215 | self.saved_state = None 216 | start_x, start_y, _ = line.get_start() 217 | end_x, end_y, _ = line.get_end() 218 | ManimStudioAPI.scene.code = f""" 219 | self.{name} = Line(RIGHT*{start_x} + UP*{start_y}, RIGHT*{end_x} + UP*{end_y}) 220 | self.add(self.{name}) 221 | """.strip() 222 | self.mobject_picker_combobox.setDisabled(False) 223 | return 224 | if self.setting_mathtex_size: 225 | mathtex = self.setting_mathtex_size 226 | self.setting_mathtex_size = None 227 | text = QInputDialog.getText( 228 | self, "Set name", "Enter the MathTex's name (default: math_tex)")[0] 229 | text = make_snake_case(text) or "math_tex" 230 | self.scene.__dict__ = self.saved_state 231 | self.saved_state = None 232 | ManimStudioAPI.scene.code = f""" 233 | self.{text} = MathTex({repr(self.mathtex_string)}).scale_to_fit_height({mathtex.height}).move_to(RIGHT*{mathtex.get_x()} + UP*{mathtex.get_y()}) 234 | self.add(self.{text}) 235 | """.strip() 236 | self.mathtex_string = None 237 | self.mobject_picker_combobox.setDisabled(False) 238 | return 239 | if self.setting_text_size: 240 | text = self.setting_text_size 241 | self.setting_text_size = None 242 | name = QInputDialog.getText( 243 | self, "Set name", "Enter the Text's name (default: text)")[0] 244 | name = make_snake_case(name) or "text" 245 | self.scene.__dict__ = self.saved_state 246 | self.saved_state = None 247 | ManimStudioAPI.scene.code = f""" 248 | self.{name} = Text({repr(self.text_string)}).scale_to_fit_height({text.height}).move_to(RIGHT*{text.get_x()} + UP*{text.get_y()}) 249 | self.add(self.{name}) 250 | """.strip() 251 | self.text_string = None 252 | self.mobject_picker_combobox.setDisabled(False) 253 | return 254 | mobject = self.mobject_to_put 255 | self.mobject_to_put = None 256 | self.add_mobject(mobject) 257 | -------------------------------------------------------------------------------- /manim_studio/syntax_highlighting.py: -------------------------------------------------------------------------------- 1 | from PyQt6.QtGui import QSyntaxHighlighter, QTextCharFormat, QColor 2 | from PyQt6.QtCore import QRegularExpression 3 | 4 | 5 | class PythonHighlighter(QSyntaxHighlighter): 6 | """A syntax highlighter for Python code.""" 7 | 8 | def highlightBlock(self, text: str): 9 | self.light(text) 10 | self.highlight_numbers(text) 11 | self.highlight_keywords(text) 12 | self.highlight_strings(text) 13 | self.highlight_comments(text) 14 | 15 | def light(self, text: str): 16 | light_format = QTextCharFormat() 17 | light_format.setForeground(QColor(214, 214, 214)) 18 | light_format.setFontFamily("Consolas") 19 | light_format.setFontPointSize(16) 20 | light_format.setFontWeight(150) 21 | self.highlight(QRegularExpression(r"."), light_format, text) 22 | 23 | def highlight_numbers(self, text: str): 24 | number_format = QTextCharFormat() 25 | number_format.setForeground(QColor(180, 210, 115)) 26 | number_format.setFontFamily("Consolas") 27 | number_format.setFontPointSize(16) 28 | number_format.setFontWeight(150) 29 | self.highlight(QRegularExpression(r"\b[0-9]+\b"), number_format, text) 30 | 31 | def highlight_keywords(self, text: str): 32 | keyword_format = QTextCharFormat() 33 | keyword_format.setForeground(QColor(176, 82, 121)) 34 | keyword_format.setFontFamily("Consolas") 35 | keyword_format.setFontPointSize(16) 36 | keyword_format.setFontWeight(150) 37 | self.highlight(QRegularExpression( 38 | r"\b(" 39 | r"and|as|assert|async|await" 40 | r"|break|class|continue|def|" 41 | r"del|elif|else|except|finally|" 42 | r"for|from|global|if|import|in|" 43 | r"is|lambda|nonlocal|not|or" 44 | r"|pass|raise|return|try|while" 45 | r"|with|yield|self|super|True|" 46 | r"False|None|print|input|open|" 47 | r"range|len|list|dict|set|tuple|" 48 | r"int|float|str|bool|complex|" 49 | r"abs|all|any|ascii|bin|bool|" 50 | r"bytes|callable|chr|classmethod|" 51 | r"compile|complex|delattr|dict|" 52 | r"dir|divmod|enumerate|eval|" 53 | r"exec|filter|float|format|frozenset|" 54 | r"getattr|globals|hasattr|hash|" 55 | r"help|hex|id|input|int|isinstance|" 56 | r"issubclass|iter|len|list|locals|" 57 | r"map|max|memoryview|min|next|" 58 | r"object|oct|open|ord|pow|print|" 59 | r"property|range|repr|reversed|" 60 | r"round|set|setattr|slice|sorted|" 61 | r"staticmethod|str|sum|super|tuple|" 62 | r"type|vars|zip" 63 | r")\b" 64 | ), keyword_format, text) 65 | 66 | def highlight_strings(self, text: str): 67 | string_format = QTextCharFormat() 68 | string_format.setForeground(QColor(206, 145, 120)) 69 | string_format.setFontFamily("Consolas") 70 | string_format.setFontPointSize(16) 71 | string_format.setFontWeight(150) 72 | self.highlight(QRegularExpression(r"\".*\""), string_format, text) 73 | self.highlight(QRegularExpression(r"'.*'"), string_format, text) 74 | 75 | def highlight_comments(self, text: str): 76 | comment_format = QTextCharFormat() 77 | comment_format.setForeground(QColor(100, 100, 100)) 78 | comment_format.setFontFamily("Consolas") 79 | comment_format.setFontPointSize(16) 80 | comment_format.setFontWeight(150) 81 | self.highlight(QRegularExpression(r"#.*"), comment_format, text) 82 | 83 | def highlight(self, pattern: QRegularExpression, char_format: QTextCharFormat, text: str): 84 | match = pattern.match(text) 85 | while match.hasMatch(): 86 | start = match.capturedStart() 87 | length = match.capturedLength() 88 | self.setFormat(start, length, char_format) 89 | match = pattern.match(text, start + length) 90 | -------------------------------------------------------------------------------- /manim_studio/utils.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | from types import ModuleType 3 | from pathlib import Path 4 | import string 5 | 6 | from manim import Scene 7 | 8 | 9 | def import_module_by_name_or_path(name_or_path: str) -> ModuleType: 10 | """Import a module by name or path.""" 11 | if name_or_path.endswith(".py"): 12 | return import_from_file(Path(name_or_path)) 13 | return importlib.import_module(name_or_path) 14 | 15 | 16 | def import_from_file(path_to_file: Path) -> ModuleType: 17 | """Import a module from a file.""" 18 | spec = importlib.util.spec_from_file_location( 19 | path_to_file.stem, path_to_file) 20 | module = importlib.util.module_from_spec(spec) 21 | spec.loader.exec_module(module) 22 | return module 23 | 24 | 25 | def qt_coords_to_manim_coords( 26 | scene: Scene, 27 | x: float, 28 | y: float, 29 | label_x: int, 30 | label_y: int, 31 | label_width: int, 32 | label_height: int 33 | ) -> tuple[float, float]: 34 | """Convert pixel coordinates to Manim coordinates.""" 35 | x -= label_x 36 | y -= label_y 37 | x /= label_width 38 | y /= label_height 39 | x *= scene.camera.frame_width 40 | y *= scene.camera.frame_height 41 | x -= scene.camera.frame_width / 2 42 | y -= scene.camera.frame_height / 2 43 | y *= -1 44 | return x, y 45 | 46 | 47 | def make_snake_case(name: str) -> str: 48 | name = name.lstrip(string.digits + string.punctuation + string.whitespace) 49 | name = name.rstrip(string.punctuation + string.whitespace) 50 | name = name.split() 51 | name = "_".join(name) 52 | name = name.lower() 53 | return name 54 | 55 | 56 | def make_camel_case(text: str, default: str) -> str: 57 | text = text.lstrip(string.punctuation + string.whitespace + string.digits) 58 | text = text.rstrip(string.punctuation + string.whitespace) 59 | if text == "": 60 | return default 61 | text = text.split() 62 | text = "".join(word.capitalize() for word in text) 63 | return text 64 | -------------------------------------------------------------------------------- /manim_studio/window.py: -------------------------------------------------------------------------------- 1 | from copy import copy 2 | from pathlib import Path 3 | from subprocess import Popen 4 | import shutil 5 | 6 | from PyQt6.QtWidgets import ( 7 | QVBoxLayout, 8 | QHBoxLayout, 9 | QMainWindow, 10 | QWidget, 11 | QColorDialog, 12 | QTextEdit, 13 | QPushButton, 14 | QFileDialog, 15 | QInputDialog, 16 | QMessageBox, 17 | QComboBox, 18 | QMenu, 19 | QScrollArea, 20 | QLabel 21 | ) 22 | from PyQt6.QtCore import Qt 23 | from PyQt6.QtGui import QPixmap, QIcon, QAction, QColor 24 | 25 | from manim import ( 26 | Scene, 27 | Camera, 28 | Circle, 29 | RegularPolygon, 30 | Line, 31 | MathTex, 32 | Text, 33 | VMobject, 34 | Transform, 35 | ReplacementTransform, 36 | open_file, 37 | BLACK, 38 | DL, 39 | UR 40 | ) 41 | from manim._config import config 42 | 43 | from PIL.ImageQt import ImageQt 44 | from PIL import Image 45 | 46 | from .api import ManimStudioAPI 47 | from .input_widgets.range_slider import RangeSlider 48 | from .input_widgets.color_picker import ColorPicker 49 | from .mobject_picker import MobjectPicker 50 | from .preview import Preview 51 | from .syntax_highlighting import PythonHighlighter 52 | from .utils import make_camel_case 53 | 54 | 55 | FILE_CONTENT_TEMPLATE = """ 56 | from manim import * 57 | from manim_studio import * 58 | %s 59 | 60 | class %s(%s): 61 | def construct(self): 62 | super().construct() 63 | %s 64 | hold_on(self, locals()) 65 | 66 | def setup_deepness(self): 67 | super().setup_deepness() 68 | self.deepness += 1 69 | """.strip() 70 | 71 | 72 | CONTENT_IF_IMPORTED = """ 73 | from manim_studio.utils import import_from_file 74 | 75 | from pathlib import Path 76 | 77 | 78 | module = import_from_file(Path(%s)) 79 | """.lstrip() 80 | 81 | 82 | class Window(QMainWindow): 83 | """A window to preview the scene.""" 84 | 85 | def __init__( 86 | self, 87 | window_size: tuple[int, int], 88 | scene: Scene 89 | ): 90 | super().__init__(None) 91 | ManimStudioAPI.signals_wrapper.print_signal.connect( 92 | self.print_gui) 93 | ManimStudioAPI.signals_wrapper.show_error_signal.connect( 94 | self.show_error) 95 | ManimStudioAPI.signals_wrapper.close_window_signal.connect( 96 | self.close) 97 | self.setWindowTitle("Manim Studio") 98 | self.saved_file = None 99 | self.saved_scene_class_name = None 100 | self.scene = scene 101 | self.setMouseTracking(True) 102 | 103 | self.setCentralWidget(QWidget()) 104 | layout = QHBoxLayout() 105 | self.centralWidget().setLayout(layout) 106 | v_layout_1 = QVBoxLayout() 107 | layout.addLayout(v_layout_1) 108 | v_layout_2 = QVBoxLayout() 109 | layout.addLayout(v_layout_2) 110 | 111 | edit_menu = QMenu("Edit", self) 112 | undo_action = QAction("Undo", self) 113 | undo_action.triggered.connect(ManimStudioAPI.undo) 114 | undo_action.setShortcut("Ctrl+Z") 115 | edit_menu.addAction(undo_action) 116 | redo_action = QAction("Redo", self) 117 | redo_action.triggered.connect(ManimStudioAPI.redo) 118 | redo_action.setShortcut("Ctrl+Y") 119 | edit_menu.addAction(redo_action) 120 | set_fill_color_action = QAction("Set Fill Color", self) 121 | set_fill_color_action.triggered.connect(self.set_fill_color) 122 | edit_menu.addAction(set_fill_color_action) 123 | set_stroke_color_action = QAction("Set Stroke Color", self) 124 | set_stroke_color_action.triggered.connect(self.set_stroke_color) 125 | edit_menu.addAction(set_stroke_color_action) 126 | set_stroke_width_action = QAction("Set Stroke Width", self) 127 | set_stroke_width_action.triggered.connect(self.set_stroke_width) 128 | edit_menu.addAction(set_stroke_width_action) 129 | self.menuBar().addMenu(edit_menu) 130 | 131 | input_widgets_menu = QMenu("Input Widgets", self) 132 | add_range_slider_action = QAction("Add Range Slider", self) 133 | add_range_slider_action.triggered.connect(self.add_range_slider) 134 | input_widgets_menu.addAction(add_range_slider_action) 135 | add_color_picker_action = QAction("Add Color Picker", self) 136 | add_color_picker_action.triggered.connect(self.add_color_picker) 137 | input_widgets_menu.addAction(add_color_picker_action) 138 | self.menuBar().addMenu(input_widgets_menu) 139 | 140 | self.menuBar().setNativeMenuBar(False) 141 | 142 | self.generate_python_file_button = QPushButton("Generate Python File") 143 | self.generate_python_file_button.clicked.connect( 144 | self.generate_python_file) 145 | v_layout_2.addWidget(self.generate_python_file_button) 146 | self.generate_video_file_button = QPushButton("Render Video File") 147 | self.generate_video_file_button.clicked.connect(self.render_video_file) 148 | v_layout_2.addWidget(self.generate_video_file_button) 149 | 150 | self.mobject_picker_combobox = QComboBox() 151 | self.setup_mobject_picker_combobox() 152 | v_layout_2.addWidget(self.mobject_picker_combobox) 153 | 154 | self.add_mobject_button = QPushButton("Add Mobject") 155 | self.add_mobject_button.setShortcut("Ctrl+A") 156 | self.add_mobject_button.clicked.connect(self.select_mobject) 157 | v_layout_2.addWidget(self.add_mobject_button) 158 | 159 | self.animation_picker_combobox = QComboBox() 160 | self.setup_animation_picker_combobox() 161 | v_layout_2.addWidget(self.animation_picker_combobox) 162 | 163 | self.animate_mobject_button = QPushButton("Animate Mobject") 164 | self.animate_mobject_button.setShortcut("Ctrl+Shift+A") 165 | self.animate_mobject_button.clicked.connect(self.animate_mobject) 166 | v_layout_2.addWidget(self.animate_mobject_button) 167 | 168 | label = QLabel("Input Widgets") 169 | label.setFixedHeight(10) 170 | v_layout_2.addWidget(label) 171 | self.input_widgets_zone = QScrollArea() 172 | self.input_widgets_zone.setWidgetResizable(True) 173 | self.input_widgets_zone.setFixedHeight(window_size[1] // 2 - 100) 174 | self.input_widgets_zone.setFixedWidth(window_size[0] // 2 - 100) 175 | self.input_widgets_zone.setWidget(QWidget()) 176 | self.input_widgets_zone.widget().setLayout(QVBoxLayout()) 177 | v_layout_2.addWidget(self.input_widgets_zone) 178 | 179 | self.label = Preview(window_size, self.mobject_picker_combobox, scene) 180 | v_layout_1.addWidget(self.label) 181 | 182 | self.editor = QTextEdit() 183 | self.editor.setPlaceholderText("Write your code here") 184 | self.highlighter = PythonHighlighter(self.editor.document()) 185 | self.editor.setFixedHeight(window_size[1] // 2 - 200) 186 | self.editor.setFixedWidth(window_size[0] // 2) 187 | self.editor.setContentsMargins(0, 0, 0, 0) 188 | self.editor.setStyleSheet("background-color: rgb(46, 46, 46);") 189 | v_layout_1.addWidget(self.editor) 190 | 191 | old_update_to_time = copy(scene.update_to_time) 192 | 193 | def update_to_time(time: float): 194 | old_update_to_time(time) 195 | self.update_image() 196 | 197 | scene.update_to_time = update_to_time 198 | 199 | self.execute_button = QPushButton("Execute") 200 | self.execute_button.clicked.connect( 201 | lambda: self.execute(self.editor.toPlainText())) 202 | self.execute_button.setShortcut("Ctrl+Return") 203 | v_layout_1.addWidget(self.execute_button) 204 | 205 | plugins_menu = QMenu("Plugins", self) 206 | for name, module in ManimStudioAPI.plugins.items(): 207 | plugin_menu = QAction(name, self) 208 | plugin_menu.triggered.connect( 209 | lambda: ManimStudioAPI.run_plugin(name)) 210 | if hasattr(module, "init_widgets"): 211 | module.init_widgets(self) 212 | plugins_menu.addAction(plugin_menu) 213 | self.menuBar().addMenu(plugins_menu) 214 | 215 | def execute(self, code: str): 216 | setattr(self.scene, "code", code) 217 | 218 | def print_gui(self, text: str): 219 | QMessageBox.information(self, "Manim Studio - Print GUI", text) 220 | 221 | def add_range_slider(self): 222 | variable_name, ok = QInputDialog.getText( 223 | self, "Variable Name", "Enter the name of the variable") 224 | if not ok: 225 | return 226 | minimum, ok = QInputDialog.getDouble( 227 | self, "Minimum Value", "Enter the minimum value", 0.0, -1000000.0, 1000000.0, 6) 228 | if not ok: 229 | return 230 | maximum, ok = QInputDialog.getDouble( 231 | self, "Maximum Value", "Enter the maximum value", 100.0, -1000000.0, 1000000.0, 6) 232 | if not ok: 233 | return 234 | step, ok = QInputDialog.getDouble( 235 | self, "Step", "Enter the step", 1.0, -1000000.0, 1000000.0, 6) 236 | if not ok: 237 | return 238 | value, ok = QInputDialog.getDouble( 239 | self, "Value", "Enter the value", 0.0, -1000000.0, 1000000.0, 6) 240 | if not ok: 241 | return 242 | range_slider = RangeSlider( 243 | variable_name, value, minimum, maximum, step, self.width()) 244 | self.input_widgets_zone.widget().layout().addWidget(range_slider) 245 | 246 | def add_color_picker(self): 247 | variable_name, ok = QInputDialog.getText( 248 | self, "Variable Name", "Enter the name of the variable") 249 | if not ok: 250 | return 251 | color_picker = ColorPicker(variable_name, self.width()) 252 | self.input_widgets_zone.widget().layout().addWidget(color_picker) 253 | 254 | def set_fill_color(self): 255 | mobject_picker = MobjectPicker( 256 | self.width(), 257 | self.scene.camera, 258 | VMobject 259 | ) 260 | selected_mobject = mobject_picker.wait_for_selection() 261 | if selected_mobject is None: 262 | return 263 | name, selected_mobject = selected_mobject 264 | selected_mobject: VMobject 265 | color = selected_mobject.get_fill_color() 266 | (r, g, b), a = color.to_rgb(), selected_mobject.get_fill_opacity() 267 | color = int(r*255), int(g*255), int(b*255), int(a*255) 268 | fill_color = QColorDialog.getColor(QColor( 269 | *color), self, "Select Fill Color", QColorDialog.ColorDialogOption.ShowAlphaChannel) 270 | if not fill_color.isValid(): 271 | return 272 | r, g, b, a = fill_color.getRgbF() 273 | ManimStudioAPI.scene.code = f"self.{name}" \ 274 | f".set_fill(rgb_to_color(({r}, {g}, {b})), {a})" 275 | QMessageBox.information(self, "Fill Color Set", 276 | "The fill color has been set successfully") 277 | 278 | def set_stroke_color(self): 279 | mobject_picker = MobjectPicker( 280 | self.width(), 281 | self.scene.camera, 282 | VMobject 283 | ) 284 | selected_mobject = mobject_picker.wait_for_selection() 285 | if selected_mobject is None: 286 | return 287 | name, selected_mobject = selected_mobject 288 | selected_mobject: VMobject 289 | color = selected_mobject.get_stroke_color() 290 | (r, g, b), a = color.to_rgb(), selected_mobject.get_stroke_opacity() 291 | color = int(r*255), int(g*255), int(b*255), int(a*255) 292 | stroke_color = QColorDialog.getColor(QColor( 293 | *color), self, "Select Stroke Color", QColorDialog.ColorDialogOption.ShowAlphaChannel) 294 | if not stroke_color.isValid(): 295 | return 296 | r, g, b, a = stroke_color.getRgbF() 297 | ManimStudioAPI.scene.code = f"self.{name}" \ 298 | f".set_stroke(rgb_to_color(({r}, {g}, {b})), opacity={a})" 299 | QMessageBox.information(self, "Stroke Color Set", 300 | "The stroke color has been set successfully") 301 | 302 | def set_stroke_width(self): 303 | mobject_picker = MobjectPicker( 304 | self.width(), 305 | self.scene.camera, 306 | VMobject 307 | ) 308 | selected_mobject = mobject_picker.wait_for_selection() 309 | if selected_mobject is None: 310 | return 311 | name, selected_mobject = selected_mobject 312 | selected_mobject: VMobject 313 | stroke_width, ok = QInputDialog.getDouble( 314 | self, "Set Stroke Width", "Enter the stroke width", selected_mobject.get_stroke_width(), 0, 100, 1) 315 | if not ok: 316 | return 317 | ManimStudioAPI.scene.code = f"self.{name}" \ 318 | f".set_stroke(width={stroke_width})" 319 | QMessageBox.information(self, "Stroke Width Set", 320 | "The stroke width has been set successfully") 321 | 322 | def select_mobject(self): 323 | self.label.mobject_to_put = ManimStudioAPI.supported_mobjects[self.mobject_picker_combobox.currentText( 324 | )] 325 | self.mobject_picker_combobox.setDisabled(True) 326 | 327 | def setup_mobject_picker_combobox(self): 328 | for mobject in ManimStudioAPI.supported_mobjects: 329 | if mobject == "Circle": 330 | camera = Camera( 331 | pixel_width=1000, 332 | pixel_height=1000, 333 | frame_width=2.25, 334 | frame_height=2.25, 335 | background_opacity=0 336 | ) 337 | self.mobject_picker_combobox.addItem( 338 | QIcon(QPixmap.fromImage(ImageQt(Circle(stroke_width=16) 339 | .get_image(camera)))), 340 | "Circle" 341 | ) 342 | elif mobject == "Regular Polygon": 343 | camera = Camera( 344 | pixel_width=1000, 345 | pixel_height=1000, 346 | frame_width=2.25, 347 | frame_height=2.25, 348 | background_opacity=0 349 | ) 350 | self.mobject_picker_combobox.addItem( 351 | QIcon(QPixmap.fromImage(ImageQt(RegularPolygon(6, stroke_width=16) 352 | .get_image(camera)))), 353 | "Regular Polygon" 354 | ) 355 | elif mobject == "Line": 356 | camera = Camera( 357 | pixel_width=1000, 358 | pixel_height=1000, 359 | frame_width=2.25, 360 | frame_height=2.25, 361 | background_opacity=0 362 | ) 363 | self.mobject_picker_combobox.addItem( 364 | QIcon(QPixmap.fromImage(ImageQt(Line( 365 | DL, UR, stroke_width=16, color=BLACK 366 | ).get_image(camera)))), 367 | "Line" 368 | ) 369 | elif mobject == "MathTex": 370 | camera = Camera( 371 | pixel_width=1000, 372 | pixel_height=1000, 373 | frame_width=2.25, 374 | frame_height=2.25, 375 | background_opacity=0 376 | ) 377 | self.mobject_picker_combobox.addItem( 378 | QIcon(QPixmap.fromImage(ImageQt(MathTex("x^2", color=BLACK) 379 | .scale_to_fit_width(2) 380 | .get_image(camera)))), 381 | "MathTex" 382 | ) 383 | elif mobject == "Text": 384 | camera = Camera( 385 | pixel_width=1000, 386 | pixel_height=1000, 387 | frame_width=2.25, 388 | frame_height=2.25, 389 | background_opacity=0 390 | ) 391 | self.mobject_picker_combobox.addItem( 392 | QIcon(QPixmap.fromImage(ImageQt(Text("T", color=BLACK) 393 | .scale_to_fit_width(2) 394 | .get_image(camera)))), 395 | "Text" 396 | ) 397 | 398 | def setup_animation_picker_combobox(self): 399 | for animation in ManimStudioAPI.supported_animations: 400 | self.animation_picker_combobox.addItem(animation) 401 | 402 | def animate_mobject(self): 403 | mobject_picker = MobjectPicker( 404 | self.width(), 405 | self.scene.camera, 406 | VMobject 407 | ) 408 | selected_mobject = mobject_picker.wait_for_selection() 409 | if selected_mobject is None: 410 | return 411 | name, selected_mobject = selected_mobject 412 | selected_mobject: VMobject 413 | animation = ManimStudioAPI.supported_animations[self.animation_picker_combobox.currentText( 414 | )] 415 | if animation not in (Transform, ReplacementTransform): 416 | ManimStudioAPI.scene.code = f"self.play({animation.__name__}" \ 417 | f"(self.{name}))" 418 | QMessageBox.information( 419 | self, "Animation Added", "The animation has been added successfully. If you don't like it, you can undo") 420 | return 421 | mobject_picker_2 = MobjectPicker( 422 | self.width(), 423 | self.scene.camera, 424 | VMobject 425 | ) 426 | selected_mobject_2 = mobject_picker_2.wait_for_selection() 427 | if selected_mobject_2 is None: 428 | return 429 | name_2, selected_mobject_2 = selected_mobject_2 430 | selected_mobject_2: VMobject 431 | ManimStudioAPI.scene.code = f"self.play({animation.__name__}" \ 432 | f"(self.{name}, self.{name_2}))" 433 | QMessageBox.information( 434 | self, "Animation Added", "The animation has been added successfully. If you don't like it, you can undo") 435 | 436 | def show_error(self, error: Exception): 437 | """Show the given error in the GUI.""" 438 | QMessageBox.critical( 439 | self, 440 | "Error", 441 | "¡Ha ocurrido un error!\n\n" 442 | f"{error.__class__.__name__}: {error}" 443 | ) 444 | 445 | def generate_python_file(self): 446 | self.scene.code = "" 447 | file_name, _ = QFileDialog.getSaveFileName( 448 | self, "Save Python File", "", "Python Files (*.py)") 449 | if not file_name: 450 | return 451 | scene_class_name = QInputDialog.getText( 452 | self, "Scene Class Name", "Enter the name of the scene class")[0] 453 | scene_class_name = make_camel_case( 454 | scene_class_name, 455 | f"{ManimStudioAPI.scene.__class__.__name__}Generated" 456 | ) 457 | codes = ManimStudioAPI.codes 458 | codes = [line for code in codes for line in code.split("\n")] 459 | with open(file_name, "w") as f: 460 | f.write(FILE_CONTENT_TEMPLATE % ( 461 | CONTENT_IF_IMPORTED % repr( 462 | str(Path(ManimStudioAPI.path_to_file).absolute())) 463 | if ManimStudioAPI.path_to_file else "", 464 | scene_class_name, 465 | f"module.{ManimStudioAPI.scene.__class__.__name__}" 466 | if ManimStudioAPI.scene.__class__ != Scene else "Scene", 467 | "\n".join(8*" " + line for line in codes) 468 | )) 469 | self.saved_file = file_name 470 | self.saved_scene_class_name = scene_class_name 471 | QMessageBox.information( 472 | self, "File Saved", "The file has been saved successfully") 473 | 474 | def render_video_file(self): 475 | if not self.saved_file: 476 | QMessageBox.critical( 477 | self, "Error", "You must generate a Python file before rendering") 478 | return 479 | file_name, _ = QFileDialog.getSaveFileName( 480 | self, "Save Video File", "", "Video Files (*.mp4)") 481 | if not file_name: 482 | return 483 | preview = QMessageBox.question(self, "Preview", "Do you want to preview the video?", 484 | QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) 485 | path = Path(file_name) 486 | 487 | process = Popen( 488 | [ 489 | "manim", 490 | self.saved_file, 491 | self.saved_scene_class_name, 492 | "-o", 493 | f"{path.stem}.mp4", 494 | "--format=mp4", 495 | ] 496 | ) 497 | process.wait() 498 | 499 | output_path = Path("media") / "videos" / \ 500 | Path(self.saved_file).stem / "1080p60" / f"{path.stem}.mp4" 501 | if output_path.exists(): 502 | shutil.move(str(output_path), str(path)) 503 | if preview == QMessageBox.StandardButton.Yes: 504 | open_file(path) 505 | QMessageBox.information( 506 | self, "File Saved", "The video has been rendered successfully") 507 | else: 508 | QMessageBox.critical( 509 | self, "Error", "The video could not be rendered") 510 | 511 | def update_image(self): 512 | frame = self.scene.renderer.get_frame() 513 | qimage = ImageQt(Image.fromarray(frame)) 514 | pixmap = QPixmap.fromImage(qimage) \ 515 | .scaled(self.label.width(), self.label.height(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) 516 | self.label.setPixmap(pixmap) 517 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "certifi" 5 | version = "2024.2.2" 6 | description = "Python package for providing Mozilla's CA Bundle." 7 | optional = false 8 | python-versions = ">=3.6" 9 | files = [ 10 | {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, 11 | {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, 12 | ] 13 | 14 | [[package]] 15 | name = "charset-normalizer" 16 | version = "3.3.2" 17 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 18 | optional = false 19 | python-versions = ">=3.7.0" 20 | files = [ 21 | {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, 22 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, 23 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, 24 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, 25 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, 26 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, 27 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, 28 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, 29 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, 30 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, 31 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, 32 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, 33 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, 34 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, 35 | {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, 36 | {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, 37 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, 38 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, 39 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, 40 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, 41 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, 42 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, 43 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, 44 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, 45 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, 46 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, 47 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, 48 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, 49 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, 50 | {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, 51 | {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, 52 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, 53 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, 54 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, 55 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, 56 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, 57 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, 58 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, 59 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, 60 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, 61 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, 62 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, 63 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, 64 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, 65 | {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, 66 | {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, 67 | {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, 68 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, 69 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, 70 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, 71 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, 72 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, 73 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, 74 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, 75 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, 76 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, 77 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, 78 | {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, 79 | {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, 80 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, 81 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, 82 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, 83 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, 84 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, 85 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, 86 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, 87 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, 88 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, 89 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, 90 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, 91 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, 92 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, 93 | {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, 94 | {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, 95 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, 96 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, 97 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, 98 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, 99 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, 100 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, 101 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, 102 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, 103 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, 104 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, 105 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, 106 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, 107 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, 108 | {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, 109 | {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, 110 | {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, 111 | ] 112 | 113 | [[package]] 114 | name = "click" 115 | version = "8.1.7" 116 | description = "Composable command line interface toolkit" 117 | optional = false 118 | python-versions = ">=3.7" 119 | files = [ 120 | {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, 121 | {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, 122 | ] 123 | 124 | [package.dependencies] 125 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 126 | 127 | [[package]] 128 | name = "click-default-group" 129 | version = "1.2.4" 130 | description = "click_default_group" 131 | optional = false 132 | python-versions = ">=2.7" 133 | files = [ 134 | {file = "click_default_group-1.2.4-py2.py3-none-any.whl", hash = "sha256:9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f"}, 135 | {file = "click_default_group-1.2.4.tar.gz", hash = "sha256:eb3f3c99ec0d456ca6cd2a7f08f7d4e91771bef51b01bdd9580cc6450fe1251e"}, 136 | ] 137 | 138 | [package.dependencies] 139 | click = "*" 140 | 141 | [package.extras] 142 | test = ["pytest"] 143 | 144 | [[package]] 145 | name = "cloup" 146 | version = "2.1.2" 147 | description = "Adds features to Click: option groups, constraints, subcommand sections and help themes." 148 | optional = false 149 | python-versions = ">=3.7" 150 | files = [ 151 | {file = "cloup-2.1.2-py2.py3-none-any.whl", hash = "sha256:2e2e5040f1e85f7f391487c1aeeb0cce3e7cfed3493e67fc2aabc683551ba7b7"}, 152 | {file = "cloup-2.1.2.tar.gz", hash = "sha256:43f10e944056f3a1eea714cb67373beebebbefc3f4551428750392f3e04ac964"}, 153 | ] 154 | 155 | [package.dependencies] 156 | click = ">=8.0,<9.0" 157 | 158 | [[package]] 159 | name = "colorama" 160 | version = "0.4.6" 161 | description = "Cross-platform colored terminal text." 162 | optional = false 163 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 164 | files = [ 165 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 166 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 167 | ] 168 | 169 | [[package]] 170 | name = "cython" 171 | version = "3.0.9" 172 | description = "The Cython compiler for writing C extensions in the Python language." 173 | optional = false 174 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 175 | files = [ 176 | {file = "Cython-3.0.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:296bd30d4445ac61b66c9d766567f6e81a6e262835d261e903c60c891a6729d3"}, 177 | {file = "Cython-3.0.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f496b52845cb45568a69d6359a2c335135233003e708ea02155c10ce3548aa89"}, 178 | {file = "Cython-3.0.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:858c3766b9aa3ab8a413392c72bbab1c144a9766b7c7bfdef64e2e414363fa0c"}, 179 | {file = "Cython-3.0.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0eb1e6ef036028a52525fd9a012a556f6dd4788a0e8755fe864ba0e70cde2ff"}, 180 | {file = "Cython-3.0.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c8191941073ea5896321de3c8c958fd66e5f304b0cd1f22c59edd0b86c4dd90d"}, 181 | {file = "Cython-3.0.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e32b016030bc72a8a22a1f21f470a2f57573761a4f00fbfe8347263f4fbdb9f1"}, 182 | {file = "Cython-3.0.9-cp310-cp310-win32.whl", hash = "sha256:d6f3ff1cd6123973fe03e0fb8ee936622f976c0c41138969975824d08886572b"}, 183 | {file = "Cython-3.0.9-cp310-cp310-win_amd64.whl", hash = "sha256:56f3b643dbe14449248bbeb9a63fe3878a24256664bc8c8ef6efd45d102596d8"}, 184 | {file = "Cython-3.0.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:35e6665a20d6b8a152d72b7fd87dbb2af6bb6b18a235b71add68122d594dbd41"}, 185 | {file = "Cython-3.0.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92f4960c40ad027bd8c364c50db11104eadc59ffeb9e5b7f605ca2f05946e20"}, 186 | {file = "Cython-3.0.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38df37d0e732fbd9a2fef898788492e82b770c33d1e4ed12444bbc8a3b3f89c0"}, 187 | {file = "Cython-3.0.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad7fd88ebaeaf2e76fd729a8919fae80dab3d6ac0005e28494261d52ff347a8f"}, 188 | {file = "Cython-3.0.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1365d5f76bf4d19df3d19ce932584c9bb76e9fb096185168918ef9b36e06bfa4"}, 189 | {file = "Cython-3.0.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c232e7f279388ac9625c3e5a5a9f0078a9334959c5d6458052c65bbbba895e1e"}, 190 | {file = "Cython-3.0.9-cp311-cp311-win32.whl", hash = "sha256:357e2fad46a25030b0c0496487e01a9dc0fdd0c09df0897f554d8ba3c1bc4872"}, 191 | {file = "Cython-3.0.9-cp311-cp311-win_amd64.whl", hash = "sha256:1315aee506506e8d69cf6631d8769e6b10131fdcc0eb66df2698f2a3ddaeeff2"}, 192 | {file = "Cython-3.0.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:157973807c2796addbed5fbc4d9c882ab34bbc60dc297ca729504901479d5df7"}, 193 | {file = "Cython-3.0.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00b105b5d050645dd59e6767bc0f18b48a4aa11c85f42ec7dd8181606f4059e3"}, 194 | {file = "Cython-3.0.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac5536d09bef240cae0416d5a703d298b74c7bbc397da803ac9d344e732d4369"}, 195 | {file = "Cython-3.0.9-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09c44501d476d16aaa4cbc29c87f8c0f54fc20e69b650d59cbfa4863426fc70c"}, 196 | {file = "Cython-3.0.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:cc9c3b9f20d8e298618e5ccd32083ca386e785b08f9893fbec4c50b6b85be772"}, 197 | {file = "Cython-3.0.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a30d96938c633e3ec37000ac3796525da71254ef109e66bdfd78f29891af6454"}, 198 | {file = "Cython-3.0.9-cp312-cp312-win32.whl", hash = "sha256:757ca93bdd80702546df4d610d2494ef2e74249cac4d5ba9464589fb464bd8a3"}, 199 | {file = "Cython-3.0.9-cp312-cp312-win_amd64.whl", hash = "sha256:1dc320a9905ab95414013f6de805efbff9e17bb5fb3b90bbac533f017bec8136"}, 200 | {file = "Cython-3.0.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4ae349960ebe0da0d33724eaa7f1eb866688fe5434cc67ce4dbc06d6a719fbfc"}, 201 | {file = "Cython-3.0.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63d2537bf688247f76ded6dee28ebd26274f019309aef1eb4f2f9c5c482fde2d"}, 202 | {file = "Cython-3.0.9-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36f5a2dfc724bea1f710b649f02d802d80fc18320c8e6396684ba4a48412445a"}, 203 | {file = "Cython-3.0.9-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:deaf4197d4b0bcd5714a497158ea96a2bd6d0f9636095437448f7e06453cc83d"}, 204 | {file = "Cython-3.0.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:000af6deb7412eb7ac0c635ff5e637fb8725dd0a7b88cc58dfc2b3de14e701c4"}, 205 | {file = "Cython-3.0.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:15c7f5c2d35bed9aa5f2a51eaac0df23ae72f2dbacf62fc672dd6bfaa75d2d6f"}, 206 | {file = "Cython-3.0.9-cp36-cp36m-win32.whl", hash = "sha256:f49aa4970cd3bec66ac22e701def16dca2a49c59cceba519898dd7526e0be2c0"}, 207 | {file = "Cython-3.0.9-cp36-cp36m-win_amd64.whl", hash = "sha256:4558814fa025b193058d42eeee498a53d6b04b2980d01339fc2444b23fd98e58"}, 208 | {file = "Cython-3.0.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:539cd1d74fd61f6cfc310fa6bbbad5adc144627f2b7486a07075d4e002fd6aad"}, 209 | {file = "Cython-3.0.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3232926cd406ee02eabb732206f6e882c3aed9d58f0fea764013d9240405bcf"}, 210 | {file = "Cython-3.0.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33b6ac376538a7fc8c567b85d3c71504308a9318702ec0485dd66c059f3165cb"}, 211 | {file = "Cython-3.0.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2cc92504b5d22ac66031ffb827bd3a967fc75a5f0f76ab48bce62df19be6fdfd"}, 212 | {file = "Cython-3.0.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:22b8fae756c5c0d8968691bed520876de452f216c28ec896a00739a12dba3bd9"}, 213 | {file = "Cython-3.0.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9cda0d92a09f3520f29bd91009f1194ba9600777c02c30c6d2d4ac65fb63e40d"}, 214 | {file = "Cython-3.0.9-cp37-cp37m-win32.whl", hash = "sha256:ec612418490941ed16c50c8d3784c7bdc4c4b2a10c361259871790b02ec8c1db"}, 215 | {file = "Cython-3.0.9-cp37-cp37m-win_amd64.whl", hash = "sha256:976c8d2bedc91ff6493fc973d38b2dc01020324039e2af0e049704a8e1b22936"}, 216 | {file = "Cython-3.0.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5055988b007c92256b6e9896441c3055556038c3497fcbf8c921a6c1fce90719"}, 217 | {file = "Cython-3.0.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9360606d964c2d0492a866464efcf9d0a92715644eede3f6a2aa696de54a137"}, 218 | {file = "Cython-3.0.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c6e809f060bed073dc7cba1648077fe3b68208863d517c8b39f3920eecf9dd"}, 219 | {file = "Cython-3.0.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95ed792c966f969cea7489c32ff90150b415c1f3567db8d5a9d489c7c1602dac"}, 220 | {file = "Cython-3.0.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8edd59d22950b400b03ca78d27dc694d2836a92ef0cac4f64cb4b2ff902f7e25"}, 221 | {file = "Cython-3.0.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4cf0ed273bf60e97922fcbbdd380c39693922a597760160b4b4355e6078ca188"}, 222 | {file = "Cython-3.0.9-cp38-cp38-win32.whl", hash = "sha256:5eb9bd4ae12ebb2bc79a193d95aacf090fbd8d7013e11ed5412711650cb34934"}, 223 | {file = "Cython-3.0.9-cp38-cp38-win_amd64.whl", hash = "sha256:44457279da56e0f829bb1fc5a5dc0836e5d498dbcf9b2324f32f7cc9d2ec6569"}, 224 | {file = "Cython-3.0.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4b419a1adc2af43f4660e2f6eaf1e4fac2dbac59490771eb8ac3d6063f22356"}, 225 | {file = "Cython-3.0.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f836192140f033b2319a0128936367c295c2b32e23df05b03b672a6015757ea"}, 226 | {file = "Cython-3.0.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd198c1a7f8e9382904d622cc0efa3c184605881fd5262c64cbb7168c4c1ec5"}, 227 | {file = "Cython-3.0.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a274fe9ca5c53fafbcf5c8f262f8ad6896206a466f0eeb40aaf36a7951e957c0"}, 228 | {file = "Cython-3.0.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:158c38360bbc5063341b1e78d3737f1251050f89f58a3df0d10fb171c44262be"}, 229 | {file = "Cython-3.0.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8bf30b045f7deda0014b042c1b41c1d272facc762ab657529e3b05505888e878"}, 230 | {file = "Cython-3.0.9-cp39-cp39-win32.whl", hash = "sha256:9a001fd95c140c94d934078544ff60a3c46aca2dc86e75a76e4121d3cd1f4b33"}, 231 | {file = "Cython-3.0.9-cp39-cp39-win_amd64.whl", hash = "sha256:530c01c4aebba709c0ec9c7ecefe07177d0b9fd7ffee29450a118d92192ccbdf"}, 232 | {file = "Cython-3.0.9-py2.py3-none-any.whl", hash = "sha256:bf96417714353c5454c2e3238fca9338599330cf51625cdc1ca698684465646f"}, 233 | {file = "Cython-3.0.9.tar.gz", hash = "sha256:a2d354f059d1f055d34cfaa62c5b68bc78ac2ceab6407148d47fb508cf3ba4f3"}, 234 | ] 235 | 236 | [[package]] 237 | name = "decorator" 238 | version = "5.1.1" 239 | description = "Decorators for Humans" 240 | optional = false 241 | python-versions = ">=3.5" 242 | files = [ 243 | {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, 244 | {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, 245 | ] 246 | 247 | [[package]] 248 | name = "exceptiongroup" 249 | version = "1.2.0" 250 | description = "Backport of PEP 654 (exception groups)" 251 | optional = false 252 | python-versions = ">=3.7" 253 | files = [ 254 | {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, 255 | {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, 256 | ] 257 | 258 | [package.extras] 259 | test = ["pytest (>=6)"] 260 | 261 | [[package]] 262 | name = "glcontext" 263 | version = "2.5.0" 264 | description = "Portable OpenGL Context" 265 | optional = false 266 | python-versions = "*" 267 | files = [ 268 | {file = "glcontext-2.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3e0f3fbbe483f3e671ae04698a2d38234cb9a5682d2edd49d5bce08a32d48ff1"}, 269 | {file = "glcontext-2.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:837ae9ed985dc8185b7f7ac62bc2727d58806f1eb125b3766f576a3957aa078b"}, 270 | {file = "glcontext-2.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c056bfbc4af86337837fbea0899b1c439673b9e2bf9aaaf78862cb68ccaeb41"}, 271 | {file = "glcontext-2.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:198d6f80a271668995f595492b7cde0e7f354e927398d85c20976a7eaf18742b"}, 272 | {file = "glcontext-2.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f435118eabef929e5281bf609eeaae343a0d3f7e34c2a4b0f026451f63a8baab"}, 273 | {file = "glcontext-2.5.0-cp310-cp310-win32.whl", hash = "sha256:9ac01ea37deb27cc53a15eb9a8ec30389cd5421c668842e0197360a502448e11"}, 274 | {file = "glcontext-2.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:194b2657f46310cd86662d946d85162710b43e4abbef800c83a61f44b09352ad"}, 275 | {file = "glcontext-2.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:798bc74604e306386f858be11aa1fe47c88296ac6fb9b5718a1c5a4cfb24416c"}, 276 | {file = "glcontext-2.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36383ef0f21a179cfd7d6907eb04d7736b724a231a7199edec194528c986b0c"}, 277 | {file = "glcontext-2.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25da4a8a8707f88e66d1597c5f03be31b354b6d6186907ad06b4735f981aa25e"}, 278 | {file = "glcontext-2.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6abae09cadd947c9b3e39c424517eb76e4d6caeca9415c44b290f3425ffb51da"}, 279 | {file = "glcontext-2.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:be62e4ce64c7f72730fccbb09efb37b3aad4e54b6f547b18161233c2a9bf9fc2"}, 280 | {file = "glcontext-2.5.0-cp311-cp311-win32.whl", hash = "sha256:a4441744dadf811f923ab2aff52ba2dc175b6f99bcc208e362399461c96c085f"}, 281 | {file = "glcontext-2.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:7d50c62fae0af1b19daa95571d52a5c56f3f1537483f105b4d092be5eb160c9d"}, 282 | {file = "glcontext-2.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc2a13791007d18b71fc9eccd3423be0a3d5c16b8d1ac4410767665a9824cc21"}, 283 | {file = "glcontext-2.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cbe2684a689cc77e659e90254dcd897af773ddda43308196c7db889d8558f9d1"}, 284 | {file = "glcontext-2.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd0f159c01dfaab990fedb9672f4be040ae7fe066afb2ce7413c63afa9475f38"}, 285 | {file = "glcontext-2.5.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7669583276cc2b4e38b1f62f5d10afdde518ffd5ff6ccfabf22157e081a0abe6"}, 286 | {file = "glcontext-2.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:74530549706fabbaecab437102c9d490adba8e27e4ca01bb9ce0050b0d558ff9"}, 287 | {file = "glcontext-2.5.0-cp312-cp312-win32.whl", hash = "sha256:762ee1231f1c5896c527ce29c76921e4868a9f21b0f305b048516a479fe500bf"}, 288 | {file = "glcontext-2.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:942486de098c035dad9165e4cb6ad6342edb8c98b11ee5cdfe97088c7c6840aa"}, 289 | {file = "glcontext-2.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9519f31c464cf1ab1232411e8700829d5bad1fb79470fde99d0aa25296cd4ec7"}, 290 | {file = "glcontext-2.5.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb33a0e3d2d7a1c3f51652489ed4d1ad16fa71ca1452bf4f983f14446d062592"}, 291 | {file = "glcontext-2.5.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab8dd3d2ea53ce6735dd9915d69572b7dd001f7fe2d35d362182e69b923193e4"}, 292 | {file = "glcontext-2.5.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:ec64bc8a6cdfb51c91c601b0d82744bfa85637fe6259f3587f73d67b5d124937"}, 293 | {file = "glcontext-2.5.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0e9c890c0fee8ff5c5ec356b0382093e8519a8bdf99ba5ced9f2ac641a37d4ec"}, 294 | {file = "glcontext-2.5.0-cp36-cp36m-win32.whl", hash = "sha256:41a3fa100962ac8733835dd15163e102d165bf65d9247b98e5bcbaa90e94666d"}, 295 | {file = "glcontext-2.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:73828d76e764f9d22704dd0304f27ec6af18cb075de0df201a23f1456d2b502e"}, 296 | {file = "glcontext-2.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f10a15975c1798bbe4f2d783e1b9c0e32f0dbdc7829a73dce21efb3ee1e24867"}, 297 | {file = "glcontext-2.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23700a43c3ced889d8ac18cb7902a76096634761f87d8139ca956bcadc3feabd"}, 298 | {file = "glcontext-2.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95675cd7c16249fde2ea9690c8b2bd39a551b67e9929eeecfdbcbc82d9c6fc4"}, 299 | {file = "glcontext-2.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:efc8a1ec7f6cdc205515e2e4e6ba0a02c2f7207a1340cce80960d63002785405"}, 300 | {file = "glcontext-2.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:464f2296474ec07318466f2381748c8259c8a587c5fcd6485ad53bbe1702363b"}, 301 | {file = "glcontext-2.5.0-cp37-cp37m-win32.whl", hash = "sha256:352cf17ade6ea429bd548384ea715024124bb83fdbf3ea06f69f53b6a9e3111f"}, 302 | {file = "glcontext-2.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9cacc6b068f74f789729dc0512611b6889a95cf6f2ff4c90aea1f741010e0d7a"}, 303 | {file = "glcontext-2.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1204fe22c96d9b36299fac20de7d9319e018e80770964e3d71375853d1b5373d"}, 304 | {file = "glcontext-2.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54e9f848ad21a471e970a0e1eedd3b85025821a0d3c4d63d09d2b97f1a7280b8"}, 305 | {file = "glcontext-2.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a8e3022da94316a4bb44e064d85e4b05c13f9eef6e68f6395644122a362ec0"}, 306 | {file = "glcontext-2.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:73c289fdfce7e8b736034f75e206be8bcc6144d132e910c816e33d2419b984b7"}, 307 | {file = "glcontext-2.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:47dc72cb63f35523f0fa6a27fcb819c3aa19e96c01a2ee8594132ffa834fab18"}, 308 | {file = "glcontext-2.5.0-cp38-cp38-win32.whl", hash = "sha256:2f71d800e8d720fa52aeeebf22d066c17528d756234e586d48b8c82b2fd65372"}, 309 | {file = "glcontext-2.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:3ba303e28a54491cd49caa6f0626b3f1992160ca1d82c2347ce30c50a16ee9b6"}, 310 | {file = "glcontext-2.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bf968a827c04d5210afc2a84d825719fa3025fd9def4aea4820e75a607d09ccf"}, 311 | {file = "glcontext-2.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:586778f6d476f34b8ddbb99d77b65cb7126cd3f501a2cb1e6e12f0bc997ca9b8"}, 312 | {file = "glcontext-2.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675091975c2bf8b59e9c41d1daa6684006162c3cf3d9e2a1acda31b35181d9d2"}, 313 | {file = "glcontext-2.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:cf928dfbed4fceb3a816452828e8745e46b8348869c0fdda312f6c73f0796906"}, 314 | {file = "glcontext-2.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1aee2105c66d1a5470d2c2de7d80977c67ee2b2cf4db6fa2b3dcbd586b888b51"}, 315 | {file = "glcontext-2.5.0-cp39-cp39-win32.whl", hash = "sha256:b1200d841b7a1ef1051fafe6aad6a472c784bc4fb906375160b0efa7d7acae71"}, 316 | {file = "glcontext-2.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:7a7962f89350966966a4a5628fd4861a81dc4f76014571567a54db4c1573e04d"}, 317 | {file = "glcontext-2.5.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9eee5426fad207fb1c572ee7e4b8341ee8f6529189f06cbd32b132ee4de31a8e"}, 318 | {file = "glcontext-2.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:433e14a9c3d368c51940a480d4f548b671ad339d5efa0604bd0d5236fae4e564"}, 319 | {file = "glcontext-2.5.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2342642732609c7cb3d681771e096fe769df58e49bdb3348bfc9f5732103c444"}, 320 | {file = "glcontext-2.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:16057bf3736f38005a7f700188a50de597cd86650d6718a115bd835d69ba554b"}, 321 | {file = "glcontext-2.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8ba64f9c14009132625b7b1f1b8545298c6ddd1d3abc78618b0f9553c219d053"}, 322 | {file = "glcontext-2.5.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811276496f46f3f9b204e43a9d35c6213f1f0a8e58d8da203d477e21e8367fc0"}, 323 | {file = "glcontext-2.5.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe0be5cf5a9598379e994d7d96d84ce506e6a7680a098c1f1112de7aaa036ebd"}, 324 | {file = "glcontext-2.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1914d44374d7ee94df779681218639324ab79b3b8e27e8fb6154a8db55e3928e"}, 325 | {file = "glcontext-2.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:916fa56a544f57ff3d53cc60d3d1f0da66c67e6cf5092e3d7ef8bbaedd47a266"}, 326 | {file = "glcontext-2.5.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1abdc499c59e4a1dd59e321151171ecb583f3fac07af428c47a8b8e3ce5ff5bf"}, 327 | {file = "glcontext-2.5.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c73882865f3daf8a02fae1486c933146dc2f1bb8de3be26907b145523df4afc1"}, 328 | {file = "glcontext-2.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:136ab0d4f966adc7a2f397e8f17debf3da18afb4b5b8684db59ea9c9452fe2f6"}, 329 | {file = "glcontext-2.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:95e6805475552254d9e1a65c2433c150e364da0081dcc6fa79d90bf74665384b"}, 330 | {file = "glcontext-2.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:60343a07fd30c024c6889687d10524c4b9f321c3991666e6c23eb0e695f60ae1"}, 331 | {file = "glcontext-2.5.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e7db3961200f3cf607ac68eb0df0640e5d538f1c029c6d9433722ee04f37960"}, 332 | {file = "glcontext-2.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7017ac46784adce071cdcda5e3ce07523bbc10186c0c9cc3120aba91f0633817"}, 333 | {file = "glcontext-2.5.0.tar.gz", hash = "sha256:0f70d4be0cdd2b532a16da76c8f786b6367754a4086aaadffdbf3e37badbad02"}, 334 | ] 335 | 336 | [[package]] 337 | name = "idna" 338 | version = "3.6" 339 | description = "Internationalized Domain Names in Applications (IDNA)" 340 | optional = false 341 | python-versions = ">=3.5" 342 | files = [ 343 | {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, 344 | {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, 345 | ] 346 | 347 | [[package]] 348 | name = "iniconfig" 349 | version = "2.0.0" 350 | description = "brain-dead simple config-ini parsing" 351 | optional = false 352 | python-versions = ">=3.7" 353 | files = [ 354 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 355 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 356 | ] 357 | 358 | [[package]] 359 | name = "isosurfaces" 360 | version = "0.1.0" 361 | description = "Construct isolines/isosurfaces over a 2D/3D scalar field defined by a function (not a uniform grid)" 362 | optional = false 363 | python-versions = "*" 364 | files = [ 365 | {file = "isosurfaces-0.1.0-py3-none-any.whl", hash = "sha256:a3421f7e7115f72f8f1af538ac4723e5570b1aaa0ddfc6a86520d2d781f3e91f"}, 366 | {file = "isosurfaces-0.1.0.tar.gz", hash = "sha256:fa1b44e5e59d2f429add49289ab89e36f8dcda49b7badd99e0beea273be331f4"}, 367 | ] 368 | 369 | [package.dependencies] 370 | numpy = "*" 371 | 372 | [[package]] 373 | name = "manim" 374 | version = "0.18.0" 375 | description = "Animation engine for explanatory math videos." 376 | optional = false 377 | python-versions = ">=3.8,<3.13" 378 | files = [ 379 | {file = "manim-0.18.0-py3-none-any.whl", hash = "sha256:56f598c66292d78ef11c56af54e06cf5203b8e227b76563f60177a2b4fa36719"}, 380 | {file = "manim-0.18.0.tar.gz", hash = "sha256:56788066bc1aec2471a988c91e337194fd38d1035ed1b4d10838bfe64bd26af8"}, 381 | ] 382 | 383 | [package.dependencies] 384 | click = ">=7.2,<=9.0" 385 | click-default-group = ">=1.2.2,<2.0.0" 386 | cloup = ">=0.13,<2.2" 387 | decorator = ">=5.0.7,<6.0.0" 388 | isosurfaces = "0.1.0" 389 | manimpango = ">=0.5.0,<1.0.0" 390 | mapbox-earcut = ">=1.0.0,<2.0.0" 391 | moderngl = ">=5.6.3,<6.0.0" 392 | moderngl-window = ">=2.3.0,<3.0.0" 393 | networkx = ">=2.5,<3.3" 394 | numpy = [ 395 | {version = ">=1.22,<2.0", markers = "python_version < \"3.12\""}, 396 | {version = ">=1.26,<2.0", markers = "python_version >= \"3.12\""}, 397 | ] 398 | Pillow = ">=9.1,<10.0" 399 | pycairo = ">=1.21,<2.0" 400 | pydub = ">=0.25.1,<0.26.0" 401 | Pygments = ">=2.10.0,<3.0.0" 402 | requests = ">=2.26.0,<3.0.0" 403 | rich = ">=6.0,<12.0.0 || >12.0.0" 404 | scipy = [ 405 | {version = ">=1.7.3,<2.0.0", markers = "python_version < \"3.12\""}, 406 | {version = ">=1.11,<2.0", markers = "python_version >= \"3.12\""}, 407 | ] 408 | screeninfo = ">=0.8,<0.9" 409 | skia-pathops = [ 410 | {version = ">=0.7.0,<0.8.0", markers = "python_version < \"3.12\""}, 411 | {version = ">=0.8.0.post1,<0.9.0", markers = "python_version >= \"3.12\""}, 412 | ] 413 | srt = ">=3.5.0,<4.0.0" 414 | svgelements = ">=1.8.0,<2.0.0" 415 | tqdm = ">=4.62.3,<5.0.0" 416 | typing-extensions = ">=4.7.1,<5.0.0" 417 | watchdog = ">=2.1,<=3.0.0" 418 | 419 | [package.extras] 420 | gui = ["dearpygui (>=1.3.1,<2.0.0)"] 421 | jupyterlab = ["jupyterlab (>=3.0,<4.0)", "notebook (>=6.4,<7.0)"] 422 | 423 | [[package]] 424 | name = "manimpango" 425 | version = "0.5.0" 426 | description = "Bindings for Pango for using with Manim." 427 | optional = false 428 | python-versions = ">=3.8" 429 | files = [ 430 | {file = "ManimPango-0.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b3309536038e11a4020bf5422d36b691e5583d38f616311c75527faa853fa948"}, 431 | {file = "ManimPango-0.5.0-cp310-cp310-win32.whl", hash = "sha256:7e301f0d2ceeb05b82dbb5ddd1e2397b6de7ef4ab556d04c0765eb29f18be981"}, 432 | {file = "ManimPango-0.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:26053a59e352c11e33fa224be6fde095a08c9db2665895ada7689fdeb225064c"}, 433 | {file = "ManimPango-0.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8a866a03c8a569dfaf08035748aea5c56f5e729d12682aae5d25fbe837a6270"}, 434 | {file = "ManimPango-0.5.0-cp311-cp311-win32.whl", hash = "sha256:5de05ac673b1ac597cc3e4e0e05756195b387f8f96b81cd03767a9f12f8af3f4"}, 435 | {file = "ManimPango-0.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:86e68c085e455d4bd607c2f63fcce41d1496a873dde29c413a3fbd98ff99c258"}, 436 | {file = "ManimPango-0.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bf4a09fe1989763ea041fcce044ce501d89678bcc14084949f6792fc3b204517"}, 437 | {file = "ManimPango-0.5.0-cp312-cp312-win32.whl", hash = "sha256:0b5e47755cce7848fa268b5f77f17fc4fe363d30f5412fef845560df26dece82"}, 438 | {file = "ManimPango-0.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:aef7151c210fce42518eff7a00e4b07d497a2516e13945d56b9b4a6427fae3f6"}, 439 | {file = "ManimPango-0.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f1b614dc33b1cc012ef38a49b04def005e80a14592bdd389be91a9073a71be30"}, 440 | {file = "ManimPango-0.5.0-cp38-cp38-win32.whl", hash = "sha256:d135fbc2049b3cb22fa941e7333c10a42b29aa080871dd4e80d169da2337b797"}, 441 | {file = "ManimPango-0.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:9bb032625d5c663c4727bae61870e3c16696278c569c98a094b14953f22a70c8"}, 442 | {file = "ManimPango-0.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d58e736ccf2afb3398c42ad1d478b84176785ad19cb994dfc9575030bfd040f"}, 443 | {file = "ManimPango-0.5.0-cp39-cp39-win32.whl", hash = "sha256:8c453e9511d5888c92aa1f7b120b7f3318fc21fd7a4862156c9b094986f2e17d"}, 444 | {file = "ManimPango-0.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:b81d815b1a5e78376ae9b6aa2d7606d38cc19e31eb89480471462bbdf0fcd3c7"}, 445 | {file = "ManimPango-0.5.0.tar.gz", hash = "sha256:299913bbccb0f15954b64401cf9df24607e1a01edda589ea77de1ed4cc2bc284"}, 446 | ] 447 | 448 | [[package]] 449 | name = "mapbox-earcut" 450 | version = "1.0.1" 451 | description = "Python bindings for the mapbox earcut C++ polygon triangulation library." 452 | optional = false 453 | python-versions = "*" 454 | files = [ 455 | {file = "mapbox_earcut-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:60f8299b724b5ad1f171c2666a12591845536b0e9318ddc9649f75805096686c"}, 456 | {file = "mapbox_earcut-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4af0911ed9d1920c36c54b500ea69fbcc948f409c66f632c75b15fee04c7544e"}, 457 | {file = "mapbox_earcut-1.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:584fd2f7de878f14b3268257ec3c55bac146f1adc1887a64f0ecbf91ee39489f"}, 458 | {file = "mapbox_earcut-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20929541c1c9f5fefde45c6c33e8ed3138c7bdd1034ced998877913878f3457c"}, 459 | {file = "mapbox_earcut-1.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48e8d8ebadd4e4d0dfd87374d43ca3caf8c8e692f1b6897588594d12527d5020"}, 460 | {file = "mapbox_earcut-1.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:352f92997fd39024919a258db29df1642dd98632807ca96e737242adf64b5e96"}, 461 | {file = "mapbox_earcut-1.0.1-cp310-cp310-win32.whl", hash = "sha256:5cf359c5ae1a5dcdd6d9c150ec43a820a289c28596ae7c52de09075543cc19ae"}, 462 | {file = "mapbox_earcut-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f5cd49d6e13b3627c6cd6d3a945285e1ce7e9b193f3ce5ca53f0b7b86acd41e"}, 463 | {file = "mapbox_earcut-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1e02d61d01aa1239ffbe1b8384cdc224d7c67db604eb7bfc34dd39fb1dc515c2"}, 464 | {file = "mapbox_earcut-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d170d0a79b4ef3c9591ec6727a0ab35bae9e267b389122365343d6f55f9027a0"}, 465 | {file = "mapbox_earcut-1.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78945356229992d7aa6da750059f401f329651adc76c000505a0e9e4f93be5df"}, 466 | {file = "mapbox_earcut-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66cf29a2434d3366889c69fc50e6d2f9f1abf3a8a4154c7e03ef8f180d3bea40"}, 467 | {file = "mapbox_earcut-1.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a73f6f422932b2758b03f78e92aa5c4d5b5f7ce6456483f5993f4677b0bbde23"}, 468 | {file = "mapbox_earcut-1.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9af9369266bf0ca32f4d401152217c46c699392513f22639c6b1be32bde9c1cc"}, 469 | {file = "mapbox_earcut-1.0.1-cp311-cp311-win32.whl", hash = "sha256:ff9a13be4364625697b0e0e04ba6a0f77300148b871bba0a85bfa67e972e85c4"}, 470 | {file = "mapbox_earcut-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e736557539c74fa969e866889c2b0149fc12668f35e3ae33667d837ff2880d3"}, 471 | {file = "mapbox_earcut-1.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4fe92174410e4120022393013705d77cb856ead5bdf6c81bec614a70df4feb5d"}, 472 | {file = "mapbox_earcut-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:082f70a865c6164a60af039aa1c377073901cf1f94fd37b1c5610dfbae2a7369"}, 473 | {file = "mapbox_earcut-1.0.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43d268ece49d0c9e22cb4f92cd54c2cc64f71bf1c5e10800c189880d923e1292"}, 474 | {file = "mapbox_earcut-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7748f1730fd36dd1fcf0809d8f872d7e1ddaa945f66a6a466ad37ef3c552ae93"}, 475 | {file = "mapbox_earcut-1.0.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5a82d10c8dec2a0bd9a6a6c90aca7044017c8dad79f7e209fd0667826f842325"}, 476 | {file = "mapbox_earcut-1.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:01b292588cd3f6bad7d76ee31c004ed1b557a92bbd9602a72d2be15513b755be"}, 477 | {file = "mapbox_earcut-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fce236ddc3a56ea7260acc94601a832c260e6ac5619374bb2cec2e73e7414ff0"}, 478 | {file = "mapbox_earcut-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:1ce86407353b4f09f5778c436518bbbc6f258f46c5736446f25074fe3d3a3bd8"}, 479 | {file = "mapbox_earcut-1.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:aa6111a18efacb79c081f3d3cdd7d25d0585bb0e9f28896b207ebe1d56efa40e"}, 480 | {file = "mapbox_earcut-1.0.1-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2911829d1e6e5e1282fbe2840fadf578f606580f02ed436346c2d51c92f810b"}, 481 | {file = "mapbox_earcut-1.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01ff909a7b8405a923abedd701b53633c997cc2b5dc9d5b78462f51c25ec2c33"}, 482 | {file = "mapbox_earcut-1.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:b7e73477b4ef3951ef5c32848126f047ac7fd2dd04dc033444a85261a346ed08"}, 483 | {file = "mapbox_earcut-1.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:dae325af3553afa4d0ca0caa5afe57dc3d2e3a90a51dfbabc49a5ce1ea1009f7"}, 484 | {file = "mapbox_earcut-1.0.1-cp36-cp36m-win32.whl", hash = "sha256:29f8f746a9c68f1509084b0c78227d4e142241a2e30aab6def872e53a46f7281"}, 485 | {file = "mapbox_earcut-1.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:3c487b93b0e1059b404be4daea62c22cfc8054ffd88591377848c8e399d4abeb"}, 486 | {file = "mapbox_earcut-1.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f85f8d95503dba4612a2dd5c076ed18845a46cea4ba38660e4929efccb5a594a"}, 487 | {file = "mapbox_earcut-1.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8ade6c4822be1680c933bda32af0bb23a73e63e951db348ac1adef8de137239"}, 488 | {file = "mapbox_earcut-1.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04431a498a836c62aba5d807572daf3c8b064b25ab83e79994498455524ce517"}, 489 | {file = "mapbox_earcut-1.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:714d33603c59d7306650615d7b05d51da273f1aa5b41c3b462207271a2283fa7"}, 490 | {file = "mapbox_earcut-1.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:065faa6b4a7525faa48e46e692176cbcf9587ade7a1abdb2c96cb6477ab0004d"}, 491 | {file = "mapbox_earcut-1.0.1-cp37-cp37m-win32.whl", hash = "sha256:9f433276f54e302aa0c3ef0f8edb7a4092cdd677aafc623fab2b81e1db9f2729"}, 492 | {file = "mapbox_earcut-1.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2ac93a18a19acffaa7dc42646534f3850b545d6ad31469f3b7157efc9da113db"}, 493 | {file = "mapbox_earcut-1.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b23d0b41d5d7e72fa197e981c3e317f234336b4594bb64252837a0558c9c505d"}, 494 | {file = "mapbox_earcut-1.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:57337d9cf95a97b926eab57845525501df61abb0334ed59502a6485cf9216f64"}, 495 | {file = "mapbox_earcut-1.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5447f35b1dda5f89a6d5c95e9a1831f1c5aaf1eeac853f0b2f3df97ec81c2c75"}, 496 | {file = "mapbox_earcut-1.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffb3e2a0253e3e2e1b7638df80a029d4d80f38db42a7736f92a8e8d4d1a3209"}, 497 | {file = "mapbox_earcut-1.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:202761e67b0974b1618e638b83a1bb24d0a421a0c773435833a368b9b4f0ee2b"}, 498 | {file = "mapbox_earcut-1.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9c37424997c46f45f16a8ec42fc892a011f9528257f207e2aae4bd14cfcd7c3d"}, 499 | {file = "mapbox_earcut-1.0.1-cp38-cp38-win32.whl", hash = "sha256:ed5ec84c85a6e6cbfa294bdcbf567d3fa0abec9191acc8f362552946b8b7b398"}, 500 | {file = "mapbox_earcut-1.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:da5eeb66f50b01e77340b00f29867fa89df4b9e28646f9a0b8f6b5c8827515fd"}, 501 | {file = "mapbox_earcut-1.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eb4aa9a7d1c5f92458d73f460d1f063fbcb38c50ff1f0b7e3485b8dc0f1f6635"}, 502 | {file = "mapbox_earcut-1.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7f779084b11bd74be374be69054803ac36095a68d1a0da1d499a47d3c7f7ccc"}, 503 | {file = "mapbox_earcut-1.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5190425932e82e22e3e35dfb892f5eb441aef155c45fa055da027c72c124b3d1"}, 504 | {file = "mapbox_earcut-1.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d68b47dc4ab2aaa9ec163c18bc6133c74739990b5013d17e13bac2d1b5c9afea"}, 505 | {file = "mapbox_earcut-1.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1b737d4b7b1c52c3915b898714e036990149a422343ec1481ac66b35df17f24"}, 506 | {file = "mapbox_earcut-1.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3b77f444324a3b0e91ba2b4b2d533a66503f8fb7103e4901d0064ec2413bff8c"}, 507 | {file = "mapbox_earcut-1.0.1-cp39-cp39-win32.whl", hash = "sha256:db61cec2374ff063e314c40b3a868237d2af1b0d98f3ec1217bc0f881e7cc40a"}, 508 | {file = "mapbox_earcut-1.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:86b8c3732fb93f4e8ed8b1cc8388b93a72d0e9755a00f324e780b15a00fe5bc0"}, 509 | {file = "mapbox_earcut-1.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0b5ad819f3fd57fc8a18c7b61a244e63b2a24475195f57e826a066e007a7a877"}, 510 | {file = "mapbox_earcut-1.0.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:732e5c86037692f6c635dc4e139520be8366cde0fd39dbe122480f657b2cca90"}, 511 | {file = "mapbox_earcut-1.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cf7c0d0d862addc99fe0b33150c8f5c06baafa320b6dd6f67d17309512d1e9a"}, 512 | {file = "mapbox_earcut-1.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8416071bd3af616afab4513347b064274899f73e0ffe309c2a1be66600736c98"}, 513 | {file = "mapbox_earcut-1.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1310c3e208e0bfd6da090ae65226ee49adba4078fe1ed2d95197c3b97ad513b9"}, 514 | {file = "mapbox_earcut-1.0.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b657a30f677de4005f497c79ab3bb2827ba01e2642cb58ac30242f7cff48e40b"}, 515 | {file = "mapbox_earcut-1.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34e3476d9af878887fd0d9cce759d6951fe0cc6c240e13afed1ff38fc23fc9d5"}, 516 | {file = "mapbox_earcut-1.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e480ce4794b0c391f0b829362c78ec74b690104ef36866160a7e14232b2d3779"}, 517 | {file = "mapbox_earcut-1.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c21271dd89263d037af5caeac425e54a8fba727ea30d1b42e3ce94cc675df15a"}, 518 | {file = "mapbox_earcut-1.0.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11c784ba52c981dcf709bcc8de99d75a214a476f7c16369d219ca4751c7f6f6f"}, 519 | {file = "mapbox_earcut-1.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be37a75c94017a2efaffc8763475867d4860fc4cb3262b6839d635690403d28f"}, 520 | {file = "mapbox_earcut-1.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ad50f947d44c8c1c0900c3e1869a4a550509450117b87b0368b06014f66590b"}, 521 | {file = "mapbox_earcut-1.0.1.tar.gz", hash = "sha256:9f155e429a22e27387cfd7a6372c3a3865aafa609ad725e2c4465257f154a438"}, 522 | ] 523 | 524 | [package.dependencies] 525 | numpy = "*" 526 | 527 | [package.extras] 528 | test = ["pytest"] 529 | 530 | [[package]] 531 | name = "markdown-it-py" 532 | version = "3.0.0" 533 | description = "Python port of markdown-it. Markdown parsing, done right!" 534 | optional = false 535 | python-versions = ">=3.8" 536 | files = [ 537 | {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, 538 | {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, 539 | ] 540 | 541 | [package.dependencies] 542 | mdurl = ">=0.1,<1.0" 543 | 544 | [package.extras] 545 | benchmarking = ["psutil", "pytest", "pytest-benchmark"] 546 | code-style = ["pre-commit (>=3.0,<4.0)"] 547 | compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] 548 | linkify = ["linkify-it-py (>=1,<3)"] 549 | plugins = ["mdit-py-plugins"] 550 | profiling = ["gprof2dot"] 551 | rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] 552 | testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] 553 | 554 | [[package]] 555 | name = "mdurl" 556 | version = "0.1.2" 557 | description = "Markdown URL utilities" 558 | optional = false 559 | python-versions = ">=3.7" 560 | files = [ 561 | {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, 562 | {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, 563 | ] 564 | 565 | [[package]] 566 | name = "moderngl" 567 | version = "5.10.0" 568 | description = "ModernGL: High performance rendering for Python 3" 569 | optional = false 570 | python-versions = ">=3.7" 571 | files = [ 572 | {file = "moderngl-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec38a4883bbfa9a094b7fec8f37c5aed031df0e060ff5451842bd4db9e30f340"}, 573 | {file = "moderngl-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:461b4185b56fc318d42f965160809f08955b8e857545c99cfa89a6734044d256"}, 574 | {file = "moderngl-5.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:046a85cc3cffbdac5a45ed53c8f10c601e4737a172e3c1307a05b3693733d6e0"}, 575 | {file = "moderngl-5.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111dd17837ec3a62a38fb8fb78376a09dcb39910554ed0df45fbb3db84d1db4e"}, 576 | {file = "moderngl-5.10.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:72dc0169e3264391905cebd11ed379ba45724329cebc9cd32b2d928f3a33ed5a"}, 577 | {file = "moderngl-5.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf4814039f365c0ad9da00fb8fb884fdce0d4e63bb042a8c1c551bce13d0ff06"}, 578 | {file = "moderngl-5.10.0-cp310-cp310-win32.whl", hash = "sha256:33b0bbd26319cdef724326997484768eb092f223245edc394541cafe59523568"}, 579 | {file = "moderngl-5.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:28c45e477cc2e47189bc6696b73777072d4c76ad59de4f8fd027ba5c6561b2c0"}, 580 | {file = "moderngl-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d31c49eb5ffeddb62d6d2b09737d7d7713faa8bc4eb293623cc625f0b4ed6020"}, 581 | {file = "moderngl-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ded56b6a182b216bdd63d63b6d373c4f4a58f20816e71c53d555cde9fba366d6"}, 582 | {file = "moderngl-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd105d15c7b73ba972d0bbf962cd2bbb762b9937fdfdd658990c7c9d2805e183"}, 583 | {file = "moderngl-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9e853e869c421632572a0fda929131f2c7a290ad50f45dcbcbcebca78b0d688"}, 584 | {file = "moderngl-5.10.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:61cd81ec6914745e416c2d9feec25541a9f800aeb387952ec73569ced3054ff9"}, 585 | {file = "moderngl-5.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:164d03e4a54d36cfa17165e1aa61f321068b84b5792e55490b447929bcdf973c"}, 586 | {file = "moderngl-5.10.0-cp311-cp311-win32.whl", hash = "sha256:cd11dbe2b598ff4e43424120b6bf9f222a4be095be1d37b0ea43b208937a7e67"}, 587 | {file = "moderngl-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:996e2963df7b9d0d82cedc80e970f4cbf214cc98b09d14cc2681f2e786477367"}, 588 | {file = "moderngl-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1996348331a458d79e60efe6c21e9b1997f338913cd441a4b40635f8202ffed5"}, 589 | {file = "moderngl-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9d4c3199ec68ab6dfaa931c1f851897d00b7cfc8df20fcfdb5d36427ee74d19"}, 590 | {file = "moderngl-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d37297241bd819f2e70747fdac3b8e8d12e1ace06078baea53164fa5b6f2c5a8"}, 591 | {file = "moderngl-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6421d352685fe3f54641efb03c7f10f1c8e9e99739ccb6f09cd7fded13cf6530"}, 592 | {file = "moderngl-5.10.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:249e9e2e82f8ef8f8167ddede17e19c9255d81b3327e3e875842fa4779b8bbc7"}, 593 | {file = "moderngl-5.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:51e7732ae0af7cb367db3f211808aeacde4d4d02da09a5e1413c7a505f44b63a"}, 594 | {file = "moderngl-5.10.0-cp312-cp312-win32.whl", hash = "sha256:fbf3cf3034271d5cff7fe7002a05fd2b6277beee9daf9d47d7772e62daf29a8a"}, 595 | {file = "moderngl-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:e92ab93fb4d948879b8a0d2d2905493015f1f4ffb7b43aa3d9c9c88e26daa393"}, 596 | {file = "moderngl-5.10.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ae28c3ca47724c023de886afc205cb73afdd5fb8593514bb58b6181504958580"}, 597 | {file = "moderngl-5.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17ea8080802252b0bed60bf0490321c8c6a0d4cfad4b0924e967a7c802c6396e"}, 598 | {file = "moderngl-5.10.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160fcabf2a98057608fdde72105f23495d204dd643aab1083ed8f775fde70a25"}, 599 | {file = "moderngl-5.10.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:64ede63c5b0eb598c8d4c4afc7bd1d257522f11d78765749c248f96a2994c3a4"}, 600 | {file = "moderngl-5.10.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3e4de1d3fffb39b6d790b3713602f05772976e2cb2c6ad4eb91dd0ce19689906"}, 601 | {file = "moderngl-5.10.0-cp37-cp37m-win32.whl", hash = "sha256:79803b3e475b9b9eb87ebe02ccde9694b4a3aa0d988894a35e571b6c265199d6"}, 602 | {file = "moderngl-5.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d0b8df2d54cd81ff95a2281f88331fadce9a58b340bc03b74d178eca760805f4"}, 603 | {file = "moderngl-5.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d9db7aa884a561d912a0d545d38d0d2dfe587ed8230271fac3143af5141349fe"}, 604 | {file = "moderngl-5.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81a287198055d2818571976e920b32975e13e1bcdbaf51ca2e13ef314b3479b2"}, 605 | {file = "moderngl-5.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d116513974c7f2177cab352678d8db1f3181385000bd10c6c2d8e3892c4a2c3"}, 606 | {file = "moderngl-5.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01a932fb195fd48a3a9e850397b6b952f48aa238f9da24073730f53c31773665"}, 607 | {file = "moderngl-5.10.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6cdb4f9542536b1e23a30f5049eced10010568ff6762b381c5ee47f18d4885be"}, 608 | {file = "moderngl-5.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3dc94d9ca08d712650ca465ca355bab49ad2a3a2ab4841f90f00cc575c09d760"}, 609 | {file = "moderngl-5.10.0-cp38-cp38-win32.whl", hash = "sha256:5f00c5e8e94d4fc8e74bc0e91ce120e5b83c9d470d33db96f2ccd54d8ffd84bf"}, 610 | {file = "moderngl-5.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:90b29cf49cb9fb95176446489d9c448f9bf21d683d66b09f9f3fffcb1dbd7aed"}, 611 | {file = "moderngl-5.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8a0957053488983e853e881e4d7b1bb5cec8208956dfbe9fb6e1454113d3921"}, 612 | {file = "moderngl-5.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c3600f33d453b77c3f577f46585807eab3a7c14d9b4555c6c553ee883794223"}, 613 | {file = "moderngl-5.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a28a10cce3656768f1fb1f1a49a87b2b0803f30e775a9605ce2875f5ae3d740a"}, 614 | {file = "moderngl-5.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02828648a362ac6d399f4babeb156cf1ccdc94053c94c9d80cbf436365f15877"}, 615 | {file = "moderngl-5.10.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5dd8802df9e33e035ff11428a0b813ce9d3ba7e6c852685b30dbe6d6ecf78219"}, 616 | {file = "moderngl-5.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:72e3e9a5d6fb7ae25d091603b3770e53c6f0f148a2ce82a6d7c0dcd50c03f221"}, 617 | {file = "moderngl-5.10.0-cp39-cp39-win32.whl", hash = "sha256:6ab3d8848d926cb5768daef7b15b596f833f4a699ff9c87f92f264da9cfd5f8d"}, 618 | {file = "moderngl-5.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:3fd5e3ff2eda7d8152e2191d281ed9744708789049c9feaf32e3f8480ad36ac6"}, 619 | {file = "moderngl-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d40c48e3d4af310807d10be4952b67d390aef83d9c1188a4562724b137381cd8"}, 620 | {file = "moderngl-5.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4e02ba34dee05bce0c6f13eff2b705f12d8b869156d16ac39146616b7b8fd75"}, 621 | {file = "moderngl-5.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a71dcaa94b2d9d89cff53d76b7b7ba8b98b9c98983851968710d143c29260b"}, 622 | {file = "moderngl-5.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6933e00279414ea82487262b1418843c813770d34f3b49ffa491a489629d83a8"}, 623 | {file = "moderngl-5.10.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8d2b579e151a68e96f46962c85dcb0ef87c1eef78f9997a1eb38c93a05d78105"}, 624 | {file = "moderngl-5.10.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8762385bc961c3e8c4d62ee3d565b70699df69674613c8815cc6a72260a455b"}, 625 | {file = "moderngl-5.10.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3b2d4d631b0119790d3fc56a9dd6047aa5bc302b5851c0cec5e7504e6ebf5fc"}, 626 | {file = "moderngl-5.10.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:319e8a5baf1fc681b541666bbbb3eb3df0bd127be96ffd751bc995cef7c1ffe3"}, 627 | {file = "moderngl-5.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:744a4c1c6c5cd959046f000b1d0af2ec5f8e75df115b91a1e4aa07a67f531520"}, 628 | {file = "moderngl-5.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf92d9645f390ac3caa2d21388c04952b6df64694199bfdfcb1bad512c530bb"}, 629 | {file = "moderngl-5.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70964094e98a7209a566c17264b70c9a075a11d7181d943742bfc86e2baa334d"}, 630 | {file = "moderngl-5.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ed976286ff722d4de657dcad0bc14a89a07671ef1ba797b89592e733956600a3"}, 631 | {file = "moderngl-5.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea8bac3464cfe63f910b76cc55f2f11194fe2325fed43edb63bed33b4aee1756"}, 632 | {file = "moderngl-5.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e5e88ed0192f15600cc810726a47508a5cc97f3ddfc33aa381c8d9f2d58d54a"}, 633 | {file = "moderngl-5.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee4777d2630b575ab5a5dd109b3ab24312e9ea793b8d5a3453f23f16a92a1851"}, 634 | {file = "moderngl-5.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6ce7020588529aba4ea8b55c0861e93f997b4a2cf310eef990942cc5fa1ec8fa"}, 635 | {file = "moderngl-5.10.0.tar.gz", hash = "sha256:119c8d364dde3cd8d1c09f237ed4916617ba759954a1952df4694e51ee4f6511"}, 636 | ] 637 | 638 | [package.dependencies] 639 | glcontext = ">=2.5.0,<3" 640 | 641 | [[package]] 642 | name = "moderngl-window" 643 | version = "2.4.4" 644 | description = "A cross platform helper library for ModernGL making window creation and resource loading simple" 645 | optional = false 646 | python-versions = ">=3.7" 647 | files = [ 648 | {file = "moderngl-window-2.4.4.tar.gz", hash = "sha256:66a9c5412b5eb0a5ca7cda351e4484ce02a167cf87eb4dc59bb82439c58130b5"}, 649 | {file = "moderngl_window-2.4.4-py3-none-any.whl", hash = "sha256:fddbca24afc3c7faaf98af7d1d45aa6b812a9a12e66401cb26284d645c4bb026"}, 650 | ] 651 | 652 | [package.dependencies] 653 | moderngl = "<6" 654 | numpy = ">=1.16,<2" 655 | Pillow = ">=9,<10" 656 | pyglet = ">=2.0dev23" 657 | pyrr = ">=0.10.3,<1" 658 | 659 | [package.extras] 660 | glfw = ["glfw"] 661 | pygame = ["pygame (>=2.1.2)"] 662 | pyqt5 = ["PyQt5"] 663 | pysdl2 = ["PySDL2"] 664 | pyside2 = ["PySide2 (<6)"] 665 | pywavefront = ["pywavefront (>=1.3.3,<2)"] 666 | tk = ["pyopengltk (>=0.0.3)"] 667 | trimesh = ["scipy (>=1.3.2)", "trimesh (>=3.2.6,<4)"] 668 | 669 | [[package]] 670 | name = "multipledispatch" 671 | version = "1.0.0" 672 | description = "Multiple dispatch" 673 | optional = false 674 | python-versions = "*" 675 | files = [ 676 | {file = "multipledispatch-1.0.0-py3-none-any.whl", hash = "sha256:0c53cd8b077546da4e48869f49b13164bebafd0c2a5afceb6bb6a316e7fb46e4"}, 677 | {file = "multipledispatch-1.0.0.tar.gz", hash = "sha256:5c839915465c68206c3e9c473357908216c28383b425361e5d144594bf85a7e0"}, 678 | ] 679 | 680 | [[package]] 681 | name = "networkx" 682 | version = "3.2.1" 683 | description = "Python package for creating and manipulating graphs and networks" 684 | optional = false 685 | python-versions = ">=3.9" 686 | files = [ 687 | {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, 688 | {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, 689 | ] 690 | 691 | [package.extras] 692 | default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] 693 | developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] 694 | doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] 695 | extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] 696 | test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] 697 | 698 | [[package]] 699 | name = "numpy" 700 | version = "1.26.4" 701 | description = "Fundamental package for array computing in Python" 702 | optional = false 703 | python-versions = ">=3.9" 704 | files = [ 705 | {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, 706 | {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, 707 | {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, 708 | {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, 709 | {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, 710 | {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, 711 | {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, 712 | {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, 713 | {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, 714 | {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, 715 | {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, 716 | {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, 717 | {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, 718 | {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, 719 | {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, 720 | {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, 721 | {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, 722 | {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, 723 | {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, 724 | {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, 725 | {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, 726 | {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, 727 | {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, 728 | {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, 729 | {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, 730 | {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, 731 | {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, 732 | {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, 733 | {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, 734 | {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, 735 | {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, 736 | {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, 737 | {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, 738 | {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, 739 | {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, 740 | {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, 741 | ] 742 | 743 | [[package]] 744 | name = "packaging" 745 | version = "24.0" 746 | description = "Core utilities for Python packages" 747 | optional = false 748 | python-versions = ">=3.7" 749 | files = [ 750 | {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, 751 | {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, 752 | ] 753 | 754 | [[package]] 755 | name = "pillow" 756 | version = "9.5.0" 757 | description = "Python Imaging Library (Fork)" 758 | optional = false 759 | python-versions = ">=3.7" 760 | files = [ 761 | {file = "Pillow-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16"}, 762 | {file = "Pillow-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa"}, 763 | {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38"}, 764 | {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062"}, 765 | {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e"}, 766 | {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5"}, 767 | {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d"}, 768 | {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903"}, 769 | {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a"}, 770 | {file = "Pillow-9.5.0-cp310-cp310-win32.whl", hash = "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44"}, 771 | {file = "Pillow-9.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb"}, 772 | {file = "Pillow-9.5.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32"}, 773 | {file = "Pillow-9.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c"}, 774 | {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3"}, 775 | {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a"}, 776 | {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1"}, 777 | {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99"}, 778 | {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625"}, 779 | {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579"}, 780 | {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296"}, 781 | {file = "Pillow-9.5.0-cp311-cp311-win32.whl", hash = "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec"}, 782 | {file = "Pillow-9.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4"}, 783 | {file = "Pillow-9.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089"}, 784 | {file = "Pillow-9.5.0-cp312-cp312-win32.whl", hash = "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb"}, 785 | {file = "Pillow-9.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b"}, 786 | {file = "Pillow-9.5.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906"}, 787 | {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf"}, 788 | {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78"}, 789 | {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270"}, 790 | {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392"}, 791 | {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47"}, 792 | {file = "Pillow-9.5.0-cp37-cp37m-win32.whl", hash = "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7"}, 793 | {file = "Pillow-9.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6"}, 794 | {file = "Pillow-9.5.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597"}, 795 | {file = "Pillow-9.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c"}, 796 | {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a"}, 797 | {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082"}, 798 | {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf"}, 799 | {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf"}, 800 | {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51"}, 801 | {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96"}, 802 | {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f"}, 803 | {file = "Pillow-9.5.0-cp38-cp38-win32.whl", hash = "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc"}, 804 | {file = "Pillow-9.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569"}, 805 | {file = "Pillow-9.5.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66"}, 806 | {file = "Pillow-9.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e"}, 807 | {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115"}, 808 | {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3"}, 809 | {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef"}, 810 | {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705"}, 811 | {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1"}, 812 | {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a"}, 813 | {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865"}, 814 | {file = "Pillow-9.5.0-cp39-cp39-win32.whl", hash = "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964"}, 815 | {file = "Pillow-9.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d"}, 816 | {file = "Pillow-9.5.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5"}, 817 | {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140"}, 818 | {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba"}, 819 | {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829"}, 820 | {file = "Pillow-9.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd"}, 821 | {file = "Pillow-9.5.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572"}, 822 | {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe"}, 823 | {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1"}, 824 | {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7"}, 825 | {file = "Pillow-9.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799"}, 826 | {file = "Pillow-9.5.0.tar.gz", hash = "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"}, 827 | ] 828 | 829 | [package.extras] 830 | docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] 831 | tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] 832 | 833 | [[package]] 834 | name = "pluggy" 835 | version = "1.4.0" 836 | description = "plugin and hook calling mechanisms for python" 837 | optional = false 838 | python-versions = ">=3.8" 839 | files = [ 840 | {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, 841 | {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, 842 | ] 843 | 844 | [package.extras] 845 | dev = ["pre-commit", "tox"] 846 | testing = ["pytest", "pytest-benchmark"] 847 | 848 | [[package]] 849 | name = "pycairo" 850 | version = "1.26.0" 851 | description = "Python interface for cairo" 852 | optional = false 853 | python-versions = ">=3.8" 854 | files = [ 855 | {file = "pycairo-1.26.0-cp310-cp310-win32.whl", hash = "sha256:696ba8024d2827e66e088a6e05a3b0aea30d289476bcb2ca47c9670d40900a50"}, 856 | {file = "pycairo-1.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:b6690a00fb225c19f42d76660e676aba7ae7cb18f3632cb02bce7f0d9b9c3800"}, 857 | {file = "pycairo-1.26.0-cp310-cp310-win_arm64.whl", hash = "sha256:1d54e28170a5e790269d9db4c195cca5152ff018ba7e330d0ed05d86ccc2ea7d"}, 858 | {file = "pycairo-1.26.0-cp311-cp311-win32.whl", hash = "sha256:5986b8da3e7de7ab931d7ad527938df38f75d3a3bdea2b515c786c5ca2c5093c"}, 859 | {file = "pycairo-1.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:d374d9ec6d2f791bf57105d87a9028db1ef2b687848f64a524e447033eae7229"}, 860 | {file = "pycairo-1.26.0-cp311-cp311-win_arm64.whl", hash = "sha256:20a31af89d92ffd5fc60c08e65ff649f16e18621a14a40dbdb049fc74942d7a9"}, 861 | {file = "pycairo-1.26.0-cp312-cp312-win32.whl", hash = "sha256:d63929ab5a2f890a333f2f2f51de9f1c9fe20d1bddc982c2ca577b737448d72f"}, 862 | {file = "pycairo-1.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:8616408ae93de4824a3777ec532ea75643e4bf74e49d601062c0b1788180c962"}, 863 | {file = "pycairo-1.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:a611e4d82ad8470138bb46d465d47e8db826d9d80b6a520ccd83ee007f2073e4"}, 864 | {file = "pycairo-1.26.0-cp38-cp38-win32.whl", hash = "sha256:675578bc6d62d15ff8669f264783efc9c8c73e3a6f564b294a70fb45a2f78667"}, 865 | {file = "pycairo-1.26.0-cp38-cp38-win_amd64.whl", hash = "sha256:aac447b423b33b64119ecdd1ffebf9163b07f5401c5da50c707197efdd1c918a"}, 866 | {file = "pycairo-1.26.0-cp39-cp39-win32.whl", hash = "sha256:9fa51168010e2dfb45499df071fca2d921893f724646f3454951000a7ad0cabb"}, 867 | {file = "pycairo-1.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:3e4e18ea03122e60abe3eb611e2849859cc950083ff85d8369328eadf3df63f5"}, 868 | {file = "pycairo-1.26.0-cp39-cp39-win_arm64.whl", hash = "sha256:a8f3b567ba2ad55624a809823ccf75aff8d768c20216cb5888365f6fc695c1d2"}, 869 | {file = "pycairo-1.26.0.tar.gz", hash = "sha256:2dddd0a874fbddb21e14acd9b955881ee1dc6e63b9c549a192d613a907f9cbeb"}, 870 | ] 871 | 872 | [[package]] 873 | name = "pydub" 874 | version = "0.25.1" 875 | description = "Manipulate audio with an simple and easy high level interface" 876 | optional = false 877 | python-versions = "*" 878 | files = [ 879 | {file = "pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6"}, 880 | {file = "pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f"}, 881 | ] 882 | 883 | [[package]] 884 | name = "pyglet" 885 | version = "2.0.12" 886 | description = "pyglet is a cross-platform games and multimedia package." 887 | optional = false 888 | python-versions = ">=3.8" 889 | files = [ 890 | {file = "pyglet-2.0.12-py3-none-any.whl", hash = "sha256:b713db0f1d939040b58dbe4583f5999540623ffae9de8c7171be26ece94eaecf"}, 891 | {file = "pyglet-2.0.12.tar.gz", hash = "sha256:d7dca1742ab1b469d4a6df44c03ef0329452d005177a9cb9bb24fe7b1b603d01"}, 892 | ] 893 | 894 | [[package]] 895 | name = "pygments" 896 | version = "2.17.2" 897 | description = "Pygments is a syntax highlighting package written in Python." 898 | optional = false 899 | python-versions = ">=3.7" 900 | files = [ 901 | {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, 902 | {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, 903 | ] 904 | 905 | [package.extras] 906 | plugins = ["importlib-metadata"] 907 | windows-terminal = ["colorama (>=0.4.6)"] 908 | 909 | [[package]] 910 | name = "pyobjc-core" 911 | version = "10.1" 912 | description = "Python<->ObjC Interoperability Module" 913 | optional = false 914 | python-versions = ">=3.8" 915 | files = [ 916 | {file = "pyobjc-core-10.1.tar.gz", hash = "sha256:1844f1c8e282839e6fdcb9a9722396c1c12fb1e9331eb68828a26f28a3b2b2b1"}, 917 | {file = "pyobjc_core-10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2a72a88222539ad07b5c8be411edc52ff9147d7cef311a2c849869d7bb9603fd"}, 918 | {file = "pyobjc_core-10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fe1b9987b7b0437685fb529832876c2a8463500114960d4e76bb8ae96b6bf208"}, 919 | {file = "pyobjc_core-10.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9f628779c345d3abd0e20048fb0e256d894c22254577a81a6dcfdb92c3647682"}, 920 | {file = "pyobjc_core-10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25a9e5a2de19238787d24cfa7def6b7fbb94bbe89c0e3109f71c1cb108e8ab44"}, 921 | {file = "pyobjc_core-10.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:2d43205d3a784aa87055b84c0ec0dfa76498e5f18d1ad16bdc58a3dcf5a7d5d0"}, 922 | {file = "pyobjc_core-10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0aa9799b5996a893944999a2f1afcf1de119cab3551c169ad9f54d12e1d38c99"}, 923 | ] 924 | 925 | [[package]] 926 | name = "pyobjc-framework-cocoa" 927 | version = "10.1" 928 | description = "Wrappers for the Cocoa frameworks on macOS" 929 | optional = false 930 | python-versions = ">=3.8" 931 | files = [ 932 | {file = "pyobjc-framework-Cocoa-10.1.tar.gz", hash = "sha256:8faaf1292a112e488b777d0c19862d993f3f384f3927dc6eca0d8d2221906a14"}, 933 | {file = "pyobjc_framework_Cocoa-10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2e82c2e20b89811d92a7e6e487b6980f360b7c142e2576e90f0e7569caf8202b"}, 934 | {file = "pyobjc_framework_Cocoa-10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0860a9beb7e5c72a1f575679a6d1428a398fa19ad710fb116df899972912e304"}, 935 | {file = "pyobjc_framework_Cocoa-10.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:34b791ea740e1afce211f19334e45469fea9a48d8fce5072e146199fd19ff49f"}, 936 | {file = "pyobjc_framework_Cocoa-10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1398c1a9bebad1a0f2549980e20f4aade00c341b9bac56b4493095a65917d34a"}, 937 | {file = "pyobjc_framework_Cocoa-10.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:22be21226e223d26c9e77645564225787f2b12a750dd17c7ad99c36f428eda14"}, 938 | {file = "pyobjc_framework_Cocoa-10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0280561f4fb98a864bd23f2c480d907b0edbffe1048654f5dfab160cea8198e6"}, 939 | ] 940 | 941 | [package.dependencies] 942 | pyobjc-core = ">=10.1" 943 | 944 | [[package]] 945 | name = "pyqt6" 946 | version = "6.6.1" 947 | description = "Python bindings for the Qt cross platform application toolkit" 948 | optional = false 949 | python-versions = ">=3.6.1" 950 | files = [ 951 | {file = "PyQt6-6.6.1-cp38-abi3-macosx_10_14_universal2.whl", hash = "sha256:6b43878d0bbbcf8b7de165d305ec0cb87113c8930c92de748a11c473a6db5085"}, 952 | {file = "PyQt6-6.6.1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5aa0e833cb5a79b93813f8181d9f145517dd5a46f4374544bcd1e93a8beec537"}, 953 | {file = "PyQt6-6.6.1-cp38-abi3-win_amd64.whl", hash = "sha256:03a656d5dc5ac31b6a9ad200f7f4f7ef49fa00ad7ce7a991b9bb691617141d12"}, 954 | {file = "PyQt6-6.6.1.tar.gz", hash = "sha256:9f158aa29d205142c56f0f35d07784b8df0be28378d20a97bcda8bd64ffd0379"}, 955 | ] 956 | 957 | [package.dependencies] 958 | PyQt6-Qt6 = ">=6.6.0" 959 | PyQt6-sip = ">=13.6,<14" 960 | 961 | [[package]] 962 | name = "pyqt6-qt6" 963 | version = "6.6.2" 964 | description = "The subset of a Qt installation needed by PyQt6." 965 | optional = false 966 | python-versions = "*" 967 | files = [ 968 | {file = "PyQt6_Qt6-6.6.2-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:7ef446d3ffc678a8586ff6dc9f0d27caf4dff05dea02c353540d2f614386faf9"}, 969 | {file = "PyQt6_Qt6-6.6.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b8363d88623342a72ac17da9127dc12f259bb3148796ea029762aa2d499778d9"}, 970 | {file = "PyQt6_Qt6-6.6.2-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:8d7f674a4ec43ca00191e14945ca4129acbe37a2172ed9d08214ad58b170bc11"}, 971 | {file = "PyQt6_Qt6-6.6.2-py3-none-win_amd64.whl", hash = "sha256:5a41fe9d53b9e29e9ec5c23f3c5949dba160f90ca313ee8b96b8ffe6a5059387"}, 972 | ] 973 | 974 | [[package]] 975 | name = "pyqt6-sip" 976 | version = "13.6.0" 977 | description = "The sip module support for PyQt6" 978 | optional = false 979 | python-versions = ">=3.7" 980 | files = [ 981 | {file = "PyQt6_sip-13.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d6b5f699aaed0ac1fcd23e8fbca70d8a77965831b7c1ce474b81b1678817a49d"}, 982 | {file = "PyQt6_sip-13.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8c282062125eea5baf830c6998587d98c50be7c3a817a057fb95fef647184012"}, 983 | {file = "PyQt6_sip-13.6.0-cp310-cp310-win32.whl", hash = "sha256:fa759b6339ff7e25f9afe2a6b651b775f0a36bcb3f5fa85e81a90d3b033c83f4"}, 984 | {file = "PyQt6_sip-13.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:8f9df9f7ccd8a9f0f1d36948c686f03ce1a1281543a3e636b7b7d5e086e1a436"}, 985 | {file = "PyQt6_sip-13.6.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b9c6b6f9cfccb48cbb78a59603145a698fb4ffd176764d7083e5bf47631d8df"}, 986 | {file = "PyQt6_sip-13.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:86a7b67c64436e32bffa9c28c9f21bf14a9faa54991520b12c3f6f435f24df7f"}, 987 | {file = "PyQt6_sip-13.6.0-cp311-cp311-win32.whl", hash = "sha256:58f68a48400e0b3d1ccb18090090299bad26e3aed7ccb7057c65887b79b8aeea"}, 988 | {file = "PyQt6_sip-13.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:0dfd22cfedd87e96f9d51e0778ca2ba3dc0be83e424e9e0f98f6994d8d9c90f0"}, 989 | {file = "PyQt6_sip-13.6.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3bf03e130fbfd75c9c06e687b86ba375410c7a9e835e4e03285889e61dd4b0c4"}, 990 | {file = "PyQt6_sip-13.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:43fb8551796030aae3d66d6e35e277494071ec6172cd182c9569ab7db268a2f5"}, 991 | {file = "PyQt6_sip-13.6.0-cp312-cp312-win32.whl", hash = "sha256:13885361ca2cb2f5085d50359ba61b3fabd41b139fb58f37332acbe631ef2357"}, 992 | {file = "PyQt6_sip-13.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:24441032a29791e82beb7dfd76878339058def0e97fdb7c1cea517f3a0e6e96b"}, 993 | {file = "PyQt6_sip-13.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3075d8b325382750829e6cde6971c943352309d35768a4d4da0587459606d562"}, 994 | {file = "PyQt6_sip-13.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a6ce80bc24618d8a41be8ca51ad9f10e8bc4296dd90ab2809573df30a23ae0e5"}, 995 | {file = "PyQt6_sip-13.6.0-cp38-cp38-win32.whl", hash = "sha256:fa7b10af7488efc5e53b41dd42c0f421bde6c2865a107af7ae259aff9d841da9"}, 996 | {file = "PyQt6_sip-13.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:9adf672f9114687533a74d5c2d4c03a9a929ad5ad9c3e88098a7da1a440ab916"}, 997 | {file = "PyQt6_sip-13.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98bf954103b087162fa63b3a78f30b0b63da22fd6450b610ec1b851dbb798228"}, 998 | {file = "PyQt6_sip-13.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:39854dba35f8e5a4288da26ecb5f40b4c5ec1932efffb3f49d5ea435a7f37fb3"}, 999 | {file = "PyQt6_sip-13.6.0-cp39-cp39-win32.whl", hash = "sha256:747f6ca44af81777a2c696bd501bc4815a53ec6fc94d4e25830e10bc1391f8ab"}, 1000 | {file = "PyQt6_sip-13.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:33ea771fe777eb0d1a2c3ef35bcc3f7a286eb3ff09cd5b2fdd3d87d1f392d7e8"}, 1001 | {file = "PyQt6_sip-13.6.0.tar.gz", hash = "sha256:2486e1588071943d4f6657ba09096dc9fffd2322ad2c30041e78ea3f037b5778"}, 1002 | ] 1003 | 1004 | [[package]] 1005 | name = "pyrr" 1006 | version = "0.10.3" 1007 | description = "3D mathematical functions using NumPy" 1008 | optional = false 1009 | python-versions = "*" 1010 | files = [ 1011 | {file = "pyrr-0.10.3-py3-none-any.whl", hash = "sha256:d8af23fb9bb29262405845e1c98f7339fbba5e49323b98528bd01160a75c65ac"}, 1012 | {file = "pyrr-0.10.3.tar.gz", hash = "sha256:3c0f7b20326e71f706a610d58f2190fff73af01eef60c19cb188b186f0ec7e1d"}, 1013 | ] 1014 | 1015 | [package.dependencies] 1016 | multipledispatch = "*" 1017 | numpy = "*" 1018 | 1019 | [[package]] 1020 | name = "pytest" 1021 | version = "8.1.1" 1022 | description = "pytest: simple powerful testing with Python" 1023 | optional = false 1024 | python-versions = ">=3.8" 1025 | files = [ 1026 | {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, 1027 | {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, 1028 | ] 1029 | 1030 | [package.dependencies] 1031 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 1032 | exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} 1033 | iniconfig = "*" 1034 | packaging = "*" 1035 | pluggy = ">=1.4,<2.0" 1036 | tomli = {version = ">=1", markers = "python_version < \"3.11\""} 1037 | 1038 | [package.extras] 1039 | testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] 1040 | 1041 | [[package]] 1042 | name = "requests" 1043 | version = "2.31.0" 1044 | description = "Python HTTP for Humans." 1045 | optional = false 1046 | python-versions = ">=3.7" 1047 | files = [ 1048 | {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, 1049 | {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, 1050 | ] 1051 | 1052 | [package.dependencies] 1053 | certifi = ">=2017.4.17" 1054 | charset-normalizer = ">=2,<4" 1055 | idna = ">=2.5,<4" 1056 | urllib3 = ">=1.21.1,<3" 1057 | 1058 | [package.extras] 1059 | socks = ["PySocks (>=1.5.6,!=1.5.7)"] 1060 | use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] 1061 | 1062 | [[package]] 1063 | name = "rich" 1064 | version = "13.7.1" 1065 | description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" 1066 | optional = false 1067 | python-versions = ">=3.7.0" 1068 | files = [ 1069 | {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, 1070 | {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, 1071 | ] 1072 | 1073 | [package.dependencies] 1074 | markdown-it-py = ">=2.2.0" 1075 | pygments = ">=2.13.0,<3.0.0" 1076 | 1077 | [package.extras] 1078 | jupyter = ["ipywidgets (>=7.5.1,<9)"] 1079 | 1080 | [[package]] 1081 | name = "scipy" 1082 | version = "1.12.0" 1083 | description = "Fundamental algorithms for scientific computing in Python" 1084 | optional = false 1085 | python-versions = ">=3.9" 1086 | files = [ 1087 | {file = "scipy-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:78e4402e140879387187f7f25d91cc592b3501a2e51dfb320f48dfb73565f10b"}, 1088 | {file = "scipy-1.12.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f5f00ebaf8de24d14b8449981a2842d404152774c1a1d880c901bf454cb8e2a1"}, 1089 | {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e53958531a7c695ff66c2e7bb7b79560ffdc562e2051644c5576c39ff8efb563"}, 1090 | {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e32847e08da8d895ce09d108a494d9eb78974cf6de23063f93306a3e419960c"}, 1091 | {file = "scipy-1.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4c1020cad92772bf44b8e4cdabc1df5d87376cb219742549ef69fc9fd86282dd"}, 1092 | {file = "scipy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:75ea2a144096b5e39402e2ff53a36fecfd3b960d786b7efd3c180e29c39e53f2"}, 1093 | {file = "scipy-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:408c68423f9de16cb9e602528be4ce0d6312b05001f3de61fe9ec8b1263cad08"}, 1094 | {file = "scipy-1.12.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5adfad5dbf0163397beb4aca679187d24aec085343755fcdbdeb32b3679f254c"}, 1095 | {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3003652496f6e7c387b1cf63f4bb720951cfa18907e998ea551e6de51a04467"}, 1096 | {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b8066bce124ee5531d12a74b617d9ac0ea59245246410e19bca549656d9a40a"}, 1097 | {file = "scipy-1.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8bee4993817e204d761dba10dbab0774ba5a8612e57e81319ea04d84945375ba"}, 1098 | {file = "scipy-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a24024d45ce9a675c1fb8494e8e5244efea1c7a09c60beb1eeb80373d0fecc70"}, 1099 | {file = "scipy-1.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e7e76cc48638228212c747ada851ef355c2bb5e7f939e10952bc504c11f4e372"}, 1100 | {file = "scipy-1.12.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f7ce148dffcd64ade37b2df9315541f9adad6efcaa86866ee7dd5db0c8f041c3"}, 1101 | {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c39f92041f490422924dfdb782527a4abddf4707616e07b021de33467f917bc"}, 1102 | {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7ebda398f86e56178c2fa94cad15bf457a218a54a35c2a7b4490b9f9cb2676c"}, 1103 | {file = "scipy-1.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:95e5c750d55cf518c398a8240571b0e0782c2d5a703250872f36eaf737751338"}, 1104 | {file = "scipy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e646d8571804a304e1da01040d21577685ce8e2db08ac58e543eaca063453e1c"}, 1105 | {file = "scipy-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:913d6e7956c3a671de3b05ccb66b11bc293f56bfdef040583a7221d9e22a2e35"}, 1106 | {file = "scipy-1.12.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba1b0c7256ad75401c73e4b3cf09d1f176e9bd4248f0d3112170fb2ec4db067"}, 1107 | {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:730badef9b827b368f351eacae2e82da414e13cf8bd5051b4bdfd720271a5371"}, 1108 | {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6546dc2c11a9df6926afcbdd8a3edec28566e4e785b915e849348c6dd9f3f490"}, 1109 | {file = "scipy-1.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:196ebad3a4882081f62a5bf4aeb7326aa34b110e533aab23e4374fcccb0890dc"}, 1110 | {file = "scipy-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:b360f1b6b2f742781299514e99ff560d1fe9bd1bff2712894b52abe528d1fd1e"}, 1111 | {file = "scipy-1.12.0.tar.gz", hash = "sha256:4bf5abab8a36d20193c698b0f1fc282c1d083c94723902c447e5d2f1780936a3"}, 1112 | ] 1113 | 1114 | [package.dependencies] 1115 | numpy = ">=1.22.4,<1.29.0" 1116 | 1117 | [package.extras] 1118 | dev = ["click", "cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] 1119 | doc = ["jupytext", "matplotlib (>2)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] 1120 | test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] 1121 | 1122 | [[package]] 1123 | name = "screeninfo" 1124 | version = "0.8.1" 1125 | description = "Fetch location and size of physical screens." 1126 | optional = false 1127 | python-versions = ">=3.6.2,<4.0.0" 1128 | files = [ 1129 | {file = "screeninfo-0.8.1-py3-none-any.whl", hash = "sha256:e97d6b173856edcfa3bd282f81deb528188aff14b11ec3e195584e7641be733c"}, 1130 | {file = "screeninfo-0.8.1.tar.gz", hash = "sha256:9983076bcc7e34402a1a9e4d7dabf3729411fd2abb3f3b4be7eba73519cd2ed1"}, 1131 | ] 1132 | 1133 | [package.dependencies] 1134 | Cython = {version = "*", markers = "sys_platform == \"darwin\""} 1135 | pyobjc-framework-Cocoa = {version = "*", markers = "sys_platform == \"darwin\""} 1136 | 1137 | [[package]] 1138 | name = "setuptools" 1139 | version = "69.1.1" 1140 | description = "Easily download, build, install, upgrade, and uninstall Python packages" 1141 | optional = false 1142 | python-versions = ">=3.8" 1143 | files = [ 1144 | {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, 1145 | {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, 1146 | ] 1147 | 1148 | [package.extras] 1149 | docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] 1150 | testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] 1151 | testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] 1152 | 1153 | [[package]] 1154 | name = "skia-pathops" 1155 | version = "0.7.4" 1156 | description = "Python access to operations on paths using the Skia library" 1157 | optional = false 1158 | python-versions = ">=3.7" 1159 | files = [ 1160 | {file = "skia-pathops-0.7.4.zip", hash = "sha256:0a2fdee87b7adb018cbfa6e95ef9e4299ed63b0080be27677a30ffefbca91350"}, 1161 | {file = "skia_pathops-0.7.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1301f3c0d7656a38208098bd37a7365a5325e09d59f1875fc99738116b0bc924"}, 1162 | {file = "skia_pathops-0.7.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:19288f9128d46be2960739242aedb1be618a618350c6d8e006b3c619449e6464"}, 1163 | {file = "skia_pathops-0.7.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a4d324b4d3c3863536f0922a18d61d7c3567acd88c69109b5fb79f60f532de5"}, 1164 | {file = "skia_pathops-0.7.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f35e2ea1a43f44ccaab75dd5c782510f79f3bd478fa404a4907597ab9d5d379"}, 1165 | {file = "skia_pathops-0.7.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a7107d11947249fa6af3996e123442bfc6893dd81565fadca023f0d9f977694"}, 1166 | {file = "skia_pathops-0.7.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a5fa30b7bc525db188672f0360e633fbc14be8f1b975b2f9a105173b212c0794"}, 1167 | {file = "skia_pathops-0.7.4-cp310-cp310-win32.whl", hash = "sha256:2367a8179d823d3c3c5ccf9e889d8a96890245f31f2bbfdc16824263f7e4d2e2"}, 1168 | {file = "skia_pathops-0.7.4-cp310-cp310-win_amd64.whl", hash = "sha256:487a3d8289a31f565fb34988155797150dabe7434cfea0006ce99337f4422666"}, 1169 | {file = "skia_pathops-0.7.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b3e4c5aa986ece9f9c89f55c4c2c43b60859697602993055ac3ef75784bf996"}, 1170 | {file = "skia_pathops-0.7.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1e55be8e0de805751515fb5d707c5fe3daab73c218b30134e8c05ba104746ef"}, 1171 | {file = "skia_pathops-0.7.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c823bf270c0869ee712647a0cf03b6aeb39669211dcc44a5a3c039075fc04f3"}, 1172 | {file = "skia_pathops-0.7.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:003119e9a5f24395f134c8223c5fbc9baddecd1002ee0814287cd78a52477655"}, 1173 | {file = "skia_pathops-0.7.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0fbbd008d586cfbc98fc2b5ce45f70dab6090a787f65292d40acd43644f6d0"}, 1174 | {file = "skia_pathops-0.7.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5aa500bd39e28cdd043f8c9edcbc793a86f557c26dc3698f0981080bfec0dd67"}, 1175 | {file = "skia_pathops-0.7.4-cp311-cp311-win32.whl", hash = "sha256:5c18a6e749389885cd6a18bd06a29bd945ad8b962f81ce3761bf0b85127ffa1a"}, 1176 | {file = "skia_pathops-0.7.4-cp311-cp311-win_amd64.whl", hash = "sha256:82fbef52409db9ccad07c0504ba692f9bc0e58095f4aeb7cd35ce1d06205781a"}, 1177 | {file = "skia_pathops-0.7.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f901bf5e43caa16a783abf3cd2d595dfdfbb9a93348a452a5d9c1e143885d09a"}, 1178 | {file = "skia_pathops-0.7.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308cdf420138a7f34680e3c6e07314d335bf1796365dbbfc807c73b503d39b0e"}, 1179 | {file = "skia_pathops-0.7.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a8097c2ce9d7ea4fc0586466e62ae5bc106f7d929b61b70ad8246e104cdba67"}, 1180 | {file = "skia_pathops-0.7.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f2601a831638fe511f67ee25ef25c43724f7b3abbb2cae50d0d86d4546176c41"}, 1181 | {file = "skia_pathops-0.7.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e05be6fc8937972beb071e7d5651ed7108aa6761b02d4ae4baaefdeb4b8d3649"}, 1182 | {file = "skia_pathops-0.7.4-cp37-cp37m-win32.whl", hash = "sha256:48b6f55117c56de80cb3d986497f1556a56823cebc9be648f2bcccfa0b869a99"}, 1183 | {file = "skia_pathops-0.7.4-cp37-cp37m-win_amd64.whl", hash = "sha256:486cb9e5bcd7801450af4188d84c12a7fa8a37f6f0a05c71f917bd429deafda5"}, 1184 | {file = "skia_pathops-0.7.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74bda285e6fb4d891f24d8937479a57d29b38e69dcb735d515c63cd911cafb24"}, 1185 | {file = "skia_pathops-0.7.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee23c6f3db16f5b2b5fc8e805d57570613fa75febe3d21fb819897fa54f82081"}, 1186 | {file = "skia_pathops-0.7.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88eeaa7b4d1d86364bc63c5d88522c40113df24f1abc7be34edd22d7b137d4c6"}, 1187 | {file = "skia_pathops-0.7.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c09c8af59ae8a7bc883342c29c062a6032a7558fd31f7b852db5a4fb0d5c0545"}, 1188 | {file = "skia_pathops-0.7.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:fe58f22bc1f37af1829e38f4867bc81346272953f764bac68c05efc88bd2fbef"}, 1189 | {file = "skia_pathops-0.7.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2f0fbccd30d6778bfec3d69d28947d80432eed55a45fcbc1584331b00da4caf1"}, 1190 | {file = "skia_pathops-0.7.4-cp38-cp38-win32.whl", hash = "sha256:84f8006a3049ba4ff17d44b4bcd8b050ac8fc6630a36d56435c1ce9e8e5500a2"}, 1191 | {file = "skia_pathops-0.7.4-cp38-cp38-win_amd64.whl", hash = "sha256:be2b601133a1e7346c9ecc791ca06e37d05ed89a425d0388a5dab04863689a5b"}, 1192 | {file = "skia_pathops-0.7.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8b1e0683ab485ed9ab42dd264f30c137efa3c308727b1931dc52073a77cd1029"}, 1193 | {file = "skia_pathops-0.7.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8fde29c64cae35d3c44586cadfae0c09f4eeb2d428ebc45de2fe5c3de3a4f07"}, 1194 | {file = "skia_pathops-0.7.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b555157958a785f63744f77b7a3cd6a99a2df8bfcc43bc80fa6332d777eff84a"}, 1195 | {file = "skia_pathops-0.7.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9aa3dfb7349f78cef20cf7b1eb0ab2393aab26d403a958f5821c18d9357f3938"}, 1196 | {file = "skia_pathops-0.7.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a868cb5e943fc90e8de4f987f890004e01de238dafaec265daa684eae0af42b6"}, 1197 | {file = "skia_pathops-0.7.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:608408ac31c5eb187dae10ad29986be16a1d179ca734264b454aca1d46c2cc4b"}, 1198 | {file = "skia_pathops-0.7.4-cp39-cp39-win32.whl", hash = "sha256:4da2d43512b07ba913ab2f3f0f64f80590b366c3aca3a3f35605568c9997a9ad"}, 1199 | {file = "skia_pathops-0.7.4-cp39-cp39-win_amd64.whl", hash = "sha256:8e701fa2c0535d428e93b145c7be0a0c41b8ec9a203256c378e66d8052d0e29d"}, 1200 | {file = "skia_pathops-0.7.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36f8eaa534d6e38e788fec9157efb11093d5de2c1cfec0d350c3e1af097a043d"}, 1201 | {file = "skia_pathops-0.7.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f63cfc73dc1f20e5ef5bdd766022c70491e2ab73c8d6b3cc1f8ca2c28c9114d7"}, 1202 | {file = "skia_pathops-0.7.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d47d48192241688609f2194273d89266bcd18c45426af417991634fc811bf37"}, 1203 | ] 1204 | 1205 | [package.extras] 1206 | testing = ["coverage", "pytest", "pytest-randomly", "pytest-xdist"] 1207 | 1208 | [[package]] 1209 | name = "skia-pathops" 1210 | version = "0.8.0.post1" 1211 | description = "Python access to operations on paths using the Skia library" 1212 | optional = false 1213 | python-versions = ">=3.8" 1214 | files = [ 1215 | {file = "skia-pathops-0.8.0.post1.zip", hash = "sha256:a056249de2f61fa55116b9ee55513c6a36b878aee00c91450e404d1606485cbb"}, 1216 | {file = "skia_pathops-0.8.0.post1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:952a03a19e687caa341ce6966eac03b167de8faea48574d3cf4bb758c2cefcfb"}, 1217 | {file = "skia_pathops-0.8.0.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:003efdbbc4400fffba00e0f9523b6b762269d7e257a6ad45cefbe4844fe04e4a"}, 1218 | {file = "skia_pathops-0.8.0.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77e8b60380a94bc277a50177f70392646e0cce83c5c8fa8ab5817d813eef0224"}, 1219 | {file = "skia_pathops-0.8.0.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d7b3361338f80bea1529698c2c66df1bdffc89339b90257d9a8e8e1cbda7f2c"}, 1220 | {file = "skia_pathops-0.8.0.post1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ccd03685b08e2ba7e65005911f0eac224eec3eabff18f9aeb8d757188dc5cbb"}, 1221 | {file = "skia_pathops-0.8.0.post1-cp310-cp310-win32.whl", hash = "sha256:e273b565544b801219bbea6b32c5b1f3f9c2ce4f43870700a859174aa1f6564b"}, 1222 | {file = "skia_pathops-0.8.0.post1-cp310-cp310-win_amd64.whl", hash = "sha256:35b3f990e9f0fc861e962b9bca959ab0de68c095959e0dccc21d7e5076141c12"}, 1223 | {file = "skia_pathops-0.8.0.post1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:934fafd7e8552b40cf7c6a02b8d3b40ead6dff2f2c0426a26e4b9a031b880a65"}, 1224 | {file = "skia_pathops-0.8.0.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db4e3a9af2bbd76d2522909cf6d32c84a0a5c6e1f8d3eff18305a960b3645293"}, 1225 | {file = "skia_pathops-0.8.0.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8973b7dccc96a9273b529f1ccea70f6d05e5b4ff90d0fe7e424a4fcff2134bd6"}, 1226 | {file = "skia_pathops-0.8.0.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27861201a5eabcd50b1d4c94be9cd28749d9236cbbab797e5ca6a293b6c15178"}, 1227 | {file = "skia_pathops-0.8.0.post1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30cb3286ff91325f1ae452f9d1bc58b92e4a5c5beeca3bd17b269c6376a0dbfa"}, 1228 | {file = "skia_pathops-0.8.0.post1-cp311-cp311-win32.whl", hash = "sha256:960a387300550a4fed0a66d5c29d26a02d9df965caf9e5ccd1eeef4e225b06c6"}, 1229 | {file = "skia_pathops-0.8.0.post1-cp311-cp311-win_amd64.whl", hash = "sha256:8235e313199be4b250ed32799d3de5a4be7ed60ecd62f19d426518814e6853a7"}, 1230 | {file = "skia_pathops-0.8.0.post1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3dc8febcb792c2542f05e12a3cee409ae421cdf865878c19d7b525291fa93348"}, 1231 | {file = "skia_pathops-0.8.0.post1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25fd0e8a18bc021f5b0b9cab37d607ea5c61f503b9e860d223906954b0c53c43"}, 1232 | {file = "skia_pathops-0.8.0.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9005f5dc5b162cac0d782e9adb5ecb304ab7ae5c873d2ed2a9895e89bf660ee2"}, 1233 | {file = "skia_pathops-0.8.0.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7b6873b65b682f8cf94a3baf8fccf98219f689e09a08967075bda36da128d57"}, 1234 | {file = "skia_pathops-0.8.0.post1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a4f111f55811ab9f8cb4ee057823db95355c8a424a2c2272ccda56ec0c48ba4"}, 1235 | {file = "skia_pathops-0.8.0.post1-cp312-cp312-win32.whl", hash = "sha256:69ff7abe4ba02b0c7159ae04d8173b4186336f3809d512e660f5569f39e08572"}, 1236 | {file = "skia_pathops-0.8.0.post1-cp312-cp312-win_amd64.whl", hash = "sha256:bc8792c342795c8d90a71d7df641513372954562b3a851b21c501400dba60dcc"}, 1237 | {file = "skia_pathops-0.8.0.post1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a5e7dd0b372c72a2c4b15505c31c1cfa0476ae2b46c8d52932a3278653e0afc4"}, 1238 | {file = "skia_pathops-0.8.0.post1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:08d73f6a6568e1ac486c927035166d9c3bcb6c60bcc10c081d626c05397d2c21"}, 1239 | {file = "skia_pathops-0.8.0.post1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ecece9b39ca2d4ed03bc49364f291f8e94bcd832cbd1e23d5539570d6f22daf"}, 1240 | {file = "skia_pathops-0.8.0.post1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2af80580d722032e650ffa535173e58c16ac7a222eb8886786c9b6f6b7e1df63"}, 1241 | {file = "skia_pathops-0.8.0.post1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:27746a5d18c908f54778654be5a09c2af52b5655977b04650089c962c1700c25"}, 1242 | {file = "skia_pathops-0.8.0.post1-cp38-cp38-win32.whl", hash = "sha256:dab68a6ca259e87a3787ebdb18ebb198711419894cd591d01d3599e036847823"}, 1243 | {file = "skia_pathops-0.8.0.post1-cp38-cp38-win_amd64.whl", hash = "sha256:4c97ae7c611b39641de0aaf7340441615327480eb90dea3ca03dc3ca6aa82b44"}, 1244 | {file = "skia_pathops-0.8.0.post1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:307a94ba2f72601273c187f7fa934b1747dbfeb348dca175c7b40873823711a1"}, 1245 | {file = "skia_pathops-0.8.0.post1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d7acb97291c2107046027fb0671870b7ca0428f55fc550a13cf262d621b8f17"}, 1246 | {file = "skia_pathops-0.8.0.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:434037b8b5ab1824b79d09d2e19a80ad8d2561018d5fb1d167b320e0bb1be7ac"}, 1247 | {file = "skia_pathops-0.8.0.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a3f62afaef14e4a1f02aef3c8d194a04d7735a0e2c700bb4ce39b6c42e8c1ea"}, 1248 | {file = "skia_pathops-0.8.0.post1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:143da8261ea047d0752f406448216cf490e4642a9798e7adfadd0bed855c464a"}, 1249 | {file = "skia_pathops-0.8.0.post1-cp39-cp39-win32.whl", hash = "sha256:83091a316bc5d24ee02ba9f4ca5b690478d1b43a50285bd8afcf623a3f58e87e"}, 1250 | {file = "skia_pathops-0.8.0.post1-cp39-cp39-win_amd64.whl", hash = "sha256:01939106a9aa8e756dd4bf376f16fd9ce616cda16aed1ab34d13e67a498db0aa"}, 1251 | {file = "skia_pathops-0.8.0.post1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c5b66e5644a4f791e3b1fb1e78559130c042f15f744bc1867c18f9268aafab3"}, 1252 | {file = "skia_pathops-0.8.0.post1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d48fd852f3ac7e30f6221ff93e0cfb8593ea897027fd6b36987479eb406fb22"}, 1253 | {file = "skia_pathops-0.8.0.post1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed911ba99e2113574b6314d424696e6e302d427c65136ff8df14359bacb794c7"}, 1254 | ] 1255 | 1256 | [package.extras] 1257 | testing = ["coverage", "pytest", "pytest-randomly", "pytest-xdist"] 1258 | 1259 | [[package]] 1260 | name = "srt" 1261 | version = "3.5.3" 1262 | description = "A tiny library for parsing, modifying, and composing SRT files." 1263 | optional = false 1264 | python-versions = ">=2.7" 1265 | files = [ 1266 | {file = "srt-3.5.3.tar.gz", hash = "sha256:4884315043a4f0740fd1f878ed6caa376ac06d70e135f306a6dc44632eed0cc0"}, 1267 | ] 1268 | 1269 | [[package]] 1270 | name = "svgelements" 1271 | version = "1.9.6" 1272 | description = "Svg Elements Parsing" 1273 | optional = false 1274 | python-versions = "*" 1275 | files = [ 1276 | {file = "svgelements-1.9.6-py2.py3-none-any.whl", hash = "sha256:8a5cf2cc066d98e713d5b875b1d6e5eeb9b92e855e835ebd7caab2713ae1dcad"}, 1277 | {file = "svgelements-1.9.6.tar.gz", hash = "sha256:7c02ad6404cd3d1771fd50e40fbfc0550b0893933466f86a6eb815f3ba3f37f7"}, 1278 | ] 1279 | 1280 | [[package]] 1281 | name = "tomli" 1282 | version = "2.0.1" 1283 | description = "A lil' TOML parser" 1284 | optional = false 1285 | python-versions = ">=3.7" 1286 | files = [ 1287 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 1288 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 1289 | ] 1290 | 1291 | [[package]] 1292 | name = "tqdm" 1293 | version = "4.66.2" 1294 | description = "Fast, Extensible Progress Meter" 1295 | optional = false 1296 | python-versions = ">=3.7" 1297 | files = [ 1298 | {file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"}, 1299 | {file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"}, 1300 | ] 1301 | 1302 | [package.dependencies] 1303 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 1304 | 1305 | [package.extras] 1306 | dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] 1307 | notebook = ["ipywidgets (>=6)"] 1308 | slack = ["slack-sdk"] 1309 | telegram = ["requests"] 1310 | 1311 | [[package]] 1312 | name = "typing-extensions" 1313 | version = "4.10.0" 1314 | description = "Backported and Experimental Type Hints for Python 3.8+" 1315 | optional = false 1316 | python-versions = ">=3.8" 1317 | files = [ 1318 | {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, 1319 | {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, 1320 | ] 1321 | 1322 | [[package]] 1323 | name = "urllib3" 1324 | version = "2.2.1" 1325 | description = "HTTP library with thread-safe connection pooling, file post, and more." 1326 | optional = false 1327 | python-versions = ">=3.8" 1328 | files = [ 1329 | {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, 1330 | {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, 1331 | ] 1332 | 1333 | [package.extras] 1334 | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] 1335 | h2 = ["h2 (>=4,<5)"] 1336 | socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] 1337 | zstd = ["zstandard (>=0.18.0)"] 1338 | 1339 | [[package]] 1340 | name = "watchdog" 1341 | version = "3.0.0" 1342 | description = "Filesystem events monitoring" 1343 | optional = false 1344 | python-versions = ">=3.7" 1345 | files = [ 1346 | {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41"}, 1347 | {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397"}, 1348 | {file = "watchdog-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96"}, 1349 | {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae"}, 1350 | {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9"}, 1351 | {file = "watchdog-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7"}, 1352 | {file = "watchdog-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674"}, 1353 | {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f"}, 1354 | {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc"}, 1355 | {file = "watchdog-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3"}, 1356 | {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3"}, 1357 | {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0"}, 1358 | {file = "watchdog-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8"}, 1359 | {file = "watchdog-3.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100"}, 1360 | {file = "watchdog-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346"}, 1361 | {file = "watchdog-3.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64"}, 1362 | {file = "watchdog-3.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a"}, 1363 | {file = "watchdog-3.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44"}, 1364 | {file = "watchdog-3.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a"}, 1365 | {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709"}, 1366 | {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83"}, 1367 | {file = "watchdog-3.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d"}, 1368 | {file = "watchdog-3.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33"}, 1369 | {file = "watchdog-3.0.0-py3-none-win32.whl", hash = "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f"}, 1370 | {file = "watchdog-3.0.0-py3-none-win_amd64.whl", hash = "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c"}, 1371 | {file = "watchdog-3.0.0-py3-none-win_ia64.whl", hash = "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759"}, 1372 | {file = "watchdog-3.0.0.tar.gz", hash = "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9"}, 1373 | ] 1374 | 1375 | [package.extras] 1376 | watchmedo = ["PyYAML (>=3.10)"] 1377 | 1378 | [metadata] 1379 | lock-version = "2.0" 1380 | python-versions = ">=3.9,<3.13" 1381 | content-hash = "4f56c12ebf05ef1936adc1434003ac0598b565a050dc38475ce2e248a1006222" 1382 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "manim-studio" 3 | version = "0.7.4" 4 | description = "A GUI for Manim" 5 | authors = ["MathItYT "] 6 | readme = "README.md" 7 | 8 | [tool.poetry.dependencies] 9 | python = ">=3.9,<3.13" 10 | manim = "^0.18.0" 11 | pyqt6 = "^6.6.1" 12 | setuptools = "^69.1.1" 13 | 14 | [tool.poetry.plugins."manim.plugins"] 15 | "manim_studio" = "manim_studio" 16 | 17 | [tool.poetry.scripts] 18 | manim-studio = "manim_studio.__main__:main" 19 | 20 | [tool.poetry.group.dev.dependencies] 21 | pytest = "^8.1.1" 22 | 23 | [build-system] 24 | requires = ["poetry-core"] 25 | build-backend = "poetry.core.masonry.api" 26 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MathItYT/manim-studio/fcd4496a64255a8dd6e91303d1000e9781ba6957/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_startup.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | 4 | 5 | class TestStartup: 6 | def test_startup(self): 7 | print(f"Testing on version {sys.version}") 8 | subprocess.run([sys.executable, "-m", "manim_studio", 9 | "--timeout", "5"], check=True) 10 | --------------------------------------------------------------------------------