[
  {
    "path": ".codecov.yml",
    "content": "codecov:\n  notify:\n    require_ci_to_pass: no\n    after_n_builds: 1\ncoverage:\n  status:\n    project:\n      default:\n        # Require 1% coverage, i.e., always succeed\n        target: 1\n    patch: true\n    changes: false\ncomment: off\n"
  },
  {
    "path": ".codespell_ignorewords",
    "content": " nam\n sherif\n falsy\n medias\n strager\n"
  },
  {
    "path": ".codespellrc",
    "content": "[codespell]\ncheck-hidden = True\nskip = .git,*.js,*.js.map,*.css,*.css.map,*.html,*.po,*.pot,uv.lock,*.log,*.svg\nignore-words = .codespell_ignorewords\n"
  },
  {
    "path": ".dockerignore",
    "content": ".git\n\n# Development / test artifacts\n__pycache__\n**/__pycache__\n*.pyc\n*.pyo\n*.pyd\n*.egg-info\ndist/\nbuild/\ncoverage.xml\n\n# Not needed to install the package\ndocs/\ntests/\nexample_scenes/\nmedia/\nlogo/\nscripts/\n"
  },
  {
    "path": ".flake8",
    "content": "[flake8]\n# Exclude the grpc generated code\nexclude = ./manim/grpc/gen/*, __pycache__,.git,\nper-file-ignores = __init__.py:F401\nmax-complexity = 29\nmax-line-length = 88\nstatistics = True\n# Prevents some flake8-rst-docstrings errors\nrst-roles = attr,class,func,meth,mod,obj,ref,doc,exc\nrst-directives = manim, SEEALSO, seealso\ndocstring-convention=numpy\n\nselect = A,A00,B,B9,C4,C90,D,E,F,F,PT,RST,SIM,W,F401\n\n                # General Compatibility\nextend-ignore = E203, W503, D202, D212, D213, D404\n\n                # Misc\n                F401, F403, F405, F841, E501, E731, E402, F811, F821,\n\n                # multiple statements on one line (overload)\n                E704,\n\n                # Plug-in: flake8-builtins\n                A001, A002, A003,\n\n                # Plug-in: flake8-bugbear\n                B006, B007, B008, B009, B010, B903, B950,\n\n                # Plug-in: flake8-simplify\n                SIM105, SIM106, SIM119,\n\n                # Plug-in: flake8-pytest-style\n                PT001, PT004, PT006, PT011, PT018, PT022, PT023,\n\n                # Plug-in: flake8-docstrings\n                D100, D101, D102, D103, D104, D105, D106, D107,\n                D200, D202, D204, D205, D209,\n                D301,\n                D400, D401, D402, D403, D405, D406, D407, D409, D411, D412, D414,\n\n                # Plug-in: flake8-rst-docstrings\n                RST201, RST203, RST210, RST212, RST213, RST215,\n                RST301, RST303, RST499\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "# Switched to ruff format:\n24025b60d57301b0a59754c38d77bccd8ed69feb\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Declare files that always have LF line endings on checkout\n* text eol=lf\n*.bat  text eol=crlf\n\n# Denote all files that are truly binary and should not be modified\n*.npz binary\n*.png binary\n*.wav binary\n\nmanim/grpc/gen/** linguist-generated=true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Manim bug\nabout: Report a bug or unexpected behavior when running Manim\ntitle: \"\"\nlabels: bug\nassignees: ''\n\n---\n\n## Description of bug / unexpected behavior\n<!-- Add a clear and concise description of the problem you encountered. -->\n\n\n## Expected behavior\n<!-- Add a clear and concise description of what you expected to happen. -->\n\n\n## How to reproduce the issue\n<!-- Provide a piece of code illustrating the undesired behavior. -->\n\n<details><summary>Code for reproducing the problem</summary>\n\n```py\nPaste your code here.\n```\n\n</details>\n\n\n## Additional media files\n<!-- Paste in the files manim produced on rendering the code above. -->\n\n<details><summary>Images/GIFs</summary>\n\n<!-- PASTE MEDIA HERE -->\n\n</details>\n\n\n## Logs\n<details><summary>Terminal output</summary>\n<!-- Add \"-v DEBUG\" when calling manim to generate more detailed logs -->\n\n```\nPASTE HERE OR PROVIDE LINK TO https://pastebin.com/ OR SIMILAR\n```\n\n<!-- Insert screenshots here (only when absolutely necessary, we prefer copy/pasted output!) -->\n\n</details>\n\n\n## System specifications\n\n<details><summary>System Details</summary>\n\n- OS (with version, e.g., Windows 10 v2004 or macOS 10.15 (Catalina)):\n- RAM:\n- Python version (`python/py/python3 --version`):\n- Installed modules (provide output from `pip list`):\n```\nPASTE HERE\n```\n</details>\n\n<details><summary>LaTeX details</summary>\n\n+ LaTeX distribution (e.g. TeX Live 2020):\n+ Installed LaTeX packages:\n<!-- output of `tlmgr list --only-installed` for TeX Live or a screenshot of the Packages page for MikTeX -->\n</details>\n\n## Additional comments\n<!-- Add further context that you think might be relevant for this issue here. -->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Request a new feature for Manim\ntitle: \"\"\nlabels: new feature\nassignees: ''\n\n---\n\n## Description of proposed feature\n<!-- Add a clear and concise description of the new feature, including a motivation: why do you think this will be useful? -->\n\n\n## How can the new feature be used?\n<!-- If possible, illustrate how this new feature could be used. -->\n\n\n## Additional comments\n<!-- Add further context that you think might be relevant. -->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/installation_issue.md",
    "content": "---\nname: Installation issue\nabout: Report issues with the installation process of Manim\ntitle: \"\"\nlabels: bug, installation\nassignees: ''\n\n---\n\n#### Preliminaries\n\n- [ ] I have followed the latest version of the\n      [installation instructions](https://docs.manim.community/en/stable/installation.html).\n- [ ] I have checked the [installation FAQ](https://docs.manim.community/en/stable/faq/installation.html) and my problem is either not mentioned there,\n      or the solution given there does not help.\n\n## Description of error\n<!-- Add a clear and concise description of the problem you encountered. -->\n\n\n## Installation logs\n<!-- Please paste the **full** terminal output; we can only help to identify the issue\n     when we receive all required information. -->\n\n<details><summary>Terminal output</summary>\n\n```\nPASTE HERE OR PROVIDE LINK TO https://pastebin.com/ OR SIMILAR\n```\n\n<!-- Insert screenshots here (only when absolutely necessary, we prefer copy/pasted output!) -->\n\n</details>\n\n\n## System specifications\n\n<details><summary>System Details</summary>\n\n- OS (with version, e.g., Windows 10 v2004 or macOS 10.15 (Catalina)):\n- RAM:\n- Python version (`python/py/python3 --version`):\n- Installed modules (provide output from `pip list`):\n```\nPASTE HERE\n```\n</details>\n\n<details><summary>LaTeX details</summary>\n\n+ LaTeX distribution (e.g. TeX Live 2020):\n+ Installed LaTeX packages:\n<!-- output of `tlmgr list --only-installed` for TeX Live or a screenshot of the Packages page for MikTeX -->\n</details>\n\n## Additional comments\n<!-- Add further context that you think might be relevant for this issue here. -->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/bugfix.md",
    "content": "<!-- Thank you for contributing to ManimCommunity!\nBefore filling in the details, ensure:\n- The title of your PR gives a descriptive summary to end-users. Some examples:\n  - Fixed last animations not running to completion\n  - Added gradient support and documentation for SVG files\n-->\n\n## Changelog\n<!-- Optional: more descriptive changelog entry than just the title for the upcoming\nrelease. Write RST between the following start and end comments.-->\n<!--changelog-start-->\n<!--changelog-end-->\n\n## Summary of Changes\n\n\n## Checklist\n- [ ] I have read the [Contributing Guidelines](https://docs.manim.community/en/latest/contributing.html)\n- [ ] I have written a descriptive PR title (see top of PR template for examples)\n- [ ] I have added a test case to prevent software regression\n\n<!-- Do not modify the lines below. These are for the reviewers of your PR -->\n## Reviewer Checklist\n- [ ] The PR title is descriptive enough\n- [ ] The PR is labeled appropriately\n- [ ] Regression test(s) are implemented\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/documentation.md",
    "content": "<!-- Thank you for contributing to ManimCommunity!\nBefore filling in the details, ensure:\n- The title of your PR gives a descriptive summary to end-users. Some examples:\n  - Fixed last animations not running to completion\n  - Added gradient support and documentation for SVG files\n-->\n## Summary of Changes\n\n## Changelog\n<!-- Optional: more descriptive changelog entry than just the title for the upcoming\nrelease. Write RST between the following start and end comments.-->\n<!--changelog-start-->\n<!--changelog-end-->\n\n## Checklist\n- [ ] I have read the [Contributing Guidelines](https://docs.manim.community/en/latest/contributing.html)\n- [ ] I have written a descriptive PR title (see top of PR template for examples)\n- [ ] My new documentation builds, looks correctly formatted, and adds no additional build warnings\n\n<!-- Do not modify the lines below. These are for the reviewers of your PR -->\n## Reviewer Checklist\n- [ ] The PR title is descriptive enough\n- [ ] The PR is labeled appropriately\n- [ ] Newly added documentation builds, looks correctly formatted, and adds no additional build warnings\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/hackathon.md",
    "content": "Thanks for your contribution for the manim community hackathon!\n\nPlease make sure your pull request has a meaningful title.\n\nE.g. \"Example for the class Angle\".\n\nDetails for the submissions can be found in the [discord announcement channel](https://discord.com/channels/581738731934056449/581739610154074112/846460718479966228\n).\n\nDocstrings can be created in the discord channel with the manimator like this:\n```\n!mdocstring\n```\n```python\nclass HelloWorld(Scene):\n    def construct(self):\n        self.add(Circle())\n```\nCopy+paste the output docstring to the right place in the source code.\n\nIf you need any help, do not hesitate to ask the hackathon-mentors in the discord channel.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!-- Thank you for contributing to Manim! Learn more about the process in our contributing guidelines: https://docs.manim.community/en/latest/contributing.html -->\n\n## Overview: What does this pull request change?\n\n## Motivation and Explanation: Why and how do your changes improve the library?\n<!-- Optional for bugfixes, small enhancements, and documentation-related PRs. Otherwise, please give a short reasoning for your changes. -->\n\n## Links to added or changed documentation pages\n<!-- Please add links to the affected documentation pages (edit the description after opening the PR). The link to the documentation for your PR is https://manimce--####.org.readthedocs.build/en/####/, where #### represents the PR number. -->\n\n\n## Further Information and Comments\n<!-- If applicable, put further comments for the reviewers here. -->\n\n\n\n<!-- Thank you again for contributing! Do not modify the lines below, they are for reviewers. -->\n## Reviewer Checklist\n- [ ] The PR title is descriptive enough for the changelog, and the PR is labeled correctly\n- [ ] If applicable: newly added non-private functions and classes have a docstring including a short summary and a PARAMETERS section\n- [ ] If applicable: newly added functions and classes are tested\n"
  },
  {
    "path": ".github/codeql.yml",
    "content": "query-filters:\n    - exclude:\n          id: py/init-calls-subclass\n    - exclude:\n          id: py/unexpected-raise-in-special-method\n    - exclude:\n          id: py/modification-of-locals\n    - exclude:\n          id: py/multiple-calls-to-init\n    - exclude:\n          id: py/missing-call-to-init\n    - exclude:\n          id: py/method-first-arg-is-not-self\n    - exclude:\n          id: py/cyclic-import\n    - exclude:\n          id: py/unsafe-cyclic-import\npaths:\n    - manim\npaths-ignore:\n    - tests/\n    - example_scenes/\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"monthly\"\n    ignore:\n      - dependency-name: \"*\"\n        update-types:\n          - \"version-update:semver-minor\"\n          - \"version-update:semver-patch\"\n"
  },
  {
    "path": ".github/manimdependency.json",
    "content": "{\n    \"windows\": {\n        \"tinytex\": [\n            \"standalone\",\n            \"preview\",\n            \"doublestroke\",\n            \"count1to\",\n            \"multitoc\",\n            \"prelim2e\",\n            \"ragged2e\",\n            \"everysel\",\n            \"setspace\",\n            \"rsfs\",\n            \"relsize\",\n            \"ragged2e\",\n            \"fundus-calligra\",\n            \"microtype\",\n            \"wasysym\",\n            \"physics\",\n            \"dvisvgm\",\n            \"jknapltx\",\n            \"wasy\",\n            \"cm-super\",\n            \"babel-english\",\n            \"gnu-freefont\",\n            \"mathastext\",\n            \"cbfonts-fd\"\n        ]\n    },\n    \"macos\": {\n        \"tinytex\": [\n            \"standalone\",\n            \"preview\",\n            \"doublestroke\",\n            \"count1to\",\n            \"multitoc\",\n            \"prelim2e\",\n            \"ragged2e\",\n            \"everysel\",\n            \"setspace\",\n            \"rsfs\",\n            \"relsize\",\n            \"ragged2e\",\n            \"fundus-calligra\",\n            \"microtype\",\n            \"wasysym\",\n            \"physics\",\n            \"dvisvgm\",\n            \"jknapltx\",\n            \"wasy\",\n            \"cm-super\",\n            \"babel-english\",\n            \"gnu-freefont\",\n            \"mathastext\",\n            \"cbfonts-fd\"\n        ]\n    }\n}\n"
  },
  {
    "path": ".github/release.yml",
    "content": "# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes\n\nchangelog:\n  exclude:\n    labels:\n      - duplicate/wontfix\n      - invalid\n      - question\n      - release\n    authors:\n      - dependabot[bot]\n      - pre-commit-ci[bot]\n\n  categories:\n    # High Impact\n    - title: \"Breaking Changes 🚨\"\n      labels:\n        - breaking changes\n\n    # Highlights\n    - title: \"Highlights 🌟\"\n      labels:\n        - highlight\n\n    # User-facing\n    - title: \"New Features ✨\"\n      labels:\n        - new feature\n\n    - title: \"Enhancements 🚀\"\n      labels:\n        - enhancement\n\n    - title: \"Bug Fixes 🐛\"\n      labels:\n        - pr:bugfix\n\n    - title: \"Deprecations & Removals ⚠️\"\n      labels:\n        - pr:deprecation\n\n    # Developer-facing\n    - title: \"Documentation 📚\"\n      labels:\n        - documentation\n\n    - title: \"Testing 🧪\"\n      labels:\n        - testing\n\n    - title: \"Infrastructure & Build 🔨\"\n      labels:\n        - infrastructure\n\n    - title: \"Code Quality & Refactoring 🧹\"\n      labels:\n        - maintenance\n        - refactor\n\n    - title: \"Type Hints 📝\"\n      labels:\n        - typehints\n\n    # Catch-all (must be last)\n    - title: \"Other Changes\"\n      labels:\n        - \"*\"\n"
  },
  {
    "path": ".github/scripts/ci_build_cairo.py",
    "content": "# Logic is as follows:\n# 1. Download cairo source code: https://cairographics.org/releases/cairo-<version>.tar.xz\n# 2. Verify the downloaded file using the sha256sums file: https://cairographics.org/releases/cairo-<version>.tar.xz.sha256sum\n# 3. Extract the downloaded file.\n# 4. Create a virtual environment and install meson and ninja.\n# 5. Run meson build in the extracted directory. Also, set required prefix.\n# 6. Run meson compile -C build.\n# 7. Run meson install -C build.\n\nimport hashlib\nimport logging\nimport os\nimport subprocess\nimport sys\nimport tarfile\nimport tempfile\nimport urllib.request\nfrom collections.abc import Generator\nfrom contextlib import contextmanager\nfrom pathlib import Path\nfrom sys import stdout\n\nCAIRO_VERSION = \"1.18.0\"\nCAIRO_URL = f\"https://cairographics.org/releases/cairo-{CAIRO_VERSION}.tar.xz\"\nCAIRO_SHA256_URL = f\"{CAIRO_URL}.sha256sum\"\n\nVENV_NAME = \"meson-venv\"\nBUILD_DIR = \"build\"\nINSTALL_PREFIX = Path(__file__).parent.parent.parent / \"third_party\" / \"cairo\"\n\nlogging.basicConfig(level=logging.INFO, format=\"%(asctime)s %(levelname)s %(message)s\")\nlogger = logging.getLogger(__name__)\n\n\ndef is_ci():\n    return os.getenv(\"CI\", None) is not None\n\n\ndef download_file(url, path):\n    logger.info(f\"Downloading {url} to {path}\")\n    block_size = 1024 * 1024\n    with urllib.request.urlopen(url) as response, open(path, \"wb\") as file:\n        while True:\n            data = response.read(block_size)\n            if not data:\n                break\n            file.write(data)\n\n\ndef verify_sha256sum(path, sha256sum):\n    with open(path, \"rb\") as file:\n        file_hash = hashlib.sha256(file.read()).hexdigest()\n    if file_hash != sha256sum:\n        raise Exception(\"SHA256SUM does not match\")\n\n\ndef extract_tar_xz(path, directory):\n    with tarfile.open(path) as file:\n        file.extractall(directory)\n\n\ndef run_command(command, cwd=None, env=None):\n    process = subprocess.Popen(command, cwd=cwd, env=env)\n    process.communicate()\n    if process.returncode != 0:\n        raise Exception(\"Command failed\")\n\n\n@contextmanager\ndef gha_group(title: str) -> Generator:\n    if not is_ci():\n        yield\n        return\n    print(f\"\\n::group::{title}\")\n    stdout.flush()\n    try:\n        yield\n    finally:\n        print(\"::endgroup::\")\n        stdout.flush()\n\n\ndef set_env_var_gha(name: str, value: str) -> None:\n    if not is_ci():\n        return\n    env_file = os.getenv(\"GITHUB_ENV\", None)\n    if env_file is None:\n        return\n    with open(env_file, \"a\") as file:\n        file.write(f\"{name}={value}\\n\")\n    stdout.flush()\n\n\ndef get_ld_library_path(prefix: Path) -> str:\n    # given a prefix, the ld library path can be found at\n    # <prefix>/lib/* or sometimes just <prefix>/lib\n    # this function returns the path to the ld library path\n\n    # first, check if the ld library path exists at <prefix>/lib/*\n    ld_library_paths = list(prefix.glob(\"lib/*\"))\n    if len(ld_library_paths) == 1:\n        return ld_library_paths[0].absolute().as_posix()\n\n    # if the ld library path does not exist at <prefix>/lib/*,\n    # return <prefix>/lib\n    ld_library_path = prefix / \"lib\"\n    if ld_library_path.exists():\n        return ld_library_path.absolute().as_posix()\n    return \"\"\n\n\ndef main():\n    if sys.platform == \"win32\":\n        logger.info(\"Skipping build on windows\")\n        return\n\n    with tempfile.TemporaryDirectory() as tmpdir:\n        with gha_group(\"Downloading and Extracting Cairo\"):\n            logger.info(f\"Downloading cairo version {CAIRO_VERSION}\")\n            download_file(CAIRO_URL, os.path.join(tmpdir, \"cairo.tar.xz\"))\n\n            logger.info(\"Downloading cairo sha256sum\")\n            download_file(CAIRO_SHA256_URL, os.path.join(tmpdir, \"cairo.sha256sum\"))\n\n            logger.info(\"Verifying cairo sha256sum\")\n            with open(os.path.join(tmpdir, \"cairo.sha256sum\")) as file:\n                sha256sum = file.read().split()[0]\n            verify_sha256sum(os.path.join(tmpdir, \"cairo.tar.xz\"), sha256sum)\n\n            logger.info(\"Extracting cairo\")\n            extract_tar_xz(os.path.join(tmpdir, \"cairo.tar.xz\"), tmpdir)\n\n        with gha_group(\"Installing meson and ninja\"):\n            logger.info(\"Creating virtual environment\")\n            run_command([sys.executable, \"-m\", \"venv\", os.path.join(tmpdir, VENV_NAME)])\n\n            logger.info(\"Installing meson and ninja\")\n            run_command(\n                [\n                    os.path.join(tmpdir, VENV_NAME, \"bin\", \"pip\"),\n                    \"install\",\n                    \"meson\",\n                    \"ninja\",\n                ]\n            )\n\n        # Inherit the current environment so PKG_CONFIG_PATH, CFLAGS, LDFLAGS, etc. are preserved.\n        env_vars = os.environ.copy()\n        # Prepend the venv bin directory so meson/ninja from the venv are used.\n        env_vars[\"PATH\"] = f\"{os.path.join(tmpdir, VENV_NAME, 'bin')}{os.pathsep}{env_vars.get('PATH','')}\"\n\n        # Ensure Homebrew-provided pkgconfig and include/lib paths are present on macOS ARM.\n        if sys.platform == \"darwin\":\n            try:\n                # Try to get specific prefix for lzo (safer for opt path), fall back to generic brew prefix.\n                brew_prefix = subprocess.check_output([\"brew\", \"--prefix\", \"lzo\"], text=True).strip()\n            except subprocess.CalledProcessError:\n                try:\n                    brew_prefix = subprocess.check_output([\"brew\", \"--prefix\"], text=True).strip()\n                except Exception:\n                    brew_prefix = None\n\n            if brew_prefix:\n                # pkg-config files can live in lib/pkgconfig or opt/<pkg>/lib/pkgconfig\n                pkgconfig_paths = [f\"{brew_prefix}/lib/pkgconfig\", f\"{brew_prefix}/opt/lzo/lib/pkgconfig\"]\n                # merge with any existing PKG_CONFIG_PATH\n                existing_pc = env_vars.get(\"PKG_CONFIG_PATH\", \"\")\n                merged_pc = \":\".join([p for p in pkgconfig_paths if p]) + (f\":{existing_pc}\" if existing_pc else \"\")\n                env_vars[\"PKG_CONFIG_PATH\"] = merged_pc\n\n                # Ensure compiler & linker flags include brew include/lib\n                existing_cflags = env_vars.get(\"CFLAGS\", \"\")\n                existing_ldflags = env_vars.get(\"LDFLAGS\", \"\")\n                env_vars[\"CFLAGS\"] = f\"-I{brew_prefix}/include {existing_cflags}\".strip()\n                env_vars[\"LDFLAGS\"] = f\"-L{brew_prefix}/lib {existing_ldflags}\".strip()\n\n        # Debugging: log environment keys relevant to detection\n        # logger.info(f\"env vars for meson: {env_vars}\")\n\n        with gha_group(\"Building and Installing Cairo\"):\n            logger.info(\"Running meson setup\")\n            run_command(\n                [\n                    os.path.join(tmpdir, VENV_NAME, \"bin\", \"meson\"),\n                    \"setup\",\n                    BUILD_DIR,\n                    f\"--prefix={INSTALL_PREFIX.absolute().as_posix()}\",\n                    \"--buildtype=release\",\n                    \"-Dtests=disabled\",\n                ],\n                cwd=os.path.join(tmpdir, f\"cairo-{CAIRO_VERSION}\"),\n                env=env_vars,\n            )\n\n            logger.info(\"Running meson compile\")\n            run_command(\n                [\n                    os.path.join(tmpdir, VENV_NAME, \"bin\", \"meson\"),\n                    \"compile\",\n                    \"-C\",\n                    BUILD_DIR,\n                ],\n                cwd=os.path.join(tmpdir, f\"cairo-{CAIRO_VERSION}\"),\n                env=env_vars,\n            )\n\n            logger.info(\"Running meson install\")\n            run_command(\n                [\n                    os.path.join(tmpdir, VENV_NAME, \"bin\", \"meson\"),\n                    \"install\",\n                    \"-C\",\n                    BUILD_DIR,\n                ],\n                cwd=os.path.join(tmpdir, f\"cairo-{CAIRO_VERSION}\"),\n                env=env_vars,\n            )\n\n        logger.info(f\"Successfully built cairo and installed it to {INSTALL_PREFIX}\")\n\n\nif __name__ == \"__main__\":\n    if \"--set-env-vars\" in sys.argv:\n        with gha_group(\"Setting environment variables\"):\n            # append the pkgconfig directory to PKG_CONFIG_PATH\n            set_env_var_gha(\n                \"PKG_CONFIG_PATH\",\n                f\"{Path(get_ld_library_path(INSTALL_PREFIX), 'pkgconfig').as_posix()}{os.pathsep}\"\n                f'{os.getenv(\"PKG_CONFIG_PATH\", \"\")}',\n            )\n            set_env_var_gha(\n                \"LD_LIBRARY_PATH\",\n                f\"{get_ld_library_path(INSTALL_PREFIX)}{os.pathsep}\"\n                f'{os.getenv(\"LD_LIBRARY_PATH\", \"\")}',\n            )\n        sys.exit(0)\n    main()\n"
  },
  {
    "path": ".github/workflows/cffconvert.yml",
    "content": "name: cffconvert\n\non:\n  push:\n    paths:\n      - CITATION.cff\n\njobs:\n  validate:\n    name: \"validate\"\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out a copy of the repository\n        uses: actions/checkout@v6\n\n      - name: Check whether the citation metadata from CITATION.cff is valid\n        uses: citation-file-format/cffconvert-github-action@2.0.0\n        with:\n          args: \"--validate\"\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\nconcurrency:\n  group: ${{ github.ref }}\n  cancel-in-progress: true\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - main\n\njobs:\n  test:\n    runs-on: ${{ matrix.os }}\n    env:\n      DISPLAY: :0\n      PYTEST_ADDOPTS: \"--color=yes\" # colors in pytest\n      PYTHONIOENCODING: \"utf8\"\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-22.04, macos-latest, windows-latest]\n        python: [\"3.11\", \"3.12\", \"3.13\", \"3.14\"]\n        include:\n          - os: macos-15-intel\n            python: \"3.13\"\n\n    steps:\n      - name: Checkout the repository\n        uses: actions/checkout@v6\n\n      - name: Setup Python ${{ matrix.python }}\n        uses: actions/setup-python@v6\n        with:\n          python-version: ${{ matrix.python }}\n\n      - name: Install uv\n        uses: astral-sh/setup-uv@v7\n        with:\n          enable-cache: true\n\n      - name: Setup cache variables\n        shell: bash\n        id: cache-vars\n        run: |\n          echo \"date=$(/bin/date -u \"+%m%w%Y\")\" >> $GITHUB_OUTPUT\n\n      - name: Install system dependencies (Linux)\n        if: runner.os == 'Linux'\n        uses: awalsh128/cache-apt-pkgs-action@latest\n        with:\n          packages: python3-opengl libpango1.0-dev xvfb freeglut3-dev\n          version: 1.0\n\n      - name: Install Texlive (Linux)\n        if: runner.os == 'Linux'\n        uses: zauguin/install-texlive@v4\n        with:\n          packages: >\n            scheme-basic latex fontspec tipa calligra xcolor\n            standalone preview doublestroke setspace rsfs relsize\n            ragged2e fundus-calligra microtype wasysym physics dvisvgm jknapltx\n            wasy cm-super babel-english gnu-freefont mathastext cbfonts-fd xetex\n\n      - name: Start virtual display (Linux)\n        if: runner.os == 'Linux'\n        run: |\n          # start xvfb in background\n          sudo /usr/bin/Xvfb $DISPLAY -screen 0 1280x1024x24 &\n\n      - name: Setup Cairo Cache\n        uses: actions/cache@v5\n        id: cache-cairo\n        if: runner.os == 'Linux' || runner.os == 'macOS'\n        with:\n          path: ${{ github.workspace }}/third_party\n          key: ${{ runner.os }}-${{ runner.arch }}-dependencies-cairo-${{ hashFiles('.github/scripts/ci_build_cairo.py') }}\n\n      - name: Build and install Cairo (Linux and macOS)\n        if: (runner.os == 'Linux' || runner.os == 'macOS') && steps.cache-cairo.outputs.cache-hit != 'true'\n        run: python .github/scripts/ci_build_cairo.py\n\n      - name: Set env vars for Cairo (Linux and macOS)\n        if: runner.os == 'Linux' || runner.os == 'macOS'\n        run: python .github/scripts/ci_build_cairo.py --set-env-vars\n\n      - name: Setup macOS cache\n        uses: actions/cache@v5\n        id: cache-macos\n        if: runner.os == 'macOS'\n        with:\n          path: ${{ github.workspace }}/macos-cache\n          key: ${{ runner.os }}-dependencies-tinytex-${{ hashFiles('.github/manimdependency.json') }}-${{ steps.cache-vars.outputs.date }}-1\n\n      - name: Install system dependencies (MacOS)\n        if: runner.os == 'macOS' && steps.cache-macos.outputs.cache-hit != 'true'\n        run: |\n          tinyTexPackages=$(python -c \"import json;print(' '.join(json.load(open('.github/manimdependency.json'))['macos']['tinytex']))\")\n          IFS=' '\n          read -a ttp <<< \"$tinyTexPackages\"\n          oriPath=$PATH\n          sudo mkdir -p $PWD/macos-cache\n          echo \"Install TinyTeX\"\n          sudo curl -L -o \"/tmp/TinyTeX.tgz\" \"https://github.com/yihui/tinytex-releases/releases/download/daily/TinyTeX-1.tgz\"\n          sudo tar zxf \"/tmp/TinyTeX.tgz\" -C \"$PWD/macos-cache\"\n          export PATH=\"$PWD/macos-cache/TinyTeX/bin/universal-darwin:$PATH\"\n          sudo tlmgr update --self\n          for i in \"${ttp[@]}\"; do\n            sudo tlmgr install \"$i\"\n          done\n          export PATH=\"$oriPath\"\n          echo \"Completed TinyTeX\"\n\n      - name: Add macOS dependencies to PATH\n        if: runner.os == 'macOS'\n        shell: bash\n        run: |\n          echo \"/Library/TeX/texbin\" >> $GITHUB_PATH\n          echo \"$PWD/macos-cache/TinyTeX/bin/universal-darwin\" >> $GITHUB_PATH\n\n      - name: Setup Windows cache\n        id: cache-windows\n        if: runner.os == 'Windows'\n        uses: actions/cache@v5\n        with:\n          path: ${{ github.workspace }}\\ManimCache\n          key: ${{ runner.os }}-dependencies-tinytex-${{ hashFiles('.github/manimdependency.json') }}-${{ steps.cache-vars.outputs.date }}-1\n\n      - uses: ssciwr/setup-mesa-dist-win@v2\n\n      - name: Install system dependencies (Windows)\n        if: runner.os == 'Windows' && steps.cache-windows.outputs.cache-hit != 'true'\n        run: |\n          $tinyTexPackages = $(python -c \"import json;print(' '.join(json.load(open('.github/manimdependency.json'))['windows']['tinytex']))\") -Split ' '\n          $OriPath = $env:PATH\n          echo \"Install Tinytex\"\n          Invoke-WebRequest \"https://github.com/yihui/tinytex-releases/releases/download/daily/TinyTeX-1.zip\" -OutFile \"$($env:TMP)\\TinyTex.zip\"\n          Expand-Archive -LiteralPath \"$($env:TMP)\\TinyTex.zip\" -DestinationPath \"$($PWD)\\ManimCache\\LatexWindows\"\n          $env:Path = \"$($PWD)\\ManimCache\\LatexWindows\\TinyTeX\\bin\\windows;$($env:PATH)\"\n          tlmgr update --self\n          tlmgr install $tinyTexPackages\n          $env:PATH=$OriPath\n          echo \"Completed Latex\"\n\n      - name: Add Windows dependencies to PATH\n        if: runner.os == 'Windows'\n        run: |\n          $env:Path += \";\" + \"$($PWD)\\ManimCache\\LatexWindows\\TinyTeX\\bin\\windows\"\n          echo \"$env:Path\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append\n\n      - name: Install dependencies and manim\n        run: |\n          uv sync --all-extras --locked\n\n      - name: Run tests\n        run: |\n          uv run python -m pytest\n\n      - name: Run module doctests\n        run: |\n          uv run python -m pytest -v --cov-append --ignore-glob=\"*opengl*\" --doctest-modules manim\n\n      - name: Run doctests in rst files\n        run: |\n          cd docs && uv run make doctest O=-tskip-manim\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n  schedule:\n    - cron: \"21 16 * * 3\"\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ python ]\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v4\n        with:\n          languages: ${{ matrix.language }}\n          config-file: ./.github/codeql.yml\n          queries: +security-and-quality\n\n      - name: Autobuild\n        uses: github/codeql-action/autobuild@v4\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v4\n        with:\n          category: \"/language:${{ matrix.language }}\"\n"
  },
  {
    "path": ".github/workflows/dependent-issues.yml",
    "content": "name: Dependent Issues\n\non:\n  issues:\n    types:\n      - opened\n      - edited\n      - reopened\n  pull_request_target:\n    types:\n      - opened\n      - edited\n      - reopened\n      - synchronize\n  schedule:\n    - cron: '0 0 * * *' # schedule daily check\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: z0al/dependent-issues@v1\n        env:\n          # (Required) The token to use to make API calls to GitHub.\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          # (Optional) The label to use to mark dependent issues\n          label: dependent\n\n          # (Optional) Enable checking for dependencies in issues. Enable by\n          # setting the value to \"on\". Default \"off\"\n          check_issues: on\n\n          # (Optional) A comma-separated list of keywords. Default\n          # \"depends on, blocked by\"\n          keywords: depends on, blocked by\n"
  },
  {
    "path": ".github/workflows/publish-docker.yml",
    "content": "name: Publish Docker Image\n\non:\n  push:\n    branches:\n      - main\n  release:\n    types: [released]\n\njobs:\n  docker-latest:\n    runs-on: ubuntu-latest\n    if: github.event_name != 'release'\n    steps:\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v3\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Login to DockerHub\n        uses: docker/login-action@v3\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n\n      - name: Build and push\n        uses: docker/build-push-action@v6\n        with:\n          platforms: linux/arm64,linux/amd64\n          push: true\n          file: docker/Dockerfile\n          tags: |\n            manimcommunity/manim:latest\n\n  docker-release:\n    runs-on: ubuntu-latest\n    if: github.event_name == 'release'\n    steps:\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v3\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Login to DockerHub\n        uses: docker/login-action@v3\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n\n      - name: Get Version\n        id: create_release\n        shell: python\n        env:\n          tag_act: ${{ github.ref }}\n        run: |\n          import os\n          ref_tag = os.getenv('tag_act').split('/')[-1]\n          with open(os.getenv('GITHUB_OUTPUT'), 'w') as f:\n            print(f\"tag_name={ref_tag}\", file=f)\n\n      - name: Build and push\n        uses: docker/build-push-action@v6\n        with:\n          platforms: linux/arm64,linux/amd64\n          push: true\n          file: docker/Dockerfile\n          tags: |\n            manimcommunity/manim:stable\n            manimcommunity/manim:latest\n            manimcommunity/manim:${{ steps.create_release.outputs.tag_name }}\n"
  },
  {
    "path": ".github/workflows/python-publish.yml",
    "content": "name: Publish Release\n\non:\n  release:\n    types: [released]\n\njobs:\n  release:\n    name: \"Publish release\"\n    runs-on: ubuntu-latest\n    environment: release\n    permissions:\n      id-token: write\n      contents: write\n\n    steps:\n    - uses: actions/checkout@v6\n\n    - name: Install dependencies\n      run: sudo apt-get update && sudo apt-get install -y build-essential python3-dev libcairo2-dev libpango1.0-dev\n\n    - name: Set up Python 3.13\n      uses: actions/setup-python@v6\n      with:\n        python-version: 3.13\n\n    - name: Install uv\n      uses: astral-sh/setup-uv@v7\n\n    - name: Build and push release to PyPI\n      run: |\n        uv build\n        uv publish\n\n    - name: Store artifacts\n      uses: actions/upload-artifact@v6\n      with:\n          path: dist/*.tar.gz\n          name: manim.tar.gz\n\n    - name: Upload Release Asset\n      shell: bash\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      run: |\n        TAG=${{ github.event.release.tag_name }}\n        gh release upload \"$TAG\" \"dist/manim-${TAG#v}.tar.gz\"\n"
  },
  {
    "path": ".github/workflows/release-publish-documentation.yml",
    "content": "name: Publish downloadable documentation\n\non:\n  release:\n    types: [released]\n  workflow_dispatch:\n\njobs:\n  build-and-publish-htmldocs:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n\n    - name: Set up Python\n      uses: actions/setup-python@v6\n      with:\n        python-version: 3.13\n\n    - name: Install uv\n      uses: astral-sh/setup-uv@v7\n\n    - name: Install system dependencies\n      run: |\n        sudo apt update && sudo apt install -y \\\n          pkg-config libcairo-dev libpango1.0-dev wget fonts-roboto\n        wget -qO- \"https://yihui.org/tinytex/install-bin-unix.sh\" | sh\n        echo ${HOME}/.TinyTeX/bin/x86_64-linux >> $GITHUB_PATH\n\n    - name: Install LaTeX and Python dependencies\n      run: |\n        tlmgr update --self\n        tlmgr install \\\n          babel-english ctex doublestroke dvisvgm frcursive fundus-calligra jknapltx \\\n          mathastext microtype physics preview ragged2e relsize rsfs setspace standalone \\\n          wasy wasysym\n        uv sync\n\n    - name: Build and package documentation\n      run: |\n        cd docs/\n        uv run make html\n        cd build/html/\n        tar -czvf ../html-docs.tar.gz *\n\n    - name: Store artifacts\n      uses: actions/upload-artifact@v6\n      with:\n          path: ${{ github.workspace }}/docs/build/html-docs.tar.gz\n          name: html-docs.tar.gz\n\n    - name: Install Dependency\n      run: pip install requests\n\n    - name: Get Upload URL\n      if: github.event == 'release'\n      id: create_release\n      shell: python\n      env:\n          access_token: ${{ secrets.GITHUB_TOKEN }}\n          tag_act: ${{ github.ref }}\n      run: |\n          import requests\n          import os\n          ref_tag = os.getenv('tag_act').split('/')[-1]\n          access_token = os.getenv('access_token')\n          headers = {\n              \"Accept\":\"application/vnd.github.v3+json\",\n              \"Authorization\": f\"token {access_token}\"\n          }\n          url = f\"https://api.github.com/repos/ManimCommunity/manim/releases/tags/{ref_tag}\"\n          c = requests.get(url,headers=headers)\n          upload_url=c.json()['upload_url']\n          with open(os.getenv('GITHUB_OUTPUT'), 'w') as f:\n            print(f\"upload_url={upload_url}\", file=f)\n            print(f\"tag_name={ref_tag[1:]}\", file=f)\n\n    - name: Upload Release Asset\n      if: github.event == 'release'\n      id: upload-release\n      uses: actions/upload-release-asset@v1\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n          upload_url: ${{ steps.create_release.outputs.upload_url }}\n          asset_path: ${{ github.workspace }}/docs/build/html-docs.tar.gz\n          asset_name: manim-htmldocs-${{ steps.create_release.outputs.tag_name }}.tar.gz\n          asset_content_type: application/gzip\n"
  },
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\npip-wheel-metadata/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\n\n*.log\n\n# Sphinx documentation\ndocs/_build/\ndocs/build/\ndocs/source/_autosummary/\ndocs/source/reference/\ndocs/source/_build/\ndocs/rendering_times.csv\n#i18n\ndocs/i18n/gettext/.doctrees\ndocs/i18n/**/*.mo\ndocs/i18n/translatable.po\ndocs/i18n/untranslatable.po\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\njupyter/\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n.python-version\n\n# pipenv\n#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# PEP 582; used by e.g. github.com/David-OConnor/pyflow\n__pypackages__/\n\n# PyCharm\n/.idea/\n\n# Celery stuff\ncelerybeat-schedule\ncelerybeat.pid\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n*.pyc\n*.bak\n.DS_Store\n\n.floo\n.flooignore\n.vscode\n.vs\n*.xml\n*.iml\nmedia\n.eggs/\nbuild/\ndist/\n\n/media_dir.txt\n# ^TODO: Remove the need for this with a proper config file\n\n# Ignore the built dependencies\nthird_party/*\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "default_stages: [pre-commit, pre-push]\nfail_fast: false\nexclude: ^(manim/grpc/gen/|docs/i18n/)\nrepos:\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v6.0.0\n    hooks:\n      - id: check-ast\n        name: Validate Python\n      - id: trailing-whitespace\n      - id: mixed-line-ending\n      - id: end-of-file-fixer\n      - id: check-toml\n        name: Validate pyproject.toml\n\n  - repo: https://github.com/codespell-project/codespell\n    rev: v2.4.1\n    hooks:\n      - id: codespell\n        files: ^.*\\.(py|md|rst)$\n        args: [\"-L\", \"medias,nam\"]\n\n  - repo: https://github.com/astral-sh/ruff-pre-commit\n    rev: v0.14.10\n    hooks:\n      - id: ruff\n        name: ruff lint\n        types: [python]\n        args: [--exit-non-zero-on-fix]\n      - id: ruff-format\n        types: [python]\n\n  - repo: https://github.com/pre-commit/mirrors-mypy\n    rev: v1.19.1\n    hooks:\n      - id: mypy\n        additional_dependencies:\n          [\n            types-backports,\n            types-decorator,\n            types-docutils,\n            types-requests,\n            types-setuptools,\n          ]\n        files: ^manim/\n"
  },
  {
    "path": ".pylintrc",
    "content": "[MASTER]\n\n# A comma-separated list of package or module names from where C extensions may\n# be loaded. Extensions are loading into the active Python interpreter and may\n# run arbitrary code.\nextension-pkg-whitelist=\n\n# Specify a score threshold to be exceeded before program exits with error.\nfail-under=10.0\n\n# Add files or directories to the blacklist. They should be base names, not\n# paths.\nignore=CVS\n\n# Add files or directories matching the regex patterns to the blacklist. The\n# regex matches against base names, not paths.\nignore-patterns=\n\n# Python code to execute, usually for sys.path manipulation such as\n# pygtk.require().\n#init-hook=\n\n# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the\n# number of processors available to use.\njobs=1\n\n# Control the amount of potential inferred values when inferring a single\n# object. This can help the performance when dealing with large functions or\n# complex, nested conditions.\nlimit-inference-results=100\n\n# List of plugins (as comma separated values of python module names) to load,\n# usually to register additional checkers.\nload-plugins=\n\n# Pickle collected data for later comparisons.\npersistent=yes\n\n# When enabled, pylint would attempt to guess common misconfiguration and emit\n# user-friendly hints instead of false-positive error messages.\nsuggestion-mode=yes\n\n# Allow loading of arbitrary C extensions. Extensions are imported into the\n# active Python interpreter and may run arbitrary code.\nunsafe-load-any-extension=no\n\n\n[MESSAGES CONTROL]\n\n# Only show warnings with the listed confidence levels. Leave empty to show\n# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.\nconfidence=\n\n# Disable the message, report, category or checker with the given id(s). You\n# can either give multiple identifiers separated by comma (,) or put this\n# option multiple times (only on the command line, not in the configuration\n# file where it should appear only once). You can also use \"--disable=all\" to\n# disable everything first and then re-enable specific checks. For example, if\n# you want to run only the similarities checker, you can use \"--disable=all\n# --enable=similarities\". If you want to run only the classes checker, but have\n# no Warning level messages displayed, use \"--disable=all --enable=classes\n# --disable=W\".\ndisable=print-statement,\n        parameter-unpacking,\n        unpacking-in-except,\n        old-raise-syntax,\n        backtick,\n        long-suffix,\n        old-ne-operator,\n        old-octal-literal,\n        import-star-module-level,\n        non-ascii-bytes-literal,\n        raw-checker-failed,\n        bad-inline-option,\n        locally-disabled,\n        file-ignored,\n        suppressed-message,\n        useless-suppression,\n        deprecated-pragma,\n        use-symbolic-message-instead,\n        apply-builtin,\n        basestring-builtin,\n        buffer-builtin,\n        cmp-builtin,\n        coerce-builtin,\n        execfile-builtin,\n        file-builtin,\n        long-builtin,\n        raw_input-builtin,\n        reduce-builtin,\n        standarderror-builtin,\n        unicode-builtin,\n        xrange-builtin,\n        coerce-method,\n        delslice-method,\n        getslice-method,\n        setslice-method,\n        no-absolute-import,\n        old-division,\n        dict-iter-method,\n        dict-view-method,\n        next-method-called,\n        metaclass-assignment,\n        indexing-exception,\n        raising-string,\n        reload-builtin,\n        oct-method,\n        hex-method,\n        nonzero-method,\n        cmp-method,\n        input-builtin,\n        round-builtin,\n        intern-builtin,\n        unichr-builtin,\n        map-builtin-not-iterating,\n        zip-builtin-not-iterating,\n        range-builtin-not-iterating,\n        filter-builtin-not-iterating,\n        using-cmp-argument,\n        eq-without-hash,\n        div-method,\n        idiv-method,\n        rdiv-method,\n        exception-message-attribute,\n        invalid-str-codec,\n        sys-max-int,\n        bad-python3-import,\n        deprecated-string-function,\n        deprecated-str-translate-call,\n        deprecated-itertools-function,\n        deprecated-types-field,\n        next-method-defined,\n        dict-items-not-iterating,\n        dict-keys-not-iterating,\n        dict-values-not-iterating,\n        deprecated-operator-function,\n        deprecated-urllib-function,\n        xreadlines-attribute,\n        deprecated-sys-function,\n        exception-escape,\n        comprehension-escape,\n        fixme,\n        missing-function-docstring\n\n# Enable the message, report, category or checker with the given id(s). You can\n# either give multiple identifier separated by comma (,) or put this option\n# multiple time (only on the command line, not in the configuration file where\n# it should appear only once). See also the \"--disable\" option for examples.\nenable=c-extension-no-member\n\n\n[REPORTS]\n\n# Python expression which should return a score less than or equal to 10. You\n# have access to the variables 'error', 'warning', 'refactor', and 'convention'\n# which contain the number of messages in each category, as well as 'statement'\n# which is the total number of statements analyzed. This score is used by the\n# global evaluation report (RP0004).\nevaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)\n\n# Template used to display messages. This is a python new-style format string\n# used to format the message information. See doc for all details.\n#msg-template=\n\n# Set the output format. Available formats are text, parseable, colorized, json\n# and msvs (visual studio). You can also give a reporter class, e.g.\n# mypackage.mymodule.MyReporterClass.\noutput-format=text\n\n# Tells whether to display a full report or only the messages.\nreports=no\n\n# Activate the evaluation score.\nscore=yes\n\n\n[REFACTORING]\n\n# Maximum number of nested blocks for function / method body\nmax-nested-blocks=5\n\n# Complete name of functions that never returns. When checking for\n# inconsistent-return-statements if a never returning function is called then\n# it will be considered as an explicit return statement and no message will be\n# printed.\nnever-returning-functions=sys.exit\n\n\n[BASIC]\n\n# Naming style matching correct argument names.\nargument-naming-style=snake_case\n\n# Regular expression matching correct argument names. Overrides argument-\n# naming-style.\n#argument-rgx=\n\n# Naming style matching correct attribute names.\nattr-naming-style=snake_case\n\n# Regular expression matching correct attribute names. Overrides attr-naming-\n# style.\n#attr-rgx=\n\n# Bad variable names which should always be refused, separated by a comma.\nbad-names=foo,\n          bar,\n          baz,\n          toto,\n          tutu,\n          tata\n\n# Bad variable names regexes, separated by a comma. If names match any regex,\n# they will always be refused\nbad-names-rgxs=\n\n# Naming style matching correct class attribute names.\nclass-attribute-naming-style=any\n\n# Regular expression matching correct class attribute names. Overrides class-\n# attribute-naming-style.\n#class-attribute-rgx=\n\n# Naming style matching correct class names.\nclass-naming-style=PascalCase\n\n# Regular expression matching correct class names. Overrides class-naming-\n# style.\n#class-rgx=\n\n# Naming style matching correct constant names.\nconst-naming-style=UPPER_CASE\n\n# Regular expression matching correct constant names. Overrides const-naming-\n# style.\n#const-rgx=\n\n# Minimum line length for functions/classes that require docstrings, shorter\n# ones are exempt.\ndocstring-min-length=-1\n\n# Naming style matching correct function names.\nfunction-naming-style=snake_case\n\n# Regular expression matching correct function names. Overrides function-\n# naming-style.\n#function-rgx=\n\n# Good variable names which should always be accepted, separated by a comma.\ngood-names=i,\n           j,\n           k,\n           e,\n           Run,\n           _\n\n# Good variable names regexes, separated by a comma. If names match any regex,\n# they will always be accepted\ngood-names-rgxs=\n\n# Include a hint for the correct naming format with invalid-name.\ninclude-naming-hint=no\n\n# Naming style matching correct inline iteration names.\ninlinevar-naming-style=any\n\n# Regular expression matching correct inline iteration names. Overrides\n# inlinevar-naming-style.\n#inlinevar-rgx=\n\n# Naming style matching correct method names.\nmethod-naming-style=snake_case\n\n# Regular expression matching correct method names. Overrides method-naming-\n# style.\n#method-rgx=\n\n# Naming style matching correct module names.\nmodule-naming-style=snake_case\n\n# Regular expression matching correct module names. Overrides module-naming-\n# style.\n#module-rgx=\n\n# Colon-delimited sets of names that determine each other's naming style when\n# the name regexes allow several styles.\nname-group=\n\n# Regular expression which should only match function or class names that do\n# not require a docstring.\nno-docstring-rgx=^_\n\n# List of decorators that produce properties, such as abc.abstractproperty. Add\n# to this list to register other decorators that produce valid properties.\n# These decorators are taken in consideration only for invalid-name.\nproperty-classes=abc.abstractproperty\n\n# Naming style matching correct variable names.\nvariable-naming-style=snake_case\n\n# Regular expression matching correct variable names. Overrides variable-\n# naming-style.\n#variable-rgx=\n\n\n[STRING]\n\n# This flag controls whether inconsistent-quotes generates a warning when the\n# character used as a quote delimiter is used inconsistently within a module.\ncheck-quote-consistency=no\n\n# This flag controls whether the implicit-str-concat should generate a warning\n# on implicit string concatenation in sequences defined over several lines.\ncheck-str-concat-over-line-jumps=no\n\n\n[FORMAT]\n\n# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.\nexpected-line-ending-format=\n\n# Regexp for a line that is allowed to be longer than the limit.\nignore-long-lines=^\\s*(# )?<?https?://\\S+>?$\n\n# Number of spaces of indent required inside a hanging or continued line.\nindent-after-paren=4\n\n# String used as indentation unit. This is usually \"    \" (4 spaces) or \"\\t\" (1\n# tab).\nindent-string='    '\n\n# Maximum number of characters on a single line.\nmax-line-length=88\n\n# Maximum number of lines in a module.\nmax-module-lines=1000\n\n# Allow the body of a class to be on the same line as the declaration if body\n# contains single statement.\nsingle-line-class-stmt=no\n\n# Allow the body of an if to be on the same line as the test if there is no\n# else.\nsingle-line-if-stmt=no\n\n\n[SPELLING]\n\n# Limits count of emitted suggestions for spelling mistakes.\nmax-spelling-suggestions=4\n\n# Spelling dictionary name. Available dictionaries: none. To make it work,\n# install the python-enchant package.\nspelling-dict=\n\n# List of comma separated words that should not be checked.\nspelling-ignore-words=\n\n# A path to a file that contains the private dictionary; one word per line.\nspelling-private-dict-file=\n\n# Tells whether to store unknown words to the private dictionary (see the\n# --spelling-private-dict-file option) instead of raising a message.\nspelling-store-unknown-words=no\n\n\n[TYPECHECK]\n\n# List of decorators that produce context managers, such as\n# contextlib.contextmanager. Add to this list to register other decorators that\n# produce valid context managers.\ncontextmanager-decorators=contextlib.contextmanager\n\n# List of members which are set dynamically and missed by pylint inference\n# system, and so shouldn't trigger E1101 when accessed. Python regular\n# expressions are accepted.\ngenerated-members=\n\n# Tells whether missing members accessed in mixin class should be ignored. A\n# mixin class is detected if its name ends with \"mixin\" (case insensitive).\nignore-mixin-members=yes\n\n# Tells whether to warn about missing members when the owner of the attribute\n# is inferred to be None.\nignore-none=yes\n\n# This flag controls whether pylint should warn about no-member and similar\n# checks whenever an opaque object is returned when inferring. The inference\n# can return multiple potential results while evaluating a Python object, but\n# some branches might not be evaluated, which results in partial inference. In\n# that case, it might be useful to still emit no-member and other checks for\n# the rest of the inferred objects.\nignore-on-opaque-inference=yes\n\n# List of class names for which member attributes should not be checked (useful\n# for classes with dynamically set attributes). This supports the use of\n# qualified names.\nignored-classes=optparse.Values,thread._local,_thread._local\n\n# List of module names for which member attributes should not be checked\n# (useful for modules/projects where namespaces are manipulated during runtime\n# and thus existing member attributes cannot be deduced by static analysis). It\n# supports qualified module names, as well as Unix pattern matching.\nignored-modules=\n\n# Show a hint with possible names when a member name was not found. The aspect\n# of finding the hint is based on edit distance.\nmissing-member-hint=yes\n\n# The minimum edit distance a name should have in order to be considered a\n# similar match for a missing member name.\nmissing-member-hint-distance=1\n\n# The total number of similar names that should be taken in consideration when\n# showing a hint for a missing member.\nmissing-member-max-choices=1\n\n# List of decorators that change the signature of a decorated function.\nsignature-mutators=\n\n\n[VARIABLES]\n\n# List of additional names supposed to be defined in builtins. Remember that\n# you should avoid defining new builtins when possible.\nadditional-builtins=\n\n# Tells whether unused global variables should be treated as a violation.\nallow-global-unused-variables=yes\n\n# List of strings which can identify a callback function by name. A callback\n# name must start or end with one of those strings.\ncallbacks=cb_,\n          _cb\n\n# A regular expression matching the name of dummy variables (i.e. expected to\n# not be used).\ndummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_\n\n# Argument names that match this expression will be ignored. Default to name\n# with leading underscore.\nignored-argument-names=_.*|^ignored_|^unused_\n\n# Tells whether we should check for unused import in __init__ files.\ninit-import=no\n\n# List of qualified module names which can have objects that can redefine\n# builtins.\nredefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io\n\n\n[SIMILARITIES]\n\n# Ignore comments when computing similarities.\nignore-comments=yes\n\n# Ignore docstrings when computing similarities.\nignore-docstrings=yes\n\n# Ignore imports when computing similarities.\nignore-imports=no\n\n# Minimum lines number of a similarity.\nmin-similarity-lines=4\n\n\n[MISCELLANEOUS]\n\n# List of note tags to take in consideration, separated by a comma.\nnotes=FIXME,\n      XXX,\n      TODO\n\n# Regular expression of note tags to take in consideration.\n#notes-rgx=\n\n\n[LOGGING]\n\n# The type of string formatting that logging methods do. `old` means using %\n# formatting, `new` is for `{}` formatting.\nlogging-format-style=old\n\n# Logging modules to check that the string format arguments are in logging\n# function parameter format.\nlogging-modules=logging\n\n\n[DESIGN]\n\n# Maximum number of arguments for function / method.\nmax-args=5\n\n# Maximum number of attributes for a class (see R0902).\nmax-attributes=7\n\n# Maximum number of boolean expressions in an if statement (see R0916).\nmax-bool-expr=5\n\n# Maximum number of branch for function / method body.\nmax-branches=12\n\n# Maximum number of locals for function / method body.\nmax-locals=15\n\n# Maximum number of parents for a class (see R0901).\nmax-parents=7\n\n# Maximum number of public methods for a class (see R0904).\nmax-public-methods=20\n\n# Maximum number of return / yield for function / method body.\nmax-returns=6\n\n# Maximum number of statements in function / method body.\nmax-statements=50\n\n# Minimum number of public methods for a class (see R0903).\nmin-public-methods=2\n\n\n[IMPORTS]\n\n# List of modules that can be imported at any level, not just the top level\n# one.\nallow-any-import-level=\n\n# Allow wildcard imports from modules that define __all__.\nallow-wildcard-with-all=no\n\n# Analyse import fallback blocks. This can be used to support both Python 2 and\n# 3 compatible code, which means that the block might have code that exists\n# only in one or another interpreter, leading to false positives when analysed.\nanalyse-fallback-blocks=no\n\n# Deprecated modules which should not be used, separated by a comma.\ndeprecated-modules=optparse,tkinter.tix\n\n# Create a graph of external dependencies in the given file (report RP0402 must\n# not be disabled).\next-import-graph=\n\n# Create a graph of every (i.e. internal and external) dependencies in the\n# given file (report RP0402 must not be disabled).\nimport-graph=\n\n# Create a graph of internal dependencies in the given file (report RP0402 must\n# not be disabled).\nint-import-graph=\n\n# Force import order to recognize a module as part of the standard\n# compatibility libraries.\nknown-standard-library=\n\n# Force import order to recognize a module as part of a third party library.\nknown-third-party=enchant\n\n# Couples of modules and preferred modules, separated by a comma.\npreferred-modules=\n\n\n[CLASSES]\n\n# List of method names used to declare (i.e. assign) instance attributes.\ndefining-attr-methods=__init__,\n                      __new__,\n                      setUp,\n                      __post_init__\n\n# List of member names, which should be excluded from the protected access\n# warning.\nexclude-protected=_asdict,\n                  _fields,\n                  _replace,\n                  _source,\n                  _make\n\n# List of valid names for the first argument in a class method.\nvalid-classmethod-first-arg=cls\n\n# List of valid names for the first argument in a metaclass class method.\nvalid-metaclass-classmethod-first-arg=cls\n\n\n[EXCEPTIONS]\n\n# Exceptions that will emit a warning when being caught. Defaults to\n# \"BaseException, Exception\".\novergeneral-exceptions=BaseException,\n                       Exception\n"
  },
  {
    "path": ".readthedocs.yml",
    "content": "version: 2\n\nsphinx:\n  configuration: docs/source/conf.py\n\nbuild:\n  os: ubuntu-22.04\n\n  tools:\n    python: \"3.13\"\n\n  apt_packages:\n    - libpango1.0-dev\n    - graphviz\n\npython:\n   install:\n      - requirements: docs/rtd-requirements.txt\n      - requirements: docs/requirements.txt\n      - method: pip\n        path: .\n"
  },
  {
    "path": "CITATION.cff",
    "content": "# YAML 1.2\n---\nauthors:\n  -\n    name: \"The Manim Community Developers\"\ncff-version: \"1.2.0\"\ndate-released: 2026-02-27\nlicense: MIT\nmessage: \"We acknowledge the importance of good software to support research, and we note that research becomes more valuable when it is communicated effectively. To demonstrate the value of Manim, we ask that you cite Manim in your work.\"\ntitle: Manim – Mathematical Animation Framework\nurl: \"https://www.manim.community/\"\nversion: \"v0.20.1\"\n...\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "\n\n# Code of Conduct\n\n\n\n   > TL;DR Be excellent to each other; we're a community after all. If you run into issues with others in our community, please [contact](https://www.manim.community/discord/) a Manim Community Dev, or Moderator.\n\n## Purpose\n\nThe Manim Community includes members of varying skills, languages, personalities, cultural backgrounds, and experiences from around the globe. Through these differences, we continue to grow and collectively improve upon an open-source animation engine. When working in a community, it is important to remember that you are interacting with humans on the other end of your screen. This code of conduct will guide your interactions and keep Manim a positive environment for our developers, users, and fundamentally our growing community.\n\n\n\n## Our Community\n\nMembers of Manim Community are respectful, open, and considerate. Behaviors that reinforce these values contribute to our positive environment, and include:\n\n- **Being respectful.** Respectful of others, their positions, experiences, viewpoints, skills, commitments, time, and efforts.\n\n- **Being open.** Open to collaboration, whether it's on problems, Pull Requests, issues, or otherwise.\n\n- **Being considerate.** Considerate of their peers -- other Manim users and developers.\n\n- **Focusing on what is best for the community.** We're respectful of the processes set forth in the community, and we work within them.\n\n- **Showing empathy towards other community members.** We're attentive in our communications, whether in person or online, and we're tactful when approaching differing views.\n\n- **Gracefully accepting constructive criticism.** When we disagree, we are courteous in raising our issues.\n\n- **Using welcoming and inclusive language.** We're accepting of all who wish to take part in our activities, fostering an environment where anyone can participate and everyone can make a difference.\n\n\n\n## Our Standards\n\nEvery member of our community has the right to have their identity respected. Manim Community is dedicated to providing a positive environment for everyone, regardless of age, gender identity and expression, sexual orientation, disability, physical appearance, body size, ethnicity, nationality, race, religion (or lack thereof), education, or socioeconomic status.\n\n\n\n## Inappropriate Behavior\n\nExamples of unacceptable behavior by participants include:\n\n   * Harassment of any participants in any form\n   * Deliberate intimidation, stalking, or following\n   * Logging or taking screenshots of online activity for harassment purposes\n   * Publishing others' private information, such as a physical or electronic address, without explicit permission\n   * Violent threats or language directed against another person\n   * Incitement of violence or harassment towards any individual, including encouraging a person to commit suicide or to engage in self-harm\n   * Creating additional online accounts in order to harass another person or circumvent a ban\n   * Sexual language and imagery in online communities or any conference venue, including talks\n   * Insults, put-downs, or jokes that are based upon stereotypes, that are exclusionary, or that hold others up for ridicule\n   * Excessive swearing\n   * Unwelcome sexual attention or advances\n   * Unwelcome physical contact, including simulated physical contact (eg, textual descriptions like \"hug\" or \"backrub\") without consent or after a request to stop\n   * Pattern of inappropriate social contact, such as requesting/assuming inappropriate levels of intimacy with others\n   * Sustained disruption of online community discussions, in-person presentations, or other in-person events\n   * Continued one-on-one communication after requests to cease\n   * Other conduct that is inappropriate for a professional audience including people of many different backgrounds\nCommunity members asked to stop any inappropriate behavior are expected to comply immediately.\n\n\n\n## Manim Community Online Spaces\n\nThis Code of Conduct applies to the following online spaces:\n\n- The [ManimCommunity GitHub Organization](https://github.com/ManimCommunity) and all of its repositories\n\n- The Manim [Discord](https://www.manim.community/discord/)\n\n- The Manim [Reddit](https://www.reddit.com/r/manim/)\n\n- The Manim [Twitter](https://twitter.com/manim\\_community/)\n\nThis Code of Conduct applies to every member in official Manim Community online spaces, including:\n\n- Moderators\n\n- Maintainers\n\n- Developers\n\n- Reviewers\n\n- Contributors\n\n- Users\n\n- All community members\n\n\n\n## Consequences\n\nIf a member's behavior violates this code of conduct, the Manim Community Code of Conduct team may take any action they deem appropriate, including, but not limited to: warning the offender, temporary bans, deletion of offending messages, and expulsion from the community and its online spaces. The full list of consequences for inappropriate behavior is listed below in the Enforcement Procedures.\n\n\n\nThank you for helping make this a welcoming, friendly community for everyone.\n\n\n\n## Contact Information\n\nIf you believe someone is violating the code of conduct, or have any other concerns, please contact a Manim Community Dev, or Moderator immediately. They can be reached on Manim's Community [Discord](https://www.manim.community/discord/).\n\n\n\n\n\n<hr style=\"border:2px solid gray\"> </hr>\n<hr style=\"border:2px solid gray\"> </hr>\n\n\n## Enforcement Procedures\n\nThis document summarizes the procedures the Manim Community Code of Conduct team uses to enforce the Code of Conduct.\n\n\n\n### Summary of processes\n\nWhen the team receives a report of a possible Code of Conduct violation, it will:\n\n   1. Acknowledge the receipt of the report.\n   1. Evaluate conflicts of interest.\n   1. Call a meeting of code of conduct team members without a conflict of interest.\n   1. Evaluate the reported incident.\n   1. Propose a behavioral modification plan.\n   1. Propose consequences for the reported behavior.\n   1. Vote on behavioral modification plan and consequences for the reported person.\n   1. Contact Manim Community moderators to approve the behavioral modification plan and consequences.\n   1. Follow up with the reported person.\n   1. Decide further responses.\n   1. Follow up with the reporter.\n\n\n### Acknowledge the report\n\nReporters should receive an acknowledgment of the receipt of their report within 48 hours.\n\n\n\n### Conflict of interest policy\n\nExamples of conflicts of interest include:\n\n   * You have a romantic or platonic relationship with either the reporter or the reported person. It's fine to participate if they are an acquaintance.\n   * The reporter or reported person is someone you work closely with. This could be someone on your team or someone who works on the same project as you.\n   * The reporter or reported person is a maintainer who regularly reviews your contributions\n   * The reporter or reported person is your metamour.\n   * The reporter or reported person is your family member\n\nCommittee members do not need to state why they have a conflict of interest, only that one exists. Other team members should not ask why the person has a conflict of interest.\n\nAnyone who has a conflict of interest will remove themselves from the discussion of the incident, and recluse themselves from voting on a response to the report.\n\n\n\n### Evaluating a report\n\n#### Jurisdiction\n\n   * *Is this a Code of Conduct violation?* Is this behavior on our list of inappropriate behavior? Is it borderline inappropriate behavior? Does it violate our community norms?\n   * *Did this occur in a space that is within our Code of Conduct's scope?* If the incident occurred outside the community, but a community member's mental health or physical safety may be negatively impacted if no action is taken, the incident may be in scope. Private conversations in community spaces are also in scope.\n#### Impact\n\n   * *Did this incident occur in a private conversation or a public space?* Incidents that all community members can see will have a more negative impact.\n   * *Does this behavior negatively impact a marginalized group in our community?* Is the reporter a person from a marginalized group in our community? How is the reporter being negatively impacted by the reported person's behavior? Are members of the marginalized group likely to disengage with the community if no action was taken on this report?\n   * *Does this incident involve a community leader?* Community members often look up to community leaders to set the standard of acceptable behavior\n#### Risk\n\n   * *Does this incident include sexual harassment?*\n   * *Does this pose a safety risk?* Does the behavior put a person's physical safety at risk? Will this incident severely negatively impact someone's mental health?\n   * *Is there a risk of this behavior being repeated?* Does the reported person understand why their behavior was inappropriate? Is there an established pattern of behavior from past reports?\n\n\nReports which involve higher risk or higher impact may face more severe consequences than reports which involve lower risk or lower impact.\n\n\n\n### Propose consequences\n\nWhat follows are examples of possible consequences of an incident report. This list of consequences is not exhaustive, and the Manim Community Code of Conduct team reserves the right to take any action it deems necessary.\n\nPossible private responses to an incident include:\n\n   * Nothing, if the behavior was determined to not be a Code of Conduct violation\n   * A warning\n   * A final warning\n   * Temporarily removing the reported person from the community's online space(s)\n   * Permanently removing the reported person from the community's online space(s)\n   * Publishing an account of the incident\n\n\n### Team vote\n\nSome team members may have a conflict of interest and may be excluded from discussions of a particular incident report. Excluding those members, decisions on the behavioral modification plans and consequences will be determined by a two-thirds majority vote of the Manim Community Code of Conduct team.\n\n\n\n### Moderators approval\n\nOnce the team has approved the behavioral modification plans and consequences, they will communicate the recommended response to the Manim Community moderators. The team should not state who reported this incident. They should attempt to anonymize any identifying information from the report.\n\nModerators are required to respond with whether they accept the recommended response to the report. If they disagree with the recommended response, they should provide a detailed response or additional context as to why they disagree. Moderators are encouraged to respond within a week.\n\nIn cases where the moderators disagree on the suggested resolution for a report, the Manim Community Code of Conduct team may choose to notify the Manim Community Moderators.\n\n\n\n### Follow up with the reported person\n\nThe Manim Community Code of Conduct team will work with Manim Community moderators to draft a response to the reported person. The response should contain:\n\n   * A description of the person's behavior in neutral language\n   * The negative impact of that behavior\n   * A concrete behavioral modification plan\n   * Any consequences of their behavior\nThe team should not state who reported this incident. They should attempt to anonymize any identifying information from the report. The reported person should be discouraged from contacting the reporter to discuss the report. If they wish to apologize to the reporter, the team can accept the apology on behalf of the reporter.\n\n\n\n### Decide further responses\n\nIf the reported person provides additional context, the Manim Community Code of Conduct team may need to re-evaluate the behavioral modification plan and consequences.\n\n### Follow up with the reporter\n\nA person who makes a report should receive a follow-up response stating what action was taken in response to the report. If the team decided no response was needed, they should provide an explanation why it was not a Code of Conduct violation. Reports that are not made in good faith (such as \"reverse sexism\" or \"reverse racism\") may receive no response.\n\nThe follow-up should be sent no later than one week after the receipt of the report. If deliberation or follow-up with the reported person takes longer than one week, the team should send a status update to the reporter.\n\n\n\n### Changes to Code of Conduct\n\nWhen discussing a change to the Manim Community code of conduct or enforcement procedures, the Manim Community Code of Conduct team will follow this decision-making process:\n\n   * **Brainstorm options.** Team members should discuss any relevant context and brainstorm a set of possible options. It is important to provide constructive feedback without getting side-tracked from the main question.\n   * **Vote.** Proposed changes to the code of conduct will be decided by a two-thirds majority of all voting members of the Code of Conduct team. Team members are listed in the charter. Currently active voting members are listed in the following section.\n   * **Board Vote.** Once a working draft is in place for the Code of Conduct and procedures, the Code of Conduct team shall provide the Manim Community Moderators with a draft of the changes. The Manim Community Moderators will vote on the changes at a board meeting.\n\n\n### Current list of voting members\n\n- All available Community Developers (i.e. those with \"write\" permissions, or above, on the Manim Community GitHub organization).\n\n\n\n## License\n\nThis Code of Conduct is licensed under the [Creative Commons Attribution-ShareAlike 3.0 Unported License](https://creativecommons.org/licenses/by-sa/3.0/).\n\n\n\n## Attributions\n\nThis Code of Conduct was forked from the code of conduct from the [Python Software Foundation](https://www.python.org/psf/conduct/) and adapted by Manim Community.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Thanks for your interest in contributing!\n\nPlease read our contributing guidelines which are hosted at https://docs.manim.community/en/latest/contributing.html\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 3Blue1Brown LLC\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "LICENSE.community",
    "content": "MIT License\n\nCopyright (c) 2024, the Manim Community Developers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n    <a href=\"https://www.manim.community/\"><img src=\"https://raw.githubusercontent.com/ManimCommunity/manim/main/logo/cropped.png\" alt=\"Manim Community logo\"></a>\n    <br />\n    <br />\n    <a href=\"https://pypi.org/project/manim/\"><img src=\"https://img.shields.io/pypi/v/manim.svg?style=flat&logo=pypi\" alt=\"PyPI Latest Release\"></a>\n    <a href=\"https://hub.docker.com/r/manimcommunity/manim\"><img src=\"https://img.shields.io/docker/v/manimcommunity/manim?color=%23099cec&label=docker%20image&logo=docker\" alt=\"Docker image\"> </a>\n    <a href=\"https://mybinder.org/v2/gh/ManimCommunity/jupyter_examples/HEAD?filepath=basic_example_scenes.ipynb\"><img src=\"https://mybinder.org/badge_logo.svg\" alt=\"Launch Binder\"></a>\n    <a href=\"http://choosealicense.com/licenses/mit/\"><img src=\"https://img.shields.io/badge/license-MIT-red.svg?style=flat\" alt=\"MIT License\"></a>\n    <a href=\"https://www.reddit.com/r/manim/\"><img src=\"https://img.shields.io/reddit/subreddit-subscribers/manim.svg?color=orange&label=reddit&logo=reddit\" alt=\"Reddit\" href=></a>\n    <a href=\"https://twitter.com/manimcommunity/\"><img src=\"https://img.shields.io/twitter/url/https/twitter.com/cloudposse.svg?style=social&label=Follow%20%40manimcommunity\" alt=\"Twitter\">\n    <a href=\"https://manim.community/discord/\"><img src=\"https://img.shields.io/discord/581738731934056449.svg?label=discord&color=yellow&logo=discord\" alt=\"Discord\"></a>\n    <a href=\"https://docs.manim.community/\"><img src=\"https://readthedocs.org/projects/manimce/badge/?version=latest\" alt=\"Documentation Status\"></a>\n    <img src=\"https://github.com/ManimCommunity/manim/workflows/CI/badge.svg\" alt=\"CI\">\n    <br />\n    <br />\n    <i>An animation engine for explanatory math videos</i>\n</p>\n<hr />\n\nManim is an animation engine for explanatory math videos. It's used to create precise animations programmatically, as demonstrated in the videos of [3Blue1Brown](https://www.3blue1brown.com/).\n\n> [!NOTE]\n> The community edition of Manim (ManimCE) is a version maintained and developed by the community. It was forked from 3b1b/manim, a tool originally created and open-sourced by Grant Sanderson, also creator of the 3Blue1Brown educational math videos. While Grant Sanderson continues to maintain his own repository, we recommend this version for its continued development, improved features, enhanced documentation, and more active community-driven maintenance. If you would like to study how Grant makes his videos, head over to his repository ([3b1b/manim](https://github.com/3b1b/manim)).\n\n## Table of Contents:\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Documentation](#documentation)\n- [Docker](#docker)\n- [Help with Manim](#help-with-manim)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Installation\n\n> [!CAUTION]\n> These instructions are for the community version _only_. Trying to use these instructions to install [3b1b/manim](https://github.com/3b1b/manim) or instructions there to install this version will cause problems. Read [this](https://docs.manim.community/en/stable/faq/installation.html#why-are-there-different-versions-of-manim) and decide which version you wish to install, then only follow the instructions for your desired version.\n\nManim requires a few dependencies that must be installed prior to using it. If you\nwant to try it out first before installing it locally, you can do so\n[in our online Jupyter environment](https://try.manim.community/).\n\nFor local installation, please visit the [Documentation](https://docs.manim.community/en/stable/installation.html)\nand follow the appropriate instructions for your operating system.\n\n## Usage\n\nManim is an extremely versatile package. The following is an example `Scene` you can construct:\n\n```python\nfrom manim import *\n\n\nclass SquareToCircle(Scene):\n    def construct(self):\n        circle = Circle()\n        square = Square()\n        square.flip(RIGHT)\n        square.rotate(-3 * TAU / 8)\n        circle.set_fill(PINK, opacity=0.5)\n\n        self.play(Create(square))\n        self.play(Transform(square, circle))\n        self.play(FadeOut(square))\n```\n\nIn order to view the output of this scene, save the code in a file called `example.py`. Then, run the following in a terminal window:\n\n```sh\nmanim -p -ql example.py SquareToCircle\n```\n\nYou should see your native video player program pop up and play a simple scene in which a square is transformed into a circle. You may find some more simple examples within this\n[GitHub repository](example_scenes). You can also visit the [official gallery](https://docs.manim.community/en/stable/examples.html) for more advanced examples.\n\nManim also ships with a `%%manim` IPython magic which allows to use it conveniently in JupyterLab (as well as classic Jupyter) notebooks. See the\n[corresponding documentation](https://docs.manim.community/en/stable/reference/manim.utils.ipython_magic.ManimMagic.html) for some guidance and\n[try it out online](https://mybinder.org/v2/gh/ManimCommunity/jupyter_examples/HEAD?filepath=basic_example_scenes.ipynb).\n\n## Command line arguments\n\nThe general usage of Manim is as follows:\n\n![manim-illustration](https://raw.githubusercontent.com/ManimCommunity/manim/main/docs/source/_static/command.png)\n\nThe `-p` flag in the command above is for previewing, meaning the video file will automatically open when it is done rendering. The `-ql` flag is for a faster rendering at a lower quality.\n\nSome other useful flags include:\n\n- `-s` to skip to the end and just show the final frame.\n- `-n <number>` to skip ahead to the `n`'th animation of a scene.\n- `-f` show the file in the file browser.\n\nFor a thorough list of command line arguments, visit the [documentation](https://docs.manim.community/en/stable/guides/configuration.html).\n\n## Documentation\n\nDocumentation is in progress at [ReadTheDocs](https://docs.manim.community/).\n\n## Docker\n\nThe community also maintains a docker image (`manimcommunity/manim`), which can be found [on DockerHub](https://hub.docker.com/r/manimcommunity/manim).\nInstructions on how to install and use it can be found in our [documentation](https://docs.manim.community/en/stable/installation/docker.html).\n\n## Help with Manim\n\nIf you need help installing or using Manim, feel free to reach out to our [Discord\nServer](https://www.manim.community/discord/) or [Reddit Community](https://www.reddit.com/r/manim). If you would like to submit a bug report or feature request, please open an issue.\n\n## Contributing\n\nContributions to Manim are always welcome. In particular, there is a dire need for tests and documentation. For contribution guidelines, please see the [documentation](https://docs.manim.community/en/stable/contributing.html).\n\nHowever, please note that Manim is currently undergoing a major refactor. In general,\ncontributions implementing new features will not be accepted in this period.\nThe contribution guide may become outdated quickly; we highly recommend joining our\n[Discord server](https://www.manim.community/discord/) to discuss any potential\ncontributions and keep up to date with the latest developments.\n\nMost developers on the project use `uv` for management. You'll want to have uv installed and available in your environment.\nLearn more about `uv` at its [documentation](https://docs.astral.sh/uv/) and find out how to install manim with uv at the [manim dev-installation guide](https://docs.manim.community/en/latest/contributing/development.html) in the manim documentation.\n\n## How to Cite Manim\n\nWe acknowledge the importance of good software to support research, and we note\nthat research becomes more valuable when it is communicated effectively. To\ndemonstrate the value of Manim, we ask that you cite Manim in your work.\nCurrently, the best way to cite Manim is to go to our\n[repository page](https://github.com/ManimCommunity/manim) (if you aren't already) and\nclick the \"cite this repository\" button on the right sidebar. This will generate\na citation in your preferred format, and will also integrate well with citation managers.\n\n## Code of Conduct\n\nOur full code of conduct, and how we enforce it, can be read on [our website](https://docs.manim.community/en/stable/conduct.html).\n\n## License\n\nThe software is double-licensed under the MIT license, with copyright by 3blue1brown LLC (see LICENSE), and copyright by Manim Community Developers (see LICENSE.community).\n"
  },
  {
    "path": "crowdin.yml",
    "content": "files:\n  - source: /docs/i18n/gettext/**/*.pot\n    translation: /docs/i18n/%two_letters_code%/LC_MESSAGES/**/%file_name%.po\n"
  },
  {
    "path": "docker/Dockerfile",
    "content": "# ── Stage 1: builder ─────────────────────────────────────────────────────────\nFROM python:3.14-slim AS builder\n\nRUN apt-get update -qq \\\n    && apt-get install --no-install-recommends -y \\\n        build-essential \\\n        gcc \\\n        cmake \\\n        make \\\n        pkg-config \\\n        wget \\\n        libcairo2-dev \\\n        libffi-dev \\\n        libpango1.0-dev \\\n        libegl-dev \\\n    && rm -rf /var/lib/apt/lists/*\n\n# Setup a minimal TeX Live installation (no ctex: drops ~100 MB of CJK fonts/packages)\nCOPY docker/texlive-profile.txt /tmp/\nENV PATH=/usr/local/texlive/bin/armhf-linux:/usr/local/texlive/bin/aarch64-linux:/usr/local/texlive/bin/x86_64-linux:$PATH\nRUN wget -O /tmp/install-tl-unx.tar.gz http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz \\\n    && mkdir /tmp/install-tl \\\n    && tar -xzf /tmp/install-tl-unx.tar.gz -C /tmp/install-tl --strip-components=1 \\\n    && /tmp/install-tl/install-tl --profile=/tmp/texlive-profile.txt \\\n    && tlmgr install \\\n        amsmath babel-english cbfonts-fd cm-super count1to doublestroke dvisvgm everysel \\\n        fontspec frcursive fundus-calligra gnu-freefont jknapltx latex-bin \\\n        mathastext microtype multitoc physics prelim2e preview ragged2e relsize rsfs \\\n        setspace standalone tipa wasy wasysym xcolor xetex xkeyval \\\n    && rm -rf /tmp/install-tl /tmp/install-tl-unx.tar.gz\n\n# Install manim into an isolated virtualenv\nENV VIRTUAL_ENV=/opt/venv\nRUN python -m venv $VIRTUAL_ENV\nENV PATH=\"$VIRTUAL_ENV/bin:$PATH\"\n\nCOPY . /opt/manim\nWORKDIR /opt/manim\nRUN pip install --no-cache-dir .[jupyterlab]\n\n# ── Stage 2: runtime ─────────────────────────────────────────────────────────\nFROM python:3.14-slim\n\n# Runtime libs only:\n#  - no ffmpeg: PyAV (av package) bundles its own ffmpeg libraries in av.libs/\n#  - OpenGL: keep EGL for headless rendering and libGL as required by moderngl/glcontext\n#  - fonts-noto-core instead of fonts-noto (drops CJK noto fonts)\nRUN apt-get update -qq \\\n    && apt-get install --no-install-recommends -y \\\n        libcairo2 \\\n        libpango-1.0-0 \\\n        libpangocairo-1.0-0 \\\n        libpangoft2-1.0-0 \\\n        libffi8 \\\n        libegl1 \\\n        libgl1 \\\n        ghostscript \\\n        fonts-noto-core \\\n        fontconfig \\\n    && rm -rf /var/lib/apt/lists/*\n\nRUN fc-cache -fv\n\n# Copy TeX Live from builder\nENV PATH=/usr/local/texlive/bin/armhf-linux:/usr/local/texlive/bin/aarch64-linux:/usr/local/texlive/bin/x86_64-linux:$PATH\nCOPY --from=builder /usr/local/texlive /usr/local/texlive\n\n# Copy the pre-built virtualenv from builder\nENV VIRTUAL_ENV=/opt/venv\nCOPY --from=builder /opt/venv /opt/venv\nENV PATH=\"$VIRTUAL_ENV/bin:$PATH\"\n\nARG NB_USER=manimuser\nARG NB_UID=1000\nENV USER=${NB_USER}\nENV NB_UID=${NB_UID}\nENV HOME=/manim\n\nRUN adduser --disabled-password \\\n    --gecos \"Default user\" \\\n    --uid ${NB_UID} \\\n    ${NB_USER}\n\nWORKDIR ${HOME}\nRUN chown -R ${NB_USER}:${NB_USER} ${HOME} && chmod 777 ${HOME}\nUSER ${NB_USER}\n\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "docker/readme.md",
    "content": "See the [main README](https://github.com/ManimCommunity/manim/blob/main/README.md) for some instructions on how to use this image.\n\n# Building the image\nThe docker image corresponding to the checked out version of the git repository\ncan be built by running\n```\ndocker build -t manimcommunity/manim:TAG -f docker/Dockerfile .\n```\nfrom the root directory of the repository.\n\nMulti-platform builds are possible by running\n```\ndocker buildx build --push --platform linux/arm64/v8,linux/amd64 --tag manimcommunity/manim:TAG -f docker/Dockerfile .\n```\nfrom the root directory of the repository.\n\n# Runtime notes\n- The image is built via a multi-stage Dockerfile (build dependencies are not\n  carried into the runtime stage).\n- The image does not include the `ffmpeg` CLI binary.\n- The default TeX installation is minimal and does not include `ctex`.\n- Headless OpenGL rendering relies on EGL/GL runtime libraries available in the\n  image.\n"
  },
  {
    "path": "docker/texlive-profile.txt",
    "content": "selected_scheme scheme-minimal\nTEXDIR /usr/local/texlive\nTEXMFCONFIG ~/.texlive/texmf-config\nTEXMFHOME ~/texmf\nTEXMFLOCAL /usr/local/texlive/texmf-local\nTEXMFSYSCONFIG /usr/local/texlive/texmf-config\nTEXMFSYSVAR /usr/local/texlive/texmf-var\nTEXMFVAR ~/.texlive/texmf-var\noption_doc 0\noption_src 0\n"
  },
  {
    "path": "docs/Makefile",
    "content": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line, and also\n# from the environment for the first two.\nSPHINXOPTS    ?=\nSPHINXBUILD   ?= sphinx-build\n\n# Path base is the source directory\nSOURCEDIR     = .\nBUILDDIR      = ../build\n\n# Put it first so that \"make\" without argument is like \"make help\".\nhelp:\n\t@(cd source; $(SPHINXBUILD) -M help \"$(SOURCEDIR)\" \"$(BUILDDIR)\" $(SPHINXOPTS) $(O))\n\n.PHONY: help Makefile i18n\n\n# All the code is executed as if everything was launched in one shell.\n.ONESHELL:\n# Like make clean but also remove files generated by autosummary and\n# rendered videos.\ncleanall: clean\n\t@rm source/reference/*\n\t@rm -rf source/media\n\t@rm -f rendering_times.csv\ni18n:\n\t@(cd source; $(SPHINXBUILD) -M gettext \"$(SOURCEDIR)\" ../i18n/ -t skip-manim $(SPHINXOPTS) $(O);cd ../i18n;bash stripUntranslatable.sh)\n\n# Catch-all target: route all unknown targets to Sphinx using the new\n# \"make mode\" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).\n%: Makefile\n\t@(cd source; $(SPHINXBUILD) -M $@ \"$(SOURCEDIR)\" \"$(BUILDDIR)\" $(SPHINXOPTS) $(O))\n"
  },
  {
    "path": "docs/html",
    "content": ""
  },
  {
    "path": "docs/i18n/fr/LC_MESSAGES/index.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: fr\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/index.pot\\n\"\n\"X-Crowdin-File-ID: 5163\\n\"\n\"Language-Team: French\\n\"\n\"Language: fr_FR\\n\"\n\"PO-Revision-Date: 2021-11-06 12:29\\n\"\n\n#: ../../source/index.rst:7\nmsgid \"Manim Community Overview\"\nmsgstr \"Manim communauté - Vue d'ensemble\"\n\n#: ../../source/index.rst:9\nmsgid \"Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. ``Manim`` uses Python to generate animations programmatically, making it possible to specify exactly how each one should run.\"\nmsgstr \"Animer des concepts techniques est traditionellement plutôt compliqué puisqu'il est difficile de rendre les animations assez precises pour bien représenter ces concepts. ``Manim`` utilise Python pour génerer des animation en programmant, permettant de préciser de manière exacte leur execution.\"\n\n#: ../../source/index.rst:14\nmsgid \"This project is still very much a work in progress, but we hope that the information here will make it easier for newcomers to get started using ``Manim``.\"\nmsgstr \"Ce projet est encore en grande partie en cours de développement, mais nous éspérons que les informations fournies ici permettront aux nouveaux venus de mieux commencer à utiliser ``Manim``.\"\n\n#: ../../source/index.rst:20\nmsgid \"All content of the docs is licensed under the MIT license. Especially for the examples you encounter: Feel free to use this code in your own projects!\"\nmsgstr \"Le contenu de ces documentations est distribué sous licence MIT. C'est aussi vrai pour les exemples présentés, vous pouvez utilisez les codes librement dans vos projets !\"\n\n#: ../../source/index.rst:23\nmsgid \"We are curious to see the awesome projects you build using this library, feel free to share your projects with us `on Twitter <https://twitter.com/manim_community>`_, `Reddit <https://www.reddit.com/r/manim/>`_, or via `Discord <https://www.manim.community/discord/>`_.\"\nmsgstr \"Nous sommes curieux de voir les super projets que vous construisez avec cette librairie, partagez-les donc avec nous `sur Twitter <https://twitter.com/manim_community>`_, `Reddit <https://www.reddit.com/r/manim/>`_, or sur `Discord <https://www.manim.community/discord/>`_. \"\n\n#: ../../source/index.rst:27\nmsgid \"In case you publish your work made with Manim, we would appreciate if you add a link to `our homepage <https://www.manim.community>`_ or `our GitHub repository <https://github.com/ManimCommunity/manim>`_. If you use Manim in a scientific context, instructions on how to cite a particular release can be found `in our README <https://github.com/ManimCommunity/manim/blob/main/README.md>`_.\"\nmsgstr \"Si vous publiez votre travail fait avec Manim, nous apprécierions si vous ajoutiez un lien vers `notre site principal <https://www.manim.community>`_ ou vers `notre repo GitHub <https://github.com/ManimCommunity/manim>`_. Si vous utilisez Manim dans un contexte scientifique, des instructions afin de citer une certaine version de Manim sont disponibles (en anglais) `dans notre fichier README <https://github.com/ManimCommunity/manim/blob/main/README.md>`_.\"\n\n#: ../../source/index.rst:36\nmsgid \"As a quick reference, here are some often used modules, classes and methods:\"\nmsgstr \"Comme rapide indications, voici certains des modules, classes et méthodes les plus utilisées:\"\n\n#: ../../source/index.rst:38\nmsgid \"Modules: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`,\"\nmsgstr \"Modules: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`,\"\n\n#: ../../source/index.rst:43\nmsgid \"Classes: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`,\"\nmsgstr \"Classes: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`,\"\n\n"
  },
  {
    "path": "docs/i18n/fr/LC_MESSAGES/installation.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: fr\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/installation.pot\\n\"\n\"X-Crowdin-File-ID: 5165\\n\"\n\"Language-Team: French\\n\"\n\"Language: fr_FR\\n\"\n\"PO-Revision-Date: 2021-11-06 12:29\\n\"\n\n#: ../../source/installation.rst:2\nmsgid \"Installation\"\nmsgstr \"Installation\"\n\n#: ../../source/installation.rst:4\nmsgid \"Depending on your use case, different installation options are recommended: if you just want to play around with Manim for a bit, interactive in-browser notebooks are a really simple way of exploring the library as they require no local installation. Head over to https://try.manim.community to give our interactive tutorial a try.\"\nmsgstr \"Suivant comment vous souhaitez utiliser Manim, différentes options d'installation s'offrent à vous : Si vous voulez simplement vous amuser avec, les bloc-notes interactifs sur votre navigateur sont un moyen simple d'explorer les possibilités offertes par la bibliothèque, puisqu'ils ne nécessitent pas d'installer quoi que ce soit sur votre ordinateur. Allez donc voir à l'adresse https://try.manim.community pour tester notre tutoriel interactif.\"\n\n#: ../../source/installation.rst:10\nmsgid \"Otherwise, if you intend to use Manim to work on an animation project, we recommend installing the library locally (either to your system's Python, or via Docker).\"\nmsgstr \"Sinon, si vous souhaitez utiliser Manim pour travailler sur un projet d'animation, il vaut mieux installer la bibliothèque sur votre ordinateur (sur le Python de votre sytème, ou via Docker).\"\n\n#: ../../source/installation.rst:16\nmsgid \"Note that there are several different versions of Manim. The instructions on this website are **only** for the *community edition*. Find out more about the :doc:`differences between Manim versions <installation/versions>` if you are unsure which version you should install.\"\nmsgstr \"Prenez garde, il y a plusieurs différentes versions de Manim. Les instructions sur ce site sont **seulement** pour la *version communautaire* (*community edition*). Découvrez en plus sur les :doc:`différences entre les versions de manim <installation/versions>` si vous n'êtes pas sûrs de quelle version installer.\"\n\n#: ../../source/installation.rst:22\nmsgid \":ref:`Installing Manim to your system's Python <local-installation>`\"\nmsgstr \":ref:`Installer Manim sur le Python de votre système <local-installation>`\"\n\n#: ../../source/installation.rst:23\nmsgid \":ref:`Using Manim via Docker <docker-installation>`\"\nmsgstr \":ref:`Utiliser Manim via Docker <docker-installation>`\"\n\n#: ../../source/installation.rst:24\nmsgid \":ref:`Interactive Jupyter notebooks via Binder / Google Colab <interactive-online>`\"\nmsgstr \":ref:`Blocs-notes interactifs Jupyter via Binder / Google Colab <interactive-online>`\"\n\n#: ../../source/installation.rst:31\nmsgid \"Installing Manim locally\"\nmsgstr \"Installation de Manim sur l'ordinateur\"\n\n#: ../../source/installation.rst:33\nmsgid \"Manim is a Python library, and it can be `installed via pip <https://pypi.org/project/manim/>`__. However, in order for Manim to work properly, some additional system dependencies need to be installed first. The following pages have operating system specific instructions for you to follow.\"\nmsgstr \"Manim est une bibliothèque Python, et peut donc être `installée avec pip <https://pypi.org/project/manim/>`__. Par contre, pour que Manim fonctionne correctement, quelques dépendances doivent être installées avant. Les pages suivantes offrent les instructions à suivre selon votre système d'exploitation.\"\n\n#: ../../source/installation.rst:41\nmsgid \"Depending on your particular setup, the installation process might be slightly different. Make sure that you have tried to follow the steps on the following pages carefully, but in case you hit a wall we are happy to help: either `join our Discord <https://www.manim.community/discord/>`__, or start a new Discussion `directly on GitHub <https://github.com/ManimCommunity/manim/discussions>`__.\"\nmsgstr \"Suivant la configuration particulière de votre ordinateur, le processus d'installation peut varier légèrement. Assurez-vous d'avoir essayé de suivre avec attention les étapes sur les pages ci-dessous, mais si vous faites face à un problème, nous serons heureux de vous aider : vous pouvez `rejoindre notre serveur Discord <https://www.manim.community/discord/>`__, ou vous pouvez lancer une nouvelle Discussion `directement sur GitHub <https://github.com/ManimCommunity/manim/discussions>`__.\"\n\n#: ../../source/installation.rst:57\nmsgid \"Once Manim is installed locally, you can proceed to our :doc:`quickstart guide <tutorials/quickstart>` which walks you through rendering a first simple scene.\"\nmsgstr \"Une fois que Manim est installé sur votre ordinateur, vous pouvez allez lire notre :doc:`guide de démarage rapide <tutorials/quickstart>` qui va vous apprendre à rendre une première scène simpliste.\"\n\n#: ../../source/installation.rst:61\nmsgid \"As mentioned above, do not worry if there are errors or other problems: consult our :doc:`troubleshooting guide <installation/troubleshooting>` for help, or get in touch with the community via `GitHub discussions <https://github.com/ManimCommunity/manim/discussions>`__ or `Discord <https://www.manim.community/discord/>`__.\"\nmsgstr \"Comme indiqué ci-dessus, ne vous inquétez pas si vous rencontrez des erreurs ou autres problèmes : consultez notre :doc:`guide de dépannage <installation/troubleshooting>` pour obtenir de l'aide, sinon, prenez contact avec la communauté via `les discussions GitHub <https://github.com/ManimCommunity/manim/discussions>`__ ou via `Discord <https://www.manim.community/discord/>`__.\"\n\n#: ../../source/installation.rst:73\nmsgid \"Using Manim via Docker\"\nmsgstr \"Utiliser Manim via Docker\"\n\n#: ../../source/installation.rst:75\nmsgid \"`Docker <https://www.docker.com>`__ is a virtualization tool that allows the distribution of encapsulated software environments (containers).\"\nmsgstr \"`Docker <https://www.docker.com>`__ est un outil de virtualisation qui permet la distribution de logiciels en environnement confiné (*containers*).\"\n\n#: ../../source/installation.rst:78\nmsgid \"The following pages contain more information about the docker image maintained by the community, ``manimcommunity/manim``:\"\nmsgstr \"Les pages suivantes contiennent plus d'informations à propos de l'image docker maintenue par la communauté, ``manimcommunity/manim`` :\"\n\n#: ../../source/installation.rst:89\nmsgid \"Interactive Jupyter notebooks for your browser\"\nmsgstr \"Bloc-notes interactifs Jupyter sur votre navigateur\"\n\n#: ../../source/installation.rst:91\nmsgid \"Manim ships with a built-in ``%%manim`` IPython magic command designed for the use within `Jupyter notebooks <https://jupyter.org>`__. Our interactive tutorial over at https://try.manim.community illustrates how Manim can be used from within a Jupyter notebook.\"\nmsgstr \"Le projet Manim contient une commande IPython ``%%manim`` prévue pour être utilisée dans des `blocs-notes Jupyter <https://jupyter.org>`__. Notre tutoriel interactif à l'adresse https://try.manim.community illustre la façon d'utiliser Manim dans un bloc-notes Jupyter.\"\n\n#: ../../source/installation.rst:96\nmsgid \"The following pages explain how you can setup interactive environments like that yourself:\"\nmsgstr \"Les pages suivantes expliquent comment mettre en place de tels environnements interactifs vous-même :\"\n\n#: ../../source/installation.rst:105\nmsgid \"Installation for developers\"\nmsgstr \"Installation pour les développeurs\"\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.1.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:3\nmsgid \"v0.1.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:5\nmsgid \"October 21, 2020\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:7\nmsgid \"This is the first release of manimce after forking from 3b1b/manim.  As such, developers have focused on cleaning up and refactoring the codebase while still maintaining backwards compatibility wherever possible.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:13\nmsgid \"New Features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:16\nmsgid \"Command line\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:18\nmsgid \"Output of 'manim --help' has been improved\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:19\nmsgid \"Implement logging with the :code:`rich` library and a :code:`logger` object instead of plain ol' prints\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:20\nmsgid \"Added a flag :code:`--dry_run`, which doesn't write any media\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:21\nmsgid \"Allow for running manim with :code:`python3 -m manim`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:22\nmsgid \"Refactored Tex Template management. You can now use custom templates with command line args using :code:`--tex_template`!\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:23\nmsgid \"Re-add :code:`--save_frames` flag, which will save each frame as a png\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:24\nmsgid \"Re-introduce manim feature that allows you to type manim code in :code:`stdin` if you pass a minus sign :code:`(-)` as filename\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:25\nmsgid \"Added the :code:`--custom_folders` flag which yields a simpler output folder structure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:26\nmsgid \"Re-implement GIF export with the :code:`-i` flag (using this flag outputs ONLY a .gif file, and no .mp4 file)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:27\nmsgid \"Added a :code:`--verbose` flag\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:28\nmsgid \"You can save the logs to a file by using :code:`--log_to_file`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:29\nmsgid \"Read :code:`tex_template` from config file if not specified by :code:`--tex_template`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:30\nmsgid \"Add experimental javascript rendering with :code:`--use_js_renderer`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:31\nmsgid \"Add :code:`-q/--quality [k|p|h|m|l]` flag and removed :code:`-m/-l` flags.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:32\nmsgid \"Removed :code:`--sound` flag\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:36\nmsgid \"Config system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:38\nmsgid \"Implement a :code:`manim.cfg` config file system, that consolidates the global configuration, the command line argument parsing, and some of the constants defined in :code:`constants.py`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:39\nmsgid \"Added utilities for manipulating Manim’s :code:`.cfg` files.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:40\nmsgid \"Added a subcommand structure for easier use of utilities managing :code:`.cfg` files\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:41\nmsgid \"Also some variables have been moved from ``constants.py`` to the new config system:\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:43\nmsgid \"``FRAME_HEIGHT`` to ``config[\\\"frame_width\\\"]``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:44\nmsgid \"``TOP`` to ``config[\\\"frame_height\\\"] / 2 * UP``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:45\nmsgid \"``BOTTOM`` to ``config[\\\"frame_height\\\"] / 2 * DOWN``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:46\nmsgid \"``LEFT_SIDE`` to ``config[\\\"frame_width\\\"] / 2 * LEFT``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:47\nmsgid \"``RIGHT_SIDE`` to ``config[\\\"frame_width\\\"] / 2 * RIGHT``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:48\nmsgid \"``self.camera.frame_rate`` to ``config[\\\"frame_rate\\\"]``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:54\nmsgid \"Mobjects, Scenes, and Animations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:56\nmsgid \"Add customizable left and right bracket for :code:`Matrix` mobject and :code:`set_row_colors` method for matrix mobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:57\nmsgid \"Add :code:`AddTeXLetterByLetter` animation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:58\nmsgid \"Enhanced GraphScene\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:60\nmsgid \"You can now add arrow tips to axes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:61\nmsgid \"extend axes a bit at the start and/or end\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:62\nmsgid \"have invisible axes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:63\nmsgid \"highlight the area between two curves\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:64\nmsgid \"ThreeDScene now supports 3dillusion_camera_rotation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:65\nmsgid \"Add :code:`z_index` for manipulating depth of Objects on scene.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:66\nmsgid \"Add a :code:`VDict` class: a :code:`VDict` is to a :code:`VGroup` what a :code:`dict` is to a :code:`list`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:67\nmsgid \"Added Scene-caching feature. Now, if a partial movie file is unchanged in your code, it isn’t rendered again! [HIGHLY UNSTABLE We're working on it ;)]\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:68\nmsgid \"Most :code:`get_` and :code:`set_` methods have been removed in favor of instance attributes and properties\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:69\nmsgid \"The :code:`Container` class has been made into an AbstractBaseClass, i.e. in cannot be instantiated.  Instead, use one of its children classes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:70\nmsgid \"The ``TextMobject`` and ``TexMobject`` objects have been deprecated, due to their confusing names, in favour of ``Tex`` and ``MathTex``. You can still, however, continue to use ``TextMobject`` and ``TexMobject``, albeit with Deprecation Warnings constantly reminding you to switch.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:71\nmsgid \"Add a :code:`Variable` class for displaying text that continuously updates to reflect the value of a python variable.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:72\nmsgid \"The ``Tex`` and ``MathTex`` objects allow you to specify a custom TexTemplate using the ``template`` keyword argument.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:73\nmsgid \":code:`VGroup` now supports printing the class names of contained mobjects and :code:`VDict` supports printing the internal dict of mobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:74\nmsgid \"Add all the standard easing functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:75\nmsgid \":code:`Scene` now renders when :code:`Scene.render()` is called rather than upon instantiation.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:76\nmsgid \":code:`ValueTracker` now supports increment using the `+=` operator (in addition to the already existing `increment_value` method)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:77\nmsgid \"Add :class:`PangoText` for rendering texts using Pango.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:81\nmsgid \"Documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:83\nmsgid \"Added clearer installation instructions, tutorials, examples, and API reference [WIP]\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:87\nmsgid \"Fixes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:89\nmsgid \"Initialization of directories has been moved to :code:`config.py`, and a bunch of bugs associated to file structure generation have been fixed\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:90\nmsgid \"Nonfunctional file :code:`media_dir.txt` has been removed\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:91\nmsgid \"Nonfunctional :code:`if` statements in :code:`scene_file_writer.py` have been removed\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:92\nmsgid \"Fix a bug where trying to render the example scenes without specifying the scene would show all scene objects in the library\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:93\nmsgid \"Many :code:`Exceptions` have been replaced for more specific exception subclasses\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:94\nmsgid \"Fixed a couple of subtle bugs in :code:`ArcBetweenPoints`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:98\nmsgid \"Of interest to developers\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:100\nmsgid \"Python code formatting is now enforced by using the :code:`black` tool\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:101\nmsgid \"PRs now require two approving code reviews from community devs before they can be merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:102\nmsgid \"Added tests to ensure stuff doesn't break between commits (For developers) [Uses Github CI, and Pytest]\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:103\nmsgid \"Add contribution guidelines (for developers)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:104\nmsgid \"Added autogenerated documentation with sphinx and autodoc/autosummary [WIP]\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:105\nmsgid \"Made manim internally use relative imports\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:106\nmsgid \"Since the introduction of the :code:`TexTemplate` class, the files :code:`tex_template.tex` and :code:`ctex_template.tex` have been removed\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:107\nmsgid \"Added logging tests tools.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:108\nmsgid \"Added ability to save logs in json\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:109\nmsgid \"Move to Poetry.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:110\nmsgid \"Colors have moved to an Enum\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:113\nmsgid \"Other Changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:115\nmsgid \"Cleanup 3b1b Specific Files\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:116\nmsgid \"Rename package from manimlib to manim\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.0-changelog.rst:117\nmsgid \"Move all imports to :code:`__init__`, so :code:`from manim import *` replaces :code:`from manimlib.imports import *`\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.1.1-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:3\nmsgid \"v0.1.1\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:5\nmsgid \"December 1, 2020\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:7\nmsgid \"Changes since Manim Community release v0.1.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:10\nmsgid \"Plugins\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:12\nmsgid \"Provided a standardized method for plugin discoverability, creation, installation, and usage. See the :ref:`documentation <plugins>`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:16\nmsgid \"Fixes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:18\nmsgid \"JsRender is optional to install. (via :pr:`697`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:19\nmsgid \"Allow importing modules from the same directory as the input file when using ``manim`` from the command line (via :pr:`724`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:21\nmsgid \"Remove some unnecessary or unpythonic methods from :class:`~.Scene` (``get_mobjects``, ``add_mobjects_among``, ``get_mobject_copies``), via :pr:`758`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:24\nmsgid \"Fix formatting of :class:`~.Code` (via :pr:`798`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:27\nmsgid \"Configuration\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:29\nmsgid \"Removed the ``skip_animations`` config option and added the ``Renderer.skip_animations`` attribute instead (via :pr:`696`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:31\nmsgid \"The global ``config`` dict has been replaced by a global ``config`` instance of the new class :class:`~.ManimConfig`.  This class has a dict-like API, so this should not break user code, only make it more robust.  See the Configuration tutorial for details.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:35\nmsgid \"Added the option to configure a directory for external assets (via :pr:`649`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:39\nmsgid \"Documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:41\nmsgid \"Add ``:issue:`` and ``:pr:`` directives for simplifying linking to issues and pull requests on GitHub (via :pr:`685`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:43\nmsgid \"Add a ``skip-manim`` tag for skipping the ``.. manim::`` directive when building the documentation locally (via :pr:`796`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:48\nmsgid \"Mobjects, Scenes, and Animations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:50\nmsgid \"The ``alignment`` attribute to Tex and MathTex has been removed in favour of ``tex_environment``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:51\nmsgid \":class:`~.Text` now uses Pango for rendering. ``PangoText`` has been removed. The old implementation is still available as a fallback as :class:`~.CairoText`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:52\nmsgid \"Variations of :class:`~.Dot` have been added as :class:`~.AnnotationDot` (a bigger dot with bolder stroke) and :class:`~.LabeledDot` (a dot containing a label).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:55\nmsgid \"Scene.set_variables_as_attrs has been removed (via :pr:`692`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:56\nmsgid \"Ensure that the axes for graphs (:class:`GraphScene`) always intersect (:pr:`580`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:57\nmsgid \"Now Mobject.add_updater does not call the newly-added updater by default (use ``call_updater=True`` instead) (via :pr:`710`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:59\nmsgid \"VMobject now has methods to determine and change the direction of the points (via :pr:`647`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:60\nmsgid \"Added BraceBetweenPoints (via :pr:`693`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:61\nmsgid \"Added ArcPolygon and ArcPolygonFromArcs (via :pr:`707`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:62\nmsgid \"Added Cutout (via :pr:`760`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:63\nmsgid \"Added Mobject raise not implemented errors for dunder methods and implementations for VGroup dunder methods (via :pr:`790`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.1.1-changelog.rst:64\nmsgid \"Added :class:`~.ManimBanner` for a animated version of our logo and banner (via :pr:`729`)\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.10.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:3\nmsgid \"v0.10.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:5\nmsgid \"September 01, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:10\nmsgid \"A total of 40 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:14\nmsgid \"Animfysyk +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:15\n#: ../../source/changelog/0.10.0-changelog.rst:48\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:16\nmsgid \"Christian Clauss\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:17\nmsgid \"Daniel Adelodun +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:18\nmsgid \"Darigov Research\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:19\n#: ../../source/changelog/0.10.0-changelog.rst:49\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:20\nmsgid \"Eric Biedert +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:21\n#: ../../source/changelog/0.10.0-changelog.rst:53\nmsgid \"Harivinay\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:22\n#: ../../source/changelog/0.10.0-changelog.rst:55\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:23\nmsgid \"Jephian Lin +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:24\nmsgid \"Joy Bhalla +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:25\n#: ../../source/changelog/0.10.0-changelog.rst:60\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:26\nmsgid \"Lalourche +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:27\nmsgid \"Max Stoumen\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:28\n#: ../../source/changelog/0.10.0-changelog.rst:61\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:29\n#: ../../source/changelog/0.10.0-changelog.rst:62\nmsgid \"Oliver\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:30\nmsgid \"Partha Das +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:31\nmsgid \"Raj Dandekar +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:32\nmsgid \"Rohan Sharma +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:33\n#: ../../source/changelog/0.10.0-changelog.rst:65\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:34\nmsgid \"Václav Hlaváč +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:35\nmsgid \"asjadaugust +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:36\n#: ../../source/changelog/0.10.0-changelog.rst:66\nmsgid \"ccn\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:37\n#: ../../source/changelog/0.10.0-changelog.rst:67\nmsgid \"icedcoffeeee\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:38\n#: ../../source/changelog/0.10.0-changelog.rst:69\nmsgid \"sparshg\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:39\nmsgid \"vinnniii15 +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:40\nmsgid \"vladislav doster +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:41\nmsgid \"xia0long +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:44\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:47\nmsgid \"Aathish Sivasubrahmanian\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:50\nmsgid \"Devin Neal\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:51\nmsgid \"Eric Biedert\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:52\nmsgid \"GameDungeon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:54\nmsgid \"Hugues Devimeux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:56\nmsgid \"Jason Villanueva\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:57\nmsgid \"Jephian Lin\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:58\nmsgid \"Joy Bhalla\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:59\nmsgid \"KingWampy\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:63\nmsgid \"Raghav Goel\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:64\nmsgid \"Raj Dandekar\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:68\nmsgid \"ralphieraccoon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:72\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:74\nmsgid \"A total of 59 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:77\nmsgid \"Breaking changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:81\nmsgid \":pr:`1843`: Dropped redundant OpenGL files and add metaclass support for :class:`~.Surface`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:80\nmsgid \"``OpenGL<x>`` classes from ``opengl_geometry.py``, ``opengl_text_mobject.py``, ``opengl_tex_mobject.py``, ``opengl_svg_path.py``, ``opengl_svg_mobject.py`` and most of ``opengl_three_dimensions.py`` have been removed.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:81\nmsgid \"``ParametricSurface`` has been renamed to :class:`~.Surface`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:84\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:86\nmsgid \":pr:`1941`: Added examples, tests and improved documentation for :mod:`~.coordinate_systems`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:89\nmsgid \":pr:`1694`: Added ``font_size`` parameter for :class:`~.Tex` and :class:`~.Text`, replaced ``scale`` parameters with ``font_size``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:92\nmsgid \":pr:`1860`: Removed :class:`~.GraphScene`, :class:`~.NumberLineOld` and parameters for :class:`~.ChangingDecimal`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:96\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:99\nmsgid \":pr:`1929`: Implementing a ``zoom`` parameter for :meth:`.ThreeDScene.move_camera`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:99\nmsgid \"Zooming into a :class:`~.ThreeDScene` can now be done by calling, for example, ``self.move_camera(zoom=2)`` in the ``construct`` method.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:101\nmsgid \":pr:`1980`: Added a ``dissipating_time`` keyword argument to :class:`~.TracedPath` to allow animating a dissipating path\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:105\nmsgid \":pr:`1899`: Allow switching the renderer to OpenGL at runtime\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:105\nmsgid \"Previously, the metaclass approach only changed the inheritance chain to switch between OpenGL and cairo mobjects when the class objects are initialized, i.e., at import time. This PR also triggers the changes to the inheritance chain when the value of ``config.renderer`` is changed.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:107\nmsgid \":pr:`1828`: Added configuration option ``zero_pad`` for zero padding PNG file names\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:111\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:113\nmsgid \":pr:`1882`: Added OpenGL support for :class:`~.PMobject` and its subclasses\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:116\nmsgid \":pr:`1881`: Added methods :meth:`.Angle.get_lines` and :meth:`.Angle.get_value` to :class:`~.Angle`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:119\nmsgid \":pr:`1952`: Added the option to save last frame for OpenGL\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:122\nmsgid \":pr:`1922`: Fixed IPython interface to exit cleanly when OpenGL renderer raises an error\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:125\nmsgid \":pr:`1923`: Fixed CLI help text for ``manim init`` subcommand so that it is not truncated\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:129\nmsgid \":pr:`1868`: Added OpenGL support to IPython magic\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:129\nmsgid \"The OpenGL renderer can now be used in jupyter notebooks when using the ``%%manim`` magic command.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:131\nmsgid \":pr:`1841`: Reduced default resolution of :class:`~.Dot3D`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:134\nmsgid \":pr:`1866`: Allow passing keyword argument ``corner_radius`` to :class:`~.SurroundingRectangle`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:137\nmsgid \":pr:`1847`: Allow :class:`~.Cross` to be created without requiring a mobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:141\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:143\nmsgid \":pr:`1985`: Use ``height`` to determine ``font_size`` instead of the ``_font_size`` attribute\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:146\nmsgid \":pr:`1758`: Fixed scene selection being ignored when using the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:149\nmsgid \":pr:`1871`: Fixed broken :meth:`.VectorScene.vector_to_coords`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:152\nmsgid \":pr:`1973`: Fixed indexing of :meth:`.Table.get_entries` to respect row length\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:155\nmsgid \":pr:`1950`: Fixed passing custom arrow shapes to :class:`~.CurvedArrow`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:158\nmsgid \":pr:`1967`: Fixed :attr:`.Axes.coordinate_labels` referring to the entire axis, not just its labels\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:161\nmsgid \":pr:`1951`: Fixed :meth:`.Axes.get_line_graph` returning a graph rendered below the axes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:164\nmsgid \":pr:`1943`: Added ``buff`` keyword argument to :class:`~.BraceLabel`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:167\nmsgid \":pr:`1938`: Fixed :class:`~.Rotate` for angles that are multiples of :math:`2\\\\pi`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:170\nmsgid \":pr:`1924`: Made arrow tips rotate ``IN`` and ``OUT`` properly\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:173\nmsgid \":pr:`1931`: Fixed ``row_heights`` in :meth:`.Mobject.arrange_in_grid`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:176\nmsgid \":pr:`1893`: Fixed CLI error when rendering a file containing a single scene without specifying the scene name\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:179\nmsgid \":pr:`1744`: Fixed bug in :class:`~.NumberPlane` with strictly positive or strictly negative values for ``x_range`` and ``y_range``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:182\nmsgid \":pr:`1887`: Fixed ``custom_config`` not working in ``frames_comparison``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:185\nmsgid \":pr:`1879`: Fixed how the installed version is determined by Poetry\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:189\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:191\nmsgid \":pr:`1979`: Corrected Japanese phrases in documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:194\nmsgid \":pr:`1976`: Fixed labelling of languages in documentation example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:197\nmsgid \":pr:`1949`: Rewrite installation instructions from scratch\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:200\nmsgid \":pr:`1963`: Added sitemap to ``robots.txt``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:203\nmsgid \":pr:`1939`: Fixed formatting of parameter description of :class:`~.NumberPlane`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:206\nmsgid \":pr:`1918`: Fixed a typo in the text tutorial\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:209\nmsgid \":pr:`1915`: Improved the wording of the installation instructions for Google Colab\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:212\nmsgid \":pr:`1906`: Improved language and overall consistency in ``README``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:215\nmsgid \":pr:`1880`: Updated tutorials to use ``.animate`` instead of :class:`~.ApplyMethod`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:218\nmsgid \":pr:`1877`: Remove duplicated imports in some documentation examples\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:221\nmsgid \":pr:`1869`: Fixed duplicated Parameters section in  :meth:`.Mobject.arrange_in_grid`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:225\nmsgid \"Changes concerning the testing system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:227\nmsgid \":pr:`1894`: Fixed an OpenGL test\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:231\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:233\nmsgid \":pr:`1987`: Added support for using OpenGL in subprocess in Windows pipeline\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:236\nmsgid \":pr:`1964`: Added ``CITATION.cff`` and a method to automatically update this citation with new releases\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:239\nmsgid \":pr:`1856`: Modified Dockerfile to support multi-platform builds via ``docker buildx``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:242\nmsgid \":pr:`1955`: Partially support OpenGL rendering with Docker\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:245\nmsgid \":pr:`1896`: Made RTD apt install FFMPEG instead of installing a Python binding\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:248\nmsgid \":pr:`1864`: Shortened and simplified PR template\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:251\nmsgid \":pr:`1853`: Updated Sphinx to 4.1.2\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:255\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:257\nmsgid \":pr:`1960`: Ignore fewer flake8 errors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:260\nmsgid \":pr:`1947`: Set flake8 not to ignore undefined names in Python code\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:263\nmsgid \":pr:`1948`: flake8: Set max-line-length instead of ignoring long lines\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:268\nmsgid \":pr:`1956`:  Upgrade to modern Python syntax\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:267\nmsgid \"This pull request was created `with the command <https://github.com/asottile/pyupgrade#readme>`__ ``pyupgrade --py36-plus **/*.py``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:268\nmsgid \"Python f-strings simplify the code and `should speed up execution <https://www.scivision.dev/python-f-string-speed>`__.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:271\nmsgid \":pr:`1898`: Replaced ``self.data[\\\"attr\\\"]`` and ``self.uniforms[\\\"attr\\\"]`` with ``self.attr``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:271\nmsgid \"In particular, ``OpenGLVMobject.points`` can now be accessed directly.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:273\nmsgid \":pr:`1934`: Improved code quality by implementing suggestions from LGTM\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:276\nmsgid \":pr:`1861`: Updated ``dearpygui`` version to 0.8.x\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.10.0-changelog.rst:280\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.11.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:3\nmsgid \"v0.11.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:5\nmsgid \"October 02, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:10\nmsgid \"A total of 31 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:14\n#: ../../source/changelog/0.11.0-changelog.rst:40\nmsgid \"Aathish Sivasubrahmanian\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:15\n#: ../../source/changelog/0.11.0-changelog.rst:41\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:16\nmsgid \"Charlie +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:17\nmsgid \"Christopher Besch +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:18\n#: ../../source/changelog/0.11.0-changelog.rst:43\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:19\nmsgid \"Evan Boehs +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:20\n#: ../../source/changelog/0.11.0-changelog.rst:45\nmsgid \"GameDungeon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:21\n#: ../../source/changelog/0.11.0-changelog.rst:46\nmsgid \"Hugues Devimeux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:22\nmsgid \"Jerónimo Squartini\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:23\n#: ../../source/changelog/0.11.0-changelog.rst:49\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:24\nmsgid \"Meredith Espinosa +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:25\n#: ../../source/changelog/0.11.0-changelog.rst:51\nmsgid \"Mysaa\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:26\n#: ../../source/changelog/0.11.0-changelog.rst:52\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:27\nmsgid \"Nicolai Weitkemper +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:28\n#: ../../source/changelog/0.11.0-changelog.rst:54\nmsgid \"Oliver\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:29\n#: ../../source/changelog/0.11.0-changelog.rst:56\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:30\nmsgid \"Tim +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:31\n#: ../../source/changelog/0.11.0-changelog.rst:59\nmsgid \"icedcoffeeee\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:32\nmsgid \"imadjamil +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:33\nmsgid \"leleogere +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:34\nmsgid \"Максим Заякин +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:37\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:42\nmsgid \"Charlie\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:44\nmsgid \"Evan Boehs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:47\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:48\nmsgid \"Jason Villanueva\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:50\nmsgid \"Mark Miller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:53\nmsgid \"Nicolai Weitkemper\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:55\nmsgid \"Raghav Goel\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:57\nmsgid \"Skaft\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:58\nmsgid \"friedkeenan\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:60\nmsgid \"leleogere\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:63\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:65\nmsgid \"A total of 55 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:68\nmsgid \"Breaking changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:71\nmsgid \":pr:`1990`: Changed and improved the implementation of :meth:`.CoordinateSystem.get_area` to work without Riemann rectangles\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:71\nmsgid \"This changes how :meth:`.CoordinateSystem.get_area` is implemented. To mimic the old behavior (tiny Riemann rectangles), use :meth:`.CoordinateSystem.get_riemann_rectangles` with a small value for ``dx``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:74\nmsgid \":pr:`2095`: Changed angles for polar coordinates to use math convention\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:74\nmsgid \"This PR switches the parameter names ``phi`` and ``theta`` in :func:`cartesian_to_spherical` and :func:`spherical_to_cartesian` to align with the `usual definition in mathematics <https://user-images.githubusercontent.com/83535735/131709630-87290522-7747-4b21-9411-dd3d35ebaf0f.png>`__.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:77\nmsgid \"Highlights\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:80\nmsgid \":pr:`2094`: Implemented :class:`~.ImplicitFunction` and :meth:`.CoordinateSystem.get_implicit_curve` for plotting implicit curves\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:80\nmsgid \"An :class:`~.ImplicitFunction` that plots the points :math:`(x, y)` which satisfy some equation :math:`f(x,y) = 0`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:82\nmsgid \":pr:`2075`: Implemented :meth:`.Mobject.set_default`, a mechanism for changing default values of keyword arguments\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:87\nmsgid \":pr:`1998`: Added support for Boolean Operations on VMobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:86\nmsgid \"This PR introduces boolean operations for :class:`~.VMobject`; see details and examples at :class:`~.Union`, :class:`~.Difference`, :class:`~.Intersection` and :class:`~.Exclusion`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:90\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:92\nmsgid \":pr:`2123`: Renamed ``distance`` parameter of :class:`.ThreeDScene` and :class:`.ThreeDCamera` to ``focal_distance``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:95\nmsgid \":pr:`2102`: Deprecated :class:`~.SampleSpaceScene` and :class:`~.ReconfigurableScene`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:98\nmsgid \":pr:`2061`: Removed deprecated ``u_min``, ``u_max``, ``v_min``, ``v_max`` in :class:`~.Surface`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:101\nmsgid \":pr:`2024`: Deprecated redundant methods :meth:`.Mobject.rotate_in_place`, :meth:`.Mobject.scale_in_place`, :meth:`.Mobject.scale_about_point`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:104\nmsgid \":pr:`1991`: Deprecated :meth:`.VMobject.get_points`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:108\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:110\nmsgid \":pr:`2118`: Added 3D support for :class:`~.ArrowVectorField` and :class:`~.StreamLines`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:113\nmsgid \":pr:`1469`: Added :meth:`.VMobject.proportion_from_point` to measure the proportion of points along a Bezier curve\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:117\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:119\nmsgid \":pr:`2111`: Improved setting of OpenGL colors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:122\nmsgid \":pr:`2113`: Added OpenGL compatibility to :meth:`.ThreeDScene.begin_ambient_camera_rotation` and :meth:`.ThreeDScene.move_camera`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:125\nmsgid \":pr:`2016`: Added OpenGL support for :mod:`~.mobject.boolean_ops`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:128\nmsgid \":pr:`2084`: Added :meth:`~Table.get_highlighted_cell` and fixed :meth:`~Table.add_highlighted_cell`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:131\nmsgid \":pr:`2013`: Removed unnecessary check in :class:`~.TransformMatchingAbstractBase`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:134\nmsgid \":pr:`1971`: Added OpenGL support for :class:`~.StreamLines`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:137\nmsgid \":pr:`2041`: Added config option to enable OpenGL wireframe for debugging\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:141\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:143\nmsgid \":pr:`2070`: Fixed :meth:`~OpenGLRenderer.get_frame` when window is created\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:146\nmsgid \":pr:`2071`: Fixed :class:`~AnimationGroup` OpenGL compatibility\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:149\nmsgid \":pr:`2108`: Fixed swapped axis step values in :class:`~.NumberPlane`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:152\nmsgid \":pr:`2072`: Added OpenGL compatibility for :class:`~.Cube`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:155\nmsgid \":pr:`2060`: Fixed OpenGL compatibility issue for meth:`~Line.set_opacity`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:158\nmsgid \":pr:`2037`: Fixed return value of :meth:`~.OpenGLMobject.apply_complex_function`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:161\nmsgid \":pr:`2039`: Added OpenGL compatibility for :meth:`~Cylinder.add_bases`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:164\nmsgid \":pr:`2066`: Fixed error raised by logging when cache is full\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:167\nmsgid \":pr:`2026`: Fixed OpenGL shift animation for :class:`~.Text`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:170\nmsgid \":pr:`2028`: Fixed OpenGL overriding SVG fill color\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:173\nmsgid \":pr:`2043`: Fixed bug where :meth:`.NumberLine.add_labels`  cannot accept non-mobject labels\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:176\nmsgid \":pr:`2011`: Fixed ``-a`` flag for OpenGL rendering\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:179\nmsgid \":pr:`1994`: Fix :meth:`~.input_to_graph_point` when passing a line graph (from :meth:`.Axes.get_line_graph`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:182\nmsgid \":pr:`2017`: Avoided using deprecated ``get_points`` method and fixed :class:`~.OpenGLPMPoint` color\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:186\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:188\nmsgid \":pr:`2131`: Copyedited the configuration tutorial in the documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:191\nmsgid \":pr:`2120`: Changed ``manim_directive`` to use a clean configuration via ``tempconfig``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:194\nmsgid \":pr:`2122`: Fixed broken links in inheritance graphs by moving them to ``reference.rst``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:197\nmsgid \":pr:`2115`: Improved docstring of :meth:`.PMobject.add_points`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:200\nmsgid \":pr:`2116`: Made type hint for ``line_spacing`` argument of :class:`~.Paragraph` more accurate\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:203\nmsgid \":pr:`2117`: Changed the way the background color was set in a documentation example to avoid leaking the setting to other examples\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:206\nmsgid \":pr:`2101`: Added note that translation process is not ready\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:209\nmsgid \":pr:`2055`: Fixed parameter types of :meth:`.Graph.add_edges` and :meth:`.Graph.add_vertices`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:212\nmsgid \":pr:`862`: Prepared documentation for translation (still work in progress)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:215\nmsgid \":pr:`2035`: Fixed broken link in README\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:218\nmsgid \":pr:`2020`:  Corrected paths to user-wide configuration files for MacOS and Linux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:222\nmsgid \"Changes concerning the testing system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:224\nmsgid \":pr:`2008`: Reuse CLI flag tests for OpenGL\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:227\nmsgid \":pr:`2080`: Reused :class:`~.Mobject` tests for :class:`~.OpenGLMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:231\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:233\nmsgid \":pr:`2004`: Cancel previous workflows in the same branch in Github Actions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:237\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:239\nmsgid \":pr:`2050`: Make colour aliases IDE-friendly\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:242\nmsgid \":pr:`2126`: Fixed whitespace in info message issued by :meth:`.SceneFileWriter.clean_cache`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:245\nmsgid \":pr:`2124`: Upgraded several dependencies (in particular: ``skia-pathops``)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:248\nmsgid \":pr:`2001`: Fixed several warnings issued by LGTM\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:251\nmsgid \":pr:`2064`: Removed duplicate insert shader directory\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:254\nmsgid \":pr:`2027`: Improved wording in info message issued by :meth:`.SceneFileWriter.clean_cache`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:257\nmsgid \":pr:`1968`: Sharpened Flake8 configuration and fixed resulting warnings\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.11.0-changelog.rst:261\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.12.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:3\nmsgid \"v0.12.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:5\nmsgid \"November 02, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:10\nmsgid \"A total of 40 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:14\nmsgid \"Anima. +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:15\nmsgid \"Arcstur +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:16\n#: ../../source/changelog/0.12.0-changelog.rst:47\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:17\n#: ../../source/changelog/0.12.0-changelog.rst:48\nmsgid \"Christopher Besch\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:18\n#: ../../source/changelog/0.12.0-changelog.rst:49\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:19\nmsgid \"David Yang +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:20\nmsgid \"Dhananjay Goratela +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:21\nmsgid \"Ethan Rooke +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:22\nmsgid \"Eugene Chung +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:23\nmsgid \"GameDungeon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:24\nmsgid \"Gustav-Rixon +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:25\n#: ../../source/changelog/0.12.0-changelog.rst:56\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:26\nmsgid \"Josiah Winslow +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:27\n#: ../../source/changelog/0.12.0-changelog.rst:58\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:28\nmsgid \"Martmists +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:29\nmsgid \"Michael Hill +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:30\n#: ../../source/changelog/0.12.0-changelog.rst:60\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:31\nmsgid \"Nick +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:32\nmsgid \"NotWearingPants +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:33\nmsgid \"Peeter Joot +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:34\n#: ../../source/changelog/0.12.0-changelog.rst:63\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:35\nmsgid \"Viicos +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:36\nmsgid \"heitor +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:37\n#: ../../source/changelog/0.12.0-changelog.rst:65\nmsgid \"icedcoffeeee\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:38\nmsgid \"kieran-pringle +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:39\nmsgid \"Виктор Виктор +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:42\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:45\nmsgid \"Alex Lembcke\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:46\nmsgid \"Anima.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:50\nmsgid \"David Yang\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:51\nmsgid \"Dhananjay Goratela\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:52\nmsgid \"Ethan Rooke\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:53\nmsgid \"Eugene Chung\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:54\nmsgid \"Gustav-Rixon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:55\nmsgid \"Hugues Devimeux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:57\nmsgid \"Jason Villanueva\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:59\nmsgid \"Mysaa\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:61\nmsgid \"Nick\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:62\nmsgid \"Oliver\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:64\nmsgid \"Viicos\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:66\nmsgid \"kieran-pringle\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:69\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:71\nmsgid \"A total of 52 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:74\nmsgid \"Highlights\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:79\nmsgid \":pr:`1812`: Implemented logarithmic scaling for :class:`~.NumberLine` / :class:`~.Axes`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:77\nmsgid \"This implements scaling bases that can be passed to the ``scaling`` keyword argument of :class:`.NumberLine`. See :class:`.LogBase` (for a logarithmic scale) and :class:`.LinearBase` (for the default scale) for more details and examples.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:85\nmsgid \":pr:`2152`: Introduced API for scene sections via :meth:`.Scene.next_section`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:82\nmsgid \"Sections divide a scene into multiple parts, resulting in multiple output videos (when using the ``--save_sections`` flag). The cuts between two sections are defined by the user in the :meth:`~.Scene.construct` method. Each section has an optional name and type, which can be used by a plugin (`see an example <https://github.com/ManimEditorProject/manim_editor>`__). You can skip rendering specific sections with the ``skip_animations`` keyword argument.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:88\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:90\nmsgid \":pr:`1926`: OpenGL: changed ``submobjects`` to be a property\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:93\nmsgid \":pr:`2245`: Removed deprecated method ``get_center_point`` and parameters ``azimuth_label_scale``, ``number_scale_value``, ``label_scale``, ``scale_factor``, ``size``, ``x_min``, ``x_max``, ``delta_x``, ``y_min``, ``y_max``, ``delta_y``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:96\nmsgid \":pr:`2187`: Renamed ``get_graph`` and its variants to :meth:`~.CoordinateSystem.plot`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:99\nmsgid \":pr:`2065`: Deprecated :class:`~.FullScreenFadeRectangle` and :class:`~.PictureInPictureFrame`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:103\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:105\nmsgid \":pr:`2025`: Implemented :meth:`.CoordinateSystem.input_to_graph_coords` and fixed :meth:`.CoordinateSystem.angle_of_tangent`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:108\nmsgid \":pr:`2151`: Added option to set the input file from a config file\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:111\nmsgid \":pr:`2128`: Added keyword arguments ``match_center``, ``match_width`` etc. to :meth:`.Mobject.become`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:114\nmsgid \":pr:`2162`: Implemented :meth:`.MovingCamera.auto_zoom` for automatically zooming onto specified mobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:117\nmsgid \":pr:`2236`: Added ``skip_animations`` argument to :meth:`.Scene.next_section`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:120\nmsgid \":pr:`2196`: Implemented :meth:`.Line3D.parallel_to` and :meth:`.Line3D.perpendicular_to`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:124\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:128\nmsgid \":pr:`2138`: Fixed example for :meth:`~.Vector.coordinate_label` and added more customization for :class:`~.Matrix`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:127\nmsgid \"Additional keyword arguments for :meth:`~.Vector.coordinate_label` are passed to the constructed matrix.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:128\nmsgid \":class:`~.Matrix` now accepts a ``bracket_config`` keyword argument.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:130\nmsgid \":pr:`2139`: Changed the color of :class:`~.NumberLine` from ``LIGHT_GREY`` to ``WHITE``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:133\nmsgid \":pr:`2157`: Added :meth:`.CoordinateSystem.plot_polar_graph`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:136\nmsgid \":pr:`2243`: Fixed wasteful recursion in :meth:`.Mobject.get_merged_array`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:139\nmsgid \":pr:`2205`: Improved last frame output handling for the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:142\nmsgid \":pr:`2172`: Added ``should_render`` attribute to disable rendering mobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:145\nmsgid \":pr:`2182`: Changed the default width of videos in Jupyter notebooks to 60%\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:149\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:151\nmsgid \":pr:`2244`: Fixed :meth:`.CoordinateSystem.get_area` when using few plot points and a boundary graph\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:154\nmsgid \":pr:`2232`: Fixed :class:`.Graph` stopping to update after animating additions/deletions of vertices or edges\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:157\nmsgid \":pr:`2142`: Fixed issue with duplicates in OpenGL family and added tests\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:160\nmsgid \":pr:`2168`: Fixed order of return values of :func:`.space_ops.cartesian_to_spherical`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:163\nmsgid \":pr:`2160`: Made projection shaders compatible with :class:`.StreamLines`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:166\nmsgid \":pr:`2140`: Fixed passing color lists to :meth:`.Mobject.set_color` for the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:169\nmsgid \":pr:`2211`: Fixed animations not respecting the specified rate function\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:172\nmsgid \":pr:`2161`: Fixed ``IndexOutOfBoundsError`` in TeX logging\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:175\nmsgid \":pr:`2148`: Fixed :class:`~.Arrow` tip disorientation with :meth:`.Line.put_start_and_end_on`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:178\nmsgid \":pr:`2192`: Fixed :func:`.svg_path.string_to_numbers` sometimes returning strings\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:181\nmsgid \":pr:`2185`: Fixed type mismatch for height and width parameters of :class:`~.Text`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:185\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:187\nmsgid \":pr:`2228`: Added a new boolean operation example to the gallery\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:190\nmsgid \":pr:`2239`: Removed erroneous raw string from text tutorial\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:193\nmsgid \":pr:`2184`: Moved comments in :class:`~.VMobject` to documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:196\nmsgid \":pr:`2217`: Removed superfluous dots in documentation of :class:`.Section`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:199\nmsgid \":pr:`2215`: Fixed typo in docstring of :meth:`.ThreeDAxes.get_z_axis_label`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:202\nmsgid \":pr:`2212`: Fixed Documentation for Sections\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:205\nmsgid \":pr:`2201`: Fixed a typo in the documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:208\nmsgid \":pr:`2165`: Added Crowdin configuration and changed source files to ``.pot`` format\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:211\nmsgid \":pr:`2130`:  Transferred troubleshooting installation related snippets from Discord to the documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:214\nmsgid \":pr:`2176`: Modified :meth:`.Mobject.set_default` example to prevent leaking across the docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:218\nmsgid \"Changes concerning the testing system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:220\nmsgid \":pr:`2197`: Added tests for resolution flag\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:223\nmsgid \":pr:`2146`: Increased test coverage for OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:227\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:229\nmsgid \":pr:`2191`: Removed ``add-trailing-comma`` pre-commit hook\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:233\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:235\nmsgid \":pr:`2136`: Added type hints to all colors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:238\nmsgid \":pr:`2220`: Cleanup: let ``Scene.renderer.time`` return something that makes sense\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:241\nmsgid \":pr:`2222`: Updated Classifiers in ``pyproject.toml``: removed Python 3.6, added Python 3.9\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:244\nmsgid \":pr:`2213`: Removed redundant ``partial_movie_files`` parameter in :meth:`.SceneFileWriter.combine_to_movie`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:251\nmsgid \":pr:`2200`: Addressed some maintenance TODOs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:248\nmsgid \"Changed an `Exception` to `ValueError`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:249\nmsgid \"Fixed :meth:`.MappingCamera.points_to_pixel_coords` by adding the ``mobject`` argument of the parent\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:250\nmsgid \"Rounded up width in :class:`.SplitScreenCamera`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:251\nmsgid \"Added docstring to :meth:`.Camera.capture_mobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:253\nmsgid \":pr:`2194`: Added type hints to :mod:`.utils.images`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:256\nmsgid \":pr:`2171`: Added type hints to :mod:`.utils.ipython_magic`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:259\nmsgid \":pr:`2164`: Improved readability of regular expression\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.12.0-changelog.rst:263\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.13.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:3\nmsgid \"v0.13.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:5\nmsgid \"December 04, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:10\nmsgid \"A total of 27 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:14\n#: ../../source/changelog/0.13.0-changelog.rst:38\nmsgid \"Alex Lembcke\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:15\n#: ../../source/changelog/0.13.0-changelog.rst:39\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:16\n#: ../../source/changelog/0.13.0-changelog.rst:40\nmsgid \"Christopher Besch\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:17\n#: ../../source/changelog/0.13.0-changelog.rst:41\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:18\nmsgid \"Filip +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:19\nmsgid \"John Ingles +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:20\n#: ../../source/changelog/0.13.0-changelog.rst:45\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:21\nmsgid \"Lucas Ricci +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:22\nmsgid \"Marcin Serwin +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:23\nmsgid \"Mysaa\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:24\n#: ../../source/changelog/0.13.0-changelog.rst:47\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:25\nmsgid \"Ricky +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:26\n#: ../../source/changelog/0.13.0-changelog.rst:50\nmsgid \"Viicos\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:27\nmsgid \"ask09ok +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:28\nmsgid \"citrusmunch +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:29\n#: ../../source/changelog/0.13.0-changelog.rst:52\nmsgid \"icedcoffeeee\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:30\nmsgid \"mostlyaman +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:31\nmsgid \"vmiezys +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:32\nmsgid \"zhujisheng +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:35\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:42\nmsgid \"Filip\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:43\nmsgid \"Hugues Devimeux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:44\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:46\nmsgid \"Lucas Ricci\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:48\nmsgid \"Oliver\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:49\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:51\nmsgid \"ask09ok\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:53\nmsgid \"mostlyaman\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:56\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:58\nmsgid \"A total of 39 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:61\nmsgid \"Highlights\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:63\nmsgid \":pr:`2313`: Finalized translation process and documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:67\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:75\nmsgid \":pr:`2331`: Removed deprecations up to ``v0.12.0``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:70\nmsgid \"Removed ``distance`` parameters from :class:`~.ThreeDCamera` (replacement: ``focal_distance``)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:71\nmsgid \"Removed ``min_distance_to_new_point`` parameter from :class:`~.TracedPath`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:72\nmsgid \"Removed ``positive_space_ratio`` and ``dash_spacing`` parameters from :class:`~.DashedVMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:73\nmsgid \"Removed ``<method>_in_place`` methods from :mod:`.mobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:74\nmsgid \"Removed ``ReconfigurableScene``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:75\nmsgid \"Removed ``SampleSpaceScene``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:77\nmsgid \":pr:`2312`: Replaced all occurrences of ``set_submobjects``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:81\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:85\nmsgid \":pr:`2314`: Added basic support for adding subcaptions via :meth:`.Scene.add_subcaption`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:84\nmsgid \"New method :meth:`.Scene.add_subcaption`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:85\nmsgid \"New keyword arguments ``subcaption``, ``subcaption_duration``, ``subcaption_offset`` for :meth:`.Scene.play`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:87\nmsgid \":pr:`2267`: Implemented :meth:`.CoordinateSystem.plot_antiderivative_graph`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:91\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:93\nmsgid \":pr:`2347`: Moved ``manim_directive.py`` to ``manim.utils.docbuild``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:96\nmsgid \":pr:`2340`: Added documentation for :mod:`.animation.growing` and improved :class:`.SpinInFromNothing`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:99\nmsgid \":pr:`2343`: Replaced current tree layout algorithm with SageMath's for improved layout of large trees\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:102\nmsgid \":pr:`2351`: Added missing ``**kwargs`` parameter to :meth:`.Table.add_highlighted_cell`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:105\nmsgid \":pr:`2344`: Resized SVG logos, fit content to canvas\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:109\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:111\nmsgid \":pr:`2359`: Resolved ``ValueError`` when calling ``manim cfg write``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:114\nmsgid \":pr:`2276`: Fixed bug with alignment of z-axis in :class:`~.ThreeDAxes`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:117\nmsgid \":pr:`2325`: Several improvements to handling of ``quality`` argument\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:120\nmsgid \":pr:`2335`: Fixed bug with zooming camera and :class:`~.PointCloud`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:123\nmsgid \":pr:`2328`: Fixed bug causing incorrect RGBA values to be passed to cairo\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:126\nmsgid \":pr:`2292`: Fixed positioning of :class:`~.Flash`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:129\nmsgid \":pr:`2262`: Fixed wrong cell coordinates with :meth:`.Table.get_cell` after scaling\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:132\nmsgid \":pr:`2280`: Fixed :class:`~.DecimalNumber` color when number of displayed digits changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:136\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:138\nmsgid \":pr:`2354`: Port over docs and typings from ``mobject.py`` and ``vectorized_mobject.py`` to their OpenGL counterparts\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:141\nmsgid \":pr:`2350`: Added mention of Manim sideview extension for VS Code\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:144\nmsgid \":pr:`2342`: Removed :meth:`~.CoordinateSystem.get_graph` usage from :class:`~.Axes` example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:147\nmsgid \":pr:`2216`: Edited and added new sections to the quickstart tutorial\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:150\nmsgid \":pr:`2279`: Added documentation for discontinuous functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:153\nmsgid \":pr:`2319`: Swapped ``dotL`` and ``dotR`` in :meth:`.Mobject.interpolate` example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:156\nmsgid \":pr:`2230`: Copyedited building blocks tutorial\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:159\nmsgid \":pr:`2310`: Clarified that Manim does not support Python 3.10 yet in the documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:162\nmsgid \":pr:`2294`: Made documentation front page more concise and rearranged order of tutorials\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:165\nmsgid \":pr:`2287`: Replace link to old interactive notebook\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:169\nmsgid \"Changes concerning the testing system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:171\nmsgid \":pr:`2346`: Made ``frames_comparsion`` decorator for frame testing a proper module of the library\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:174\nmsgid \":pr:`2318`: Added tests for ``remover`` keyword argument of :class:`~.AnimationGroup`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:177\nmsgid \":pr:`2301`: Added a test for :meth:`.ThreeDScene.add_fixed_in_frame_mobjects`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:180\nmsgid \":pr:`2274`: Optimized some tests to reduce duration\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:183\nmsgid \":pr:`2272`: Added test for :class:`~.Broadcast`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:187\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:189\nmsgid \":pr:`2327`: Corrected type hint for ``labels`` keyword argument of :class:`~.Graph`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:192\nmsgid \":pr:`2329`: Remove unintended line break in README\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:195\nmsgid \":pr:`2305`: Corrected type hint ``discontinuities`` argument for :class:`~.ParametricFunction`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:198\nmsgid \":pr:`2300`: Add contact email for PyPi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:202\nmsgid \"New releases\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:204\nmsgid \":pr:`2353`: Prepare new release: ``v0.13.0``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.0-changelog.rst:208\nmsgid \"Unclassified changes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.13.1-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:3\nmsgid \"v0.13.1\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:5\nmsgid \"December 05, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:10\nmsgid \"A total of 2 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:14\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:17\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:20\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:23\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:25\nmsgid \"A total of 2 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:28\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:30\nmsgid \":pr:`2363`: Fixed broken IPython magic command\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.13.1-changelog.rst:34\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.14.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:3\nmsgid \"v0.14.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:5\nmsgid \"January 07, 2022\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:10\nmsgid \"A total of 29 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:14\n#: ../../source/changelog/0.14.0-changelog.rst:38\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:15\nmsgid \"BorisTheBrave +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:16\n#: ../../source/changelog/0.14.0-changelog.rst:41\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:17\n#: ../../source/changelog/0.14.0-changelog.rst:42\nmsgid \"GameDungeon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:18\nmsgid \"Gergely Bencsik +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:19\n#: ../../source/changelog/0.14.0-changelog.rst:45\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:20\nmsgid \"Jihoon +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:21\nmsgid \"Kian Kasad +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:22\nmsgid \"Kiran-Raj-Dev +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:23\n#: ../../source/changelog/0.14.0-changelog.rst:47\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:24\nmsgid \"Leo Xu +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:25\n#: ../../source/changelog/0.14.0-changelog.rst:50\nmsgid \"Marcin Serwin\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:26\nmsgid \"Matt Gleich +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:27\n#: ../../source/changelog/0.14.0-changelog.rst:51\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:28\nmsgid \"Steven nguyen +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:29\nmsgid \"Vectozavr +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:30\n#: ../../source/changelog/0.14.0-changelog.rst:54\nmsgid \"Viicos\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:31\nmsgid \"citrusmunch\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:32\nmsgid \"netwizard22 +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:35\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:39\nmsgid \"BorisTheBrave\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:40\nmsgid \"Christopher Besch\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:43\nmsgid \"Gergely Bencsik\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:44\nmsgid \"Hugues Devimeux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:46\nmsgid \"Kiran-Raj-Dev\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:48\nmsgid \"Leo Xu\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:49\nmsgid \"Lucas Ricci\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:52\nmsgid \"Raghav Goel\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:53\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:55\nmsgid \"icedcoffeeee\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:58\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:60\nmsgid \"A total of 29 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:63\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:69\nmsgid \":pr:`2390`: Removed deprecations up to `v0.13.0`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:66\nmsgid \"Removed ``get_graph``, ``get_implicit_curve``, ``get_derivative_graph``, ``get_line_graph`` and ``get_parametric_curve`` in favour of their ``plot`` variants\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:67\nmsgid \"Removed ``FullScreenFadeRectangle`` and ``PictureInPictureFrame``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:68\nmsgid \"Removed ``path_arc`` parameter from :class:`~.SpinInFromNothing`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:69\nmsgid \"Removed ``set_submobjects`` method from ``opengl_mobject.py``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:72\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:75\nmsgid \":pr:`2341`: Update :class:`~.Text` to use new ``ManimPango`` color setting\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:75\nmsgid \":class:`~.Text` class now uses color setting introduced in ``ManimPango 0.4.0`` for color and gradient.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:78\nmsgid \":pr:`2397`: Added ``label_constructor`` parameter for :class:`~.NumberLine`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:78\nmsgid \"Allows changing the class that will be used to construct :class:`~.Axes` and :class:`~.NumberLine` labels by default. Makes it possible to easily use :class:`~.Text` for labels if needed.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:81\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:83\nmsgid \":pr:`2383`: Made :meth:`.Surface.set_fill_by_value` support gradients along different axes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:86\nmsgid \":pr:`2388`: Added ``about_point`` keyword argument to :class:`~.ApplyMatrix`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:89\nmsgid \":pr:`2395`: Add documentation for paths functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:94\nmsgid \":pr:`2372`: Improved :class:`~.DashedVMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:93\nmsgid \":class:`~.DashedVMobject` used to create stretched and uneven dashes on most plotted curves. Now the dash lengths are equalized. An option is reserved to use the old method. New keyword argument: ``dash_offset``. This parameter shifts the starting point.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:97\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:99\nmsgid \":pr:`2409`: Fixed performance degradation by trimming empty curves from paths when calling :meth:`.VMobject.align_points`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:102\nmsgid \":pr:`2392`: Fixed ``ZeroDivisionError`` in :mod:`~.mobject.three_dimensions`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:105\nmsgid \":pr:`2362`: Fixed phi updater in :meth:`.ThreeDScene.begin_3dillusion_camera_rotation`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:109\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:111\nmsgid \":pr:`2415`: Removed instructions on using and installing Docker in README\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:114\nmsgid \":pr:`2414`: Made improvements to the :doc:`/guides/configuration` tutorial\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:117\nmsgid \":pr:`2423`: Changed recommendation to ``mactex-no-gui`` from ``mactex`` for macOS install\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:120\nmsgid \":pr:`2407`: Clarified docstrings of :meth:`.Mobject.animate`, :meth:`.Mobject.set` and :class:`~.Variable`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:123\nmsgid \":pr:`2352`: Added Crowdin badge\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:126\nmsgid \":pr:`2371`: Added ``dvips`` to list of required LaTeX packages on Linux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:129\nmsgid \":pr:`2403`: Improved docstring of :class:`~.ApplyMethod` and removed propagated ``__init__`` docstring\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:132\nmsgid \":pr:`2391`: Fixed typo in parameter name in documentation of :class:`~.NumberLine`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:135\nmsgid \":pr:`2368`: Added note in Internationalization\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:139\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:141\nmsgid \":pr:`2408`: Removed various return annotations that were stifling type inference\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:144\nmsgid \":pr:`2424`: Removed ``strings.py``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:147\nmsgid \":pr:`1972`: Added support for MyPy\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:150\nmsgid \":pr:`2410`: Fixed Flake8\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:153\nmsgid \":pr:`2401`: Fixed type annotations in :mod:`.mobject.three_dimensions`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:156\nmsgid \":pr:`2405`: Removed some unused OpenGL files\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:159\nmsgid \":pr:`2399`: Fixed type annotations in :mod:`~.mobject.table`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:162\nmsgid \":pr:`2385`: Made comments in quickstart tutorial more precise\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:165\nmsgid \":pr:`2377`: Fixed type hint for an argument of :class:`~.MoveAlongPath`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.14.0-changelog.rst:169\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.15.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:3\nmsgid \"v0.15.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:5\nmsgid \"February 26, 2022\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:10\nmsgid \"A total of 34 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:14\nmsgid \"Alex Lembcke\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:15\nmsgid \"AnonymoZ +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:16\n#: ../../source/changelog/0.15.0-changelog.rst:44\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:17\n#: ../../source/changelog/0.15.0-changelog.rst:46\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:18\nmsgid \"Eshaan Naga Venkata +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:19\nmsgid \"Faruk D. +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:20\n#: ../../source/changelog/0.15.0-changelog.rst:48\nmsgid \"GameDungeon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:21\nmsgid \"Kevin Cen +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:22\n#: ../../source/changelog/0.15.0-changelog.rst:50\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:23\nmsgid \"Leo Xu\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:24\nmsgid \"Lucas Ricci\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:25\n#: ../../source/changelog/0.15.0-changelog.rst:52\nmsgid \"Marcin Serwin\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:26\nmsgid \"Michael McNeil Forbes +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:27\nmsgid \"Mysaa\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:28\n#: ../../source/changelog/0.15.0-changelog.rst:53\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:29\nmsgid \"Pierre Couy +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:30\nmsgid \"Simon Ellmann +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:31\nmsgid \"Tommy Chu +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:32\nmsgid \"Viicos\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:33\n#: ../../source/changelog/0.15.0-changelog.rst:58\nmsgid \"ad_chaos\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:34\nmsgid \"betafcc +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:35\nmsgid \"friedkeenan\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:36\n#: ../../source/changelog/0.15.0-changelog.rst:60\nmsgid \"icedcoffeeee\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:37\nmsgid \"vmoros +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:38\nmsgid \"鹤翔万里\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:41\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:45\nmsgid \"Christopher Besch\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:47\nmsgid \"Eshaan Naga Venkata\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:49\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:51\nmsgid \"Marcin Kurczewski\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:54\nmsgid \"Raghav Goel\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:55\nmsgid \"RomainJMend\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:56\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:57\nmsgid \"Tommy Chu\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:59\nmsgid \"betafcc\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:63\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:65\nmsgid \"A total of 71 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:68\nmsgid \"Breaking changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:71\nmsgid \":pr:`2476`: Improved structure of the :mod:`.mobject` module\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:71\nmsgid \"Arrow tips now have to be imported from ``manim.mobject.geometry.tips`` instead of ``manim.mobject.geometry``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:75\nmsgid \":pr:`2387`: Refactored :class:`~.BarChart` and made it inherit from :class:`~.Axes`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:74\nmsgid \":class:`~.BarChart` now inherits from :class:`~.Axes`, allowing it to use :class:`~.Axes`' methods. Also improves :class:`~.BarChart`'s configuration and ease of use.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:75\nmsgid \"Added :meth:`~.BarChart.get_bar_labels` to annotate the value of each bar of a :class:`~.BarChart`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:78\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:81\nmsgid \":pr:`2568`: Removed Deprecated Methods\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:81\nmsgid \"Removed methods and classes that were deprecated since v0.10.0 and v0.11.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:83\nmsgid \":pr:`2457`: Deprecated :class:`.ShowCreationThenFadeOut`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:87\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:89\nmsgid \":pr:`2442`: Added ``media_embed`` config option to control whether media in Jupyter notebooks is embedded\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:96\nmsgid \":pr:`2504`: Added finer control over :meth:`.Scene.wait` being static (i.e., no updaters) or not\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:93\nmsgid \"Added keyword argument ``frozen_frame`` to :class:`.Wait` and :meth:`.Scene.wait`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:94\nmsgid \"New convenience method: :meth:`.Scene.pause` (alias for ``Scene.wait(frozen_frame=True)``)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:95\nmsgid \"Changed default behavior for OpenGL updaters: updater functions are now not called by default when they are added\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:96\nmsgid \"Changed default behavior of :meth:`.Scene.should_mobjects_update`: made it respect the set value of ``Wait.frozen_frame``, changed automatic determination of frozen frame state to also consider Scene updaters\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:99\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:101\nmsgid \":pr:`2478`: Alternative scaling for tree graph layout\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:104\nmsgid \":pr:`2565`: Allowed passing vertex configuration keyword arguments to :meth:`.Graph.add_edges`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:107\nmsgid \":pr:`2467`: :class:`~.MathTex`, :class:`~.Tex`, :class:`~.Text` and :class:`~.MarkupText` inherit color from their parent mobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:110\nmsgid \":pr:`2537`: Added support for PySide coordinate system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:113\nmsgid \":pr:`2158`: Added OpenGL compatibility to :meth:`.ThreeDScene.add_fixed_orientation_mobjects` and  :meth:`.ThreeDScene.add_fixed_in_frame_mobjects`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:116\nmsgid \":pr:`2535`: Implemented performance enhancement for :meth:`.VMobject.insert_n_curves_to_point_list`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:119\nmsgid \":pr:`2516`: Cached view matrix for :class:`~.OpenGLCamera`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:122\nmsgid \":pr:`2508`: Improve performance for :meth:`.Mobject.become`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:125\nmsgid \":pr:`2332`: Changed ``color``, ``stroke_color`` and ``fill_color`` attributes to properties\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:131\nmsgid \":pr:`2396`: Fixed animations introducing or removing objects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:129\nmsgid \":class:`.ShowPassingFlash` now removes objects when the animation is finished\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:130\nmsgid \"Added ``introducer`` keyword argument to :class:`.Animation` analogous to ``remover``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:131\nmsgid \"Updated :class:`.Graph` vertex addition handling\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:134\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:136\nmsgid \":pr:`2574`: Improved Error in :mod:`.utils.tex_file_writing`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:139\nmsgid \":pr:`2580`: Fixed :func:`.find_intersection` in :mod:`.space_ops`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:142\nmsgid \":pr:`2576`: Fixed a bug with animation of removal of edges from a :class:`.Graph`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:145\nmsgid \":pr:`2556`: Fixed showing highlighted cells when creating :class:`.Table`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:148\nmsgid \":pr:`2559`: Fix setting line numbers in :class:`.Text` when using ManimPango settings\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:151\nmsgid \":pr:`2557`: Fixed logger bug in :meth:`.Camera.make_background_from_func`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:154\nmsgid \":pr:`2548`: Fixed :class:`.Axes` plotting bug with logarithmic x-axis\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:157\nmsgid \":pr:`1547`: Fixed certain unicode characters in users' paths causing issues on Windows\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:160\nmsgid \":pr:`2526`: Fixed segfault when using ``--enable_gui``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:163\nmsgid \":pr:`2538`: Fixed flickering OpenGL preview when using ``frozen_frame``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:166\nmsgid \":pr:`2528`: Fixed custom naming of gifs and added some tests\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:169\nmsgid \":pr:`2487`: Fixed :meth:`.ThreeDCamera.remove_fixed_orientation_mobjects`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:172\nmsgid \":pr:`2530`: Use single source of truth for default text values\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:175\nmsgid \":pr:`2494`: Fixed an issue related to previewing gifs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:178\nmsgid \":pr:`2490`: Fixed order of transformation application in :class:`~.SVGMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:181\nmsgid \":pr:`2357`: Fixed ``screeninfo.get_monitors`` for MacOS\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:184\nmsgid \":pr:`2444`: Fixed :meth:`.VectorScene.add_axes`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:188\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:190\nmsgid \":pr:`2560`: Refactored more docstrings in :mod:`.geometry`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:193\nmsgid \":pr:`2571`: Refactored docstrings in :mod:`.graphing`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:196\nmsgid \":pr:`2569`: Refactored docstrings in :mod:`.geometry`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:198\nmsgid \":pr:`2549`: Added a page for internals which links to our GitHub wiki\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:201\nmsgid \":pr:`2458`: Improved documentation for :class:`.Rotate`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:204\nmsgid \":pr:`2459`: Added examples to some transform animations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:207\nmsgid \":pr:`2517`: Added guide on profiling and improving performance\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:210\nmsgid \":pr:`2518`: Added imports to examples for ``deprecation`` decorator\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:213\nmsgid \":pr:`2499`: Improved help text for ``--write_to_movie``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:216\nmsgid \":pr:`2465`: Added documentation for :func:`.index_labels`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:219\nmsgid \":pr:`2495`: Updated minimal LaTeX installation instructions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:222\nmsgid \":pr:`2500`: Added note about contributions during refactor period\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:225\nmsgid \":pr:`2431`: Changed example in :meth:`.Surface.set_fill_by_value`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:228\nmsgid \":pr:`2485`: Fixed some typos in documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:231\nmsgid \":pr:`2493`: Fixed typo in documentation for parameters of :class:`.Square`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:234\nmsgid \":pr:`2482`: Updated Python version requirement in installation guide\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:237\nmsgid \":pr:`2438`: Removed unnecessary rotation from example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:240\nmsgid \":pr:`2468`: Hid more private methods from the docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:243\nmsgid \":pr:`2466`: Fixed a typo in the documentation for plugins\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:246\nmsgid \":pr:`2448`: Improvements to the ``.pot`` files cleaning system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:249\nmsgid \":pr:`2436`: Fixed typo and improved example in building blocks tutorial\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:253\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:255\nmsgid \":pr:`2554`: Removed ``Remove-Item`` calls for MSYS2 Python\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:258\nmsgid \":pr:`2531`: Added a GitHub Action for automatic validation of citation metadata\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:261\nmsgid \":pr:`2536`: Upgraded version of setup-ffmpeg CI action\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:264\nmsgid \":pr:`2484`: Updated tinytex download URL\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:268\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:270\nmsgid \":pr:`2573`: Moved :mod:`.value_tracker` back inside :mod:`.mobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:273\nmsgid \":pr:`2566`: Removed unused livestream-related imports and functions from :mod:`.scene_file_writer`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:276\nmsgid \":pr:`2524`: Reworked :mod:`.space_ops`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:279\nmsgid \":pr:`2519`: Removed outdated comment\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:282\nmsgid \":pr:`2503`: Removed unused imports\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:285\nmsgid \":pr:`2475`: Removed setuptools dependency\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:288\nmsgid \":pr:`2472`: Removed unnecessary comment in :mod:`.simple_functions`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:291\nmsgid \":pr:`2429`: Upgraded to future-style type annotations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:294\nmsgid \":pr:`2464`: Bump pillow from 8.4.0 to 9.0.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:297\nmsgid \":pr:`2376`: Updated dependencies for Python 3.10\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:305\nmsgid \":pr:`2437`: Cleaned up :mod:`.simple_functions`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:301\nmsgid \"Removed ``fdiv`` as in all cases where it was used, it was just doing the same thing as numpy array division.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:302\nmsgid \"Replaced old implementation of the choose function with scipy's implementation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:303\nmsgid \"Use ``lru_cache`` (least recently used cache) for caching the choose function. Since it's only used for beziers, only 2 choose k and 3 choose k will be used, hence a size of 10 should be enough.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:304\nmsgid \"Removed ``clip_in_place`` in favor of ``np.clip``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:305\nmsgid \"Removed one use of ``clip_in_place`` that wasn't actually doing anything\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:307\nmsgid \":pr:`2439`: Removed twitter template from scripts\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.0-changelog.rst:311\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.15.1-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:3\nmsgid \"v0.15.1\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:5\nmsgid \"March 08, 2022\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:10\nmsgid \"A total of 9 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:14\n#: ../../source/changelog/0.15.1-changelog.rst:24\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:15\nmsgid \"Nicolai Weitkemper\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:16\nmsgid \"Yuchen +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:17\n#: ../../source/changelog/0.15.1-changelog.rst:28\nmsgid \"ad_chaos\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:20\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:23\nmsgid \"Alex Lembcke\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:25\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:26\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:27\nmsgid \"Raghav Goel\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:29\nmsgid \"icedcoffeeee\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:32\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:34\nmsgid \"A total of 9 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:37\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:39\nmsgid \":pr:`2602`: Support groups in :class:`.TransformMatchingTex`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:43\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:45\nmsgid \":pr:`2594`: Fixed render flow issues with introducer animations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:48\nmsgid \":pr:`2584`: Fixed bug with invalid color type ``None``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:51\nmsgid \":pr:`2587`: Fixed bug with rendering Tex string that contain ``%``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:54\nmsgid \":pr:`2593`: Fixed bug with displaying images in Jupyter Notebooks when ``config.media_embed`` is set to ``False``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:58\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:60\nmsgid \":pr:`2570`: Refactored docstrings in :mod:`.coordinate_systems`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:63\nmsgid \":pr:`2603`: Reduced the number of warnings during documentation build\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:67\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:69\nmsgid \":pr:`2578`: Fixed incorrect type hint for color property of :class:`.Text`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.1-changelog.rst:73\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.15.2-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:3\nmsgid \"v0.15.2\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:5\nmsgid \"April 25, 2022\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:10\nmsgid \"A total of 33 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:14\nmsgid \"Bailey Powers +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:15\n#: ../../source/changelog/0.15.2-changelog.rst:44\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:16\nmsgid \"Dan Walsh +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:17\nmsgid \"Darigov Research\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:18\n#: ../../source/changelog/0.15.2-changelog.rst:46\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:19\nmsgid \"David Millard +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:20\nmsgid \"Hamidreza Hashemi +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:21\n#: ../../source/changelog/0.15.2-changelog.rst:49\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:22\n#: ../../source/changelog/0.15.2-changelog.rst:50\nmsgid \"Jason Villanueva\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:23\nmsgid \"Jonathan Alpert +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:24\nmsgid \"Joy Bhalla\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:25\nmsgid \"Kian Cross +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:26\nmsgid \"Luca +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:27\nmsgid \"Mohsin Shaikh +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:28\n#: ../../source/changelog/0.15.2-changelog.rst:53\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:29\nmsgid \"Prismo +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:30\n#: ../../source/changelog/0.15.2-changelog.rst:55\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:31\nmsgid \"WillSoltas +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:32\n#: ../../source/changelog/0.15.2-changelog.rst:56\nmsgid \"ad_chaos\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:33\nmsgid \"darkways +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:34\nmsgid \"dawn*squirryl +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:35\n#: ../../source/changelog/0.15.2-changelog.rst:59\nmsgid \"icedcoffeeee\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:36\n#: ../../source/changelog/0.15.2-changelog.rst:60\nmsgid \"peaceheis\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:37\nmsgid \"sparshg\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:38\nmsgid \"trickypr +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:41\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:45\nmsgid \"Dan Walsh\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:47\nmsgid \"GameDungeon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:48\nmsgid \"Hugues Devimeux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:51\nmsgid \"Jonathan Alpert\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:52\nmsgid \"Luca\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:54\nmsgid \"Prismo\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:57\nmsgid \"darkways\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:58\nmsgid \"hickmott99\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:63\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:65\nmsgid \"A total of 39 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:68\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:74\nmsgid \":pr:`1975`: Improved CLI help page styling\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:71\nmsgid \"Updates dependencies on Click and Cloup libraries for CLI help page styling.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:72\nmsgid \"Removed the dependency on click-default-group.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:73\nmsgid \"Added ``no_args_is_help`` parameter for ``manim render`` to allow easy access to help page.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:74\nmsgid \"Added note to ``manim`` help page epilog on how to access other command help pages.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:77\nmsgid \":pr:`2404`: Add :class:`.SpiralIn` Animation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:77\nmsgid \"Make :class:`.ManimBanner` to use :class:`.SpiralIn`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:79\nmsgid \":pr:`2534`: Implement :class:`~.OpenGLImageMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:82\nmsgid \":pr:`2684`: Created a more accessible way to create Angles with line.py angle function - :meth:`.Angle.from_three_points`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:86\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:88\nmsgid \":pr:`2062`: Reuse shader wrappers and shader data\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:92\nmsgid \":pr:`2642`: Migrated ``file_ops.py`` and ``scene_file_writer.py`` from os.path to Pathlib\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:92\nmsgid \"In ``file_ops.py`` and ``scene_file_writer.py``: Uses of str type file names have been mostly (see further information) converted to pathlib's Path objects. Uses of ``os.path`` methods have been converted to equivalent pathlib methods.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:94\nmsgid \":pr:`2655`: Fix :func:`.assert_is_mobject_method` when using OpenGL\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:97\nmsgid \":pr:`2665`: Improved handling of attributes when using the ``.animate`` syntax\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:102\nmsgid \":pr:`2674`: Document and type ``simple_functions.py``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:101\nmsgid \"Add documentation for ``simple_functions.py``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:102\nmsgid \"Small additions with some extra clarity for these functions.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:105\nmsgid \":pr:`2693`: Allow using :meth:`.MovingCamera.auto_zoom` without animation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:105\nmsgid \"Allows auto zooming camera without having to play an animation by passing an ``animation=False`` argument\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:108\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:110\nmsgid \":pr:`2546`: Fixed a file logging bug and some maintenance\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:116\nmsgid \":pr:`2597`: Fix Bug in :class:`.Uncreate` with ``rate_func`` via introducing new parameter ``reversed`` to :class:`.Animation`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:114\nmsgid \"Refractor the :class:`.Uncreate`. The new implementation uses a flag member ``reversed``. Set it to ``True`` and its superclass handles the reverse.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:115\nmsgid \"Introduce a bool parameter ``reversed`` to :class:`.Animation`. It decides whether the animation needs to be played backwards. Default to be False.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:116\nmsgid \"Add conditional branches in :meth:`.Animation.get_sub_alpha`. If the parameter ``reversed`` is True, it would set ``rate_func(t)`` to ``rate_func(1 - t)``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:118\nmsgid \":pr:`2613`: Fixed bug in :meth:`.Circle.point_at_angle` when the angle is not in the interval :math:`[0, 2\\\\pi]`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:121\nmsgid \":pr:`2634`: Fix background lines drawn twice in :class:`.NumberPlane`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:124\nmsgid \":pr:`2648`: Handle user-defined centers for Wiggle animation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:128\nmsgid \":pr:`2658`: Fix arguments of overridden ``set_style`` for :class:`.BackgroundRectangle`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:128\nmsgid \"Using :class:`.Write` animation on a :class:`.Text` object with ``.add_background_rectangle()`` applied no longer generates a ``TypeError``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:130\nmsgid \":pr:`2668`: (Re)set background color of :class:`.OpenGLRenderer` when initializing scene\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:133\nmsgid \":pr:`2676`: Fixed propagation of custom attributes in animations for the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:136\nmsgid \":pr:`2688`: Fixed two minor issues of :class:`.SpiralIn` and :class:`.ManimBanner`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:140\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:142\nmsgid \":pr:`2609`: Copyedit troubleshooting.rst\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:145\nmsgid \":pr:`2610`: Add example PolygonOnAxes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:148\nmsgid \":pr:`2617`: Re-added :mod:`.value_tracker` documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:151\nmsgid \":pr:`2619`: Improve Example for arrange_in_grid\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:154\nmsgid \":pr:`2620`: Fixed typo in :meth:`.Animation.is_introducer`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:158\nmsgid \":pr:`2640`: Copyedited Documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:158\nmsgid \"Reviewed ``tutorials/configurations.rst``. Edited simple mistakes such as Manim not being capitalized and commas.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:160\nmsgid \":pr:`2649`: Document and type utils/iterables.py\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:163\nmsgid \":pr:`2651`: Update copyright year in documentation to 2020-2022\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:165\nmsgid \":pr:`2663`: Added documentation for scene updater functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:168\nmsgid \":pr:`2686`: Add instructions to install extra dependencies with poetry\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:172\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:174\nmsgid \":pr:`2561`: Run tests on Linux-aarch64\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:177\nmsgid \":pr:`2656`: Fixed incompatibility with black version\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:181\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:184\nmsgid \":pr:`2630`: Remove WebGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:184\nmsgid \"The WebGL renderer is broken and unmaintained. The support for it in Manim is removed.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:186\nmsgid \":pr:`2652`: Update ``cloup`` version to 0.13.0 from 0.7.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:189\nmsgid \":pr:`2678`: Require ``backports-cached-property`` only for Python < 3.8\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:193\nmsgid \":pr:`2685`: Migrate from ``os.path`` to ``pathlib`` in testing scripts\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:193\nmsgid \"This pull request changes a number of instances of ``os.path`` to Pathlib objects and functions. In addition, this PR modifies the SVGMobject constructor to accept both a Pathlib object or a string variable pathname its constructor.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:195\nmsgid \":pr:`2691`:  Removed :class:`CameraFrame`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:198\nmsgid \":pr:`2696`: Made changelog generation run in parallel plus further improvements to ``scripts/dev_changelog.py``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:201\nmsgid \":pr:`2697`: Sort PRs by number in changelog sections before writing\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.15.2-changelog.rst:205\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.16.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:3\nmsgid \"v0.16.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:5\nmsgid \"July 13, 2022\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:10\nmsgid \"A total of 44 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:14\n#: ../../source/changelog/0.16.0-changelog.rst:51\nmsgid \"Alex Lembcke\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:15\nmsgid \"Baroudi Aymen +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:16\n#: ../../source/changelog/0.16.0-changelog.rst:52\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:17\nmsgid \"Charalampos Georgiou +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:18\nmsgid \"Cindy Park +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:19\nmsgid \"Ejar +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:20\nmsgid \"Francesco Frassinelli +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:21\nmsgid \"Francisco Manríquez Novoa +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:22\nmsgid \"Jacob Evan Shreve +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:23\nmsgid \"Jaime Santos +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:24\n#: ../../source/changelog/0.16.0-changelog.rst:58\nmsgid \"Jonathan Alpert\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:25\nmsgid \"Joshua Mankelow +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:26\nmsgid \"Kevin Lubick +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:27\n#: ../../source/changelog/0.16.0-changelog.rst:60\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:28\nmsgid \"Lingren Kong +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:29\nmsgid \"Logen +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:30\n#: ../../source/changelog/0.16.0-changelog.rst:61\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:31\nmsgid \"Noam Zaks\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:32\nmsgid \"Pedro Lamkowski +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:33\n#: ../../source/changelog/0.16.0-changelog.rst:64\nmsgid \"Raghav Goel\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:34\nmsgid \"Simeon Widdis\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:35\n#: ../../source/changelog/0.16.0-changelog.rst:66\nmsgid \"Sparsh Goenka\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:36\nmsgid \"TornaxO7 +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:37\nmsgid \"Tristan Schulz +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:38\nmsgid \"WillSoltas\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:39\n#: ../../source/changelog/0.16.0-changelog.rst:69\nmsgid \"ad_chaos\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:40\nmsgid \"conor-oneill-2 +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:41\nmsgid \"fcrozatier +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:42\nmsgid \"mooncaker816 +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:43\nmsgid \"niklebedenko +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:44\nmsgid \"nyabkun +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:45\nmsgid \"quark67\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:48\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:53\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:54\nmsgid \"Francesco Frassinelli\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:55\nmsgid \"Francisco Manríquez Novoa\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:56\nmsgid \"Gianluca Gippetto\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:57\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:59\nmsgid \"Kevin Lubick\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:62\nmsgid \"Pedro Lamkowski\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:63\nmsgid \"Philipp Imhof\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:65\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:67\nmsgid \"TornaxO7\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:68\nmsgid \"Tristan Schulz\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:70\nmsgid \"hickmott99\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:73\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:75\nmsgid \"A total of 56 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:78\nmsgid \"Highlights\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:82\nmsgid \":pr:`2550`: New thematic guide: a deep dive into the internals of the library\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:81\nmsgid \"This new :doc:`thematic guide </guides/deep_dive>` aims to be a comprehensive walkthrough describing all the things that Manim does when you run it to produce a video.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:84\nmsgid \":pr:`2732`: Improved overall structure of deployed documentation; added a dedicated :doc:`FAQ section </faq/index>`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:90\nmsgid \":pr:`2749`: Added :class:`.ChangeSpeed`, an animation wrapper that allows to smoothly change the speed at which an animation is played\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:88\nmsgid \"The speed of any animation can be changed by wrapping the animation with :class:`.ChangeSpeed` and passing a dictionary as ``speedinfo`` whose keys are the relative animation run time stamps and whose values are the absolute speed factors; e.g., ``{0.5: 2, 0.75: 0.25}`` smoothly speeds up the animation by a factor of 2 once it has been completed to 50%, and then it is smoothly slowed down to 1/4 of the default run speed after 75% of the animation are completed. The ``run_time`` of the animation will be adjusted to match the changed play speed.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:90\nmsgid \"It is also possible to add time-based updaters that respect the change in speed, use the auxiliary :meth:`.ChangeSpeed.add_updater` method to do so.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:93\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:95\nmsgid \":pr:`2667`: Made FFmpeg executable path configurable\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:98\nmsgid \":pr:`2739`: Added vectorized plotting functionality via keyword argument ``use_vectorized`` to improve performance\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:102\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:104\nmsgid \":pr:`2186`: Enabled filling color by value for :class:`.OpenGLSurface`, replaced ``colors`` keyword argument of :meth:`.Surface.set_fill_by_value`  with ``colorscale``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:107\nmsgid \":pr:`2288`: Added warning when attempting to add same mobject as child twice\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:112\nmsgid \":pr:`2707`: Fixed missing ``get_nth_curve_length_pieces`` method of :class:`.OpenGLVMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:111\nmsgid \"Removed duplicate definition of ``get_curve_functions_with_lengths`` in ``OpenGLVMobject``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:112\nmsgid \"Added definition of ``get_nth_curve_length_pieces`` to ``OpenGLVMobject``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:114\nmsgid \":pr:`2709`: Improved the look of the brackets of :class:`.Matrix`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:117\nmsgid \":pr:`2714`: Fixed :meth:`.OpenGLVMobject.pointwise_become_partial` to improve stroke rendering\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:120\nmsgid \":pr:`2727`: Slight performance improvement for :class:`.ArrowVectorField` and Bézier curve computation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:123\nmsgid \":pr:`2728`: Added :meth:`.VectorField.fit_to_coordinate_system` to fit a vector field to a given coordinate system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:126\nmsgid \":pr:`2730`: Added note to let users find documentation of default CLI subcommand easier\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:129\nmsgid \":pr:`2746`: Installed ghostscript in the docker image\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:132\nmsgid \":pr:`2841`: Added :func:`.split_quadratic_bezier` and :func:`.subdivide_quadratic_bezier`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:135\nmsgid \":pr:`2842`: CLI: Moved functionality from ``manim new`` to ``manim init`` and added deprecation warning for ``manim new``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:138\nmsgid \":pr:`2866`: Reorganize test files to match library module structure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:142\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:144\nmsgid \":pr:`2567`: Use tempconfig for every scene render\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:147\nmsgid \":pr:`2638`: Fixed :meth:`BarChart.change_bar_values`  not updating when height is 0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:150\nmsgid \":pr:`2661`: Fixed tip resize functionality for :class:`.Axes` to match documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:153\nmsgid \":pr:`2703`: Default to utf-8 when reading files in :class:`.Code`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:156\nmsgid \":pr:`2721`: Fixed bad text slicing for lines in :class:`.Paragraph`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:159\nmsgid \":pr:`2725`: Fixed wrong indentation in :class:`.Code`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:162\nmsgid \":pr:`2734`: Fixed OpenGL segfaults when running :meth:`.Scene.play` or :meth:`.Scene.wait` in interactive mode\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:165\nmsgid \":pr:`2753`: Fixed multiplatform builds for docker images in pipeline\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:168\nmsgid \":pr:`2757`: Added missing ``__init__.py`` file in :mod:`.docbuild` module\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:171\nmsgid \":pr:`2770`: Fixed bug in :meth:`.VMobject.proportion_from_point` that caused proportions greater than 1 to be returned\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:174\nmsgid \":pr:`2826`: Fixed leaked mobjects coming from :class:`.TransformMatchingAbstractBase`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:177\nmsgid \":pr:`2870`: Fixed issue with ``manim init scene SCENE_NAME filename.py`` and removed necessity of ``main.py`` to be present in working directory\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:181\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:183\nmsgid \":pr:`2704`: Updated URL to Pango Markup formatting page\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:186\nmsgid \":pr:`2716`: Improved the order of the reference manuals\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:189\nmsgid \":pr:`2720`: Fixed typo in docstring of :class:`.Angle`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:192\nmsgid \":pr:`2722`: Fixed typos in docstrings of classes in :mod:`.mobject.table`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:195\nmsgid \":pr:`2726`: Edited note on :class:`.NumberPlane` length and added another example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:198\nmsgid \":pr:`2740`: Fixed documentation of :meth:`.Cylinder.get_direction`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:201\nmsgid \":pr:`2755`: Fixed docstring of  :meth:`.VMobject.get_end_anchors`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:204\nmsgid \":pr:`2760`: Removed ``cmake`` from the MacOS installation section\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:207\nmsgid \":pr:`2767`: Added more questions and answers to FAQ section, new :doc:`OpenGL FAQ </faq/opengl>`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:210\nmsgid \":pr:`2771`: Added documentation and testing for ``path_func`` keyword argument of :class:`.Transform`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:213\nmsgid \":pr:`2828`: Removed suggestion issue template, added FAQ answer regarding proposing new features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:216\nmsgid \":pr:`2849`: Added example for ``path_arc`` keyword argument of :class:`.Transform`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:219\nmsgid \":pr:`2851`: Added an example on constructing a (neural) network using a partite :class:`.Graph`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:222\nmsgid \":pr:`2855`: Added implicit ``docker.io/`` URL base in reference to docker images\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:225\nmsgid \":pr:`2861`: Added docstring for :meth:`.CoordinateSystem.plot_parametric_curve`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:229\nmsgid \"Changes concerning the testing system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:231\nmsgid \":pr:`2743`: Replaced ``assert`` statements with with assertion functions from ``np.testing``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:235\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:237\nmsgid \":pr:`2700`: CI: updated Python versions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:240\nmsgid \":pr:`2701`: CI: added a workflow to publish docker image after releases and commits to main branch\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:244\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:246\nmsgid \":pr:`2680`: Increased minimum required version of ``numpy`` to 1.19\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:249\nmsgid \":pr:`2687`: Migrated from ``os.path`` to ``pathlib`` in :class:`.SVGMobject` and other locations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:252\nmsgid \":pr:`2715`: Updated deprecated ``pillow`` constants\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:255\nmsgid \":pr:`2735`: Bump pyjwt from 2.3.0 to 2.4.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:258\nmsgid \":pr:`2748`: Bump pillow from 9.1.0 to 9.1.1\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:261\nmsgid \":pr:`2751`: Fixed flake C417 and improved a comment\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:264\nmsgid \":pr:`2825`: Bump notebook from 6.4.11 to 6.4.12\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:267\nmsgid \":pr:`2864`: Updated lockfile\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.16.0-changelog.rst:271\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.2.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:3\nmsgid \"v0.2.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:5\nmsgid \"January 1, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:7\nmsgid \"The changes since Manim Community release v0.1.1 are listed below.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:10\nmsgid \"Breaking Changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:12\nmsgid \"Remove all CONFIG dictionaries and all calls to ``digest_config`` and allow passing options directly to the constructor of the corresponding classes (:pr:`783`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:15\nmsgid \"Practically, this means that old constructions using ``CONFIG`` like::\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:22\nmsgid \"where corresponding objects were then instantiated as ``my_mobject = SomeMobject()`` should now be created simply using ``my_mobject = SomeMobject(my_awesome_property=42)``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:25\nmsgid \"Remove old syntax for animating mobject methods by passing the methods and arguments to ``self.play``, and use a new syntax featuring the ``animate`` property (:pr:`881`).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:28\nmsgid \"For example: the old-style ``play`` call ::\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:33\nmsgid \"should be replaced with the new following call using the ``animate`` property::\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:38\nmsgid \"New Features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:40\nmsgid \"Added creation animation for :class:`~.ManimBanner` (:pr:`814`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:41\nmsgid \"Added some documentation to :meth:`~.Scene.construct` (:pr:`753`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:42\nmsgid \"Added a black and white monochromatic version of Manim's logo (:pr:`826`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:43\nmsgid \"Added support for a plugin system (``manim plugin`` subcommand + documentation) (:pr:`784`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:44\nmsgid \"Implemented ``__add__``, ``__iadd__``, ``__sub__``, and ``__isub__`` for :class:`~.Mobject` (allowing for notation like ``some_vgroup + some_mobject``) (:pr:`790`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:45\nmsgid \"Added type hints to several files in the library (:pr:`835`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:46\nmsgid \"Added some examples to :mod:`~.animation.creation` (:pr:`820`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:47\nmsgid \"Added some examples to :class:`~.DashedLine` and :class:`~.CurvesAsSubmobjects` (:pr:`833`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:48\nmsgid \"Added new implementation for text rendered with Pango, :class:`~.MarkupText`, which can be formatted with an HTML-like syntax (:pr:`855`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:49\nmsgid \"Added Fading in and out examples and deprecation of ``FadeInFromDown`` and ``FadeOutAndShiftDown`` (:pr:`827`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:50\nmsgid \"Added example for :class:`~.MoveAlongPath` to the docs (:pr:`873`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:51\nmsgid \"Added ambient rotate for other angles - theta, phi, gamma (:pr:`660`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:52\nmsgid \"Use custom bindings for Pango (:pr:`878`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:53\nmsgid \"Added :class:`~.Graph`, a basic implementation for (graph theory) graphs (:pr:`861`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:54\nmsgid \"Allow for chaining methods when using the new ``.animate`` syntax in :meth:`~.Scene.play` (:pr:`889`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:57\nmsgid \"Bugfixes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:59\nmsgid \"Fix doctests in .rst files (:pr:`797`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:60\nmsgid \"Fix failing doctest after adding ``manim plugin`` subcommand (:pr:`831`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:61\nmsgid \"Normalize the direction vector in :meth:`~.mobject_update_utils.always_shift` (:pr:`839`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:62\nmsgid \"Add ``disable_ligatures`` to :class:`~.Text` (via :pr:`804`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:63\nmsgid \"Make scene caching aware of order of Mobjects (:pr:`845`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:64\nmsgid \"Fix :class:`~.CairoText` to work with new config structure (:pr:`858`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:65\nmsgid \"Added missing argument to classes inheriting from :class:`~.Matrix` (:pr:`859`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:66\nmsgid \"Fixed: ``z_index`` of mobjects contained in others as submobjects is now properly respected (:pr:`872`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:67\nmsgid \"Let :meth:`~.ParametricSurface.set_fill_by_checkboard` return the modified surface to allow method chaining (:pr:`883`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:68\nmsgid \"Mobjects added during an updater are added to ``Scene.moving_mobjects`` (:pr:`838`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:69\nmsgid \"Pass background color to JS renderer (:pr:`876`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:70\nmsgid \"Small fixes to docstrings. Tiny cleanups. Remove ``digest_mobject_attrs``. (:pr:`834`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:71\nmsgid \"Added closed shape detection in :class:`~.DashedVMobject` in order to achieve an even dash pattern (:pr:`884`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:72\nmsgid \"Fix Spelling in docstrings and variables across the library (:pr:`890`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:75\nmsgid \"Other changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:77\nmsgid \"Change library name to manim (:pr:`811`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:78\nmsgid \"Docker: use local files when building an image (:pr:`803`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:79\nmsgid \"Let ffmpeg render partial movie files directly instead of temp files (:pr:`817`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:80\nmsgid \"``manimce`` to ``manim`` & capitalizing Manim in readme (:pr:`794`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:81\nmsgid \"Added flowchart for different docstring categories (:pr:`828`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:82\nmsgid \"Improve example in module docstring of :mod:`~.animation.creation` + explicitly document buff parameter in :meth:`~.Mobject.arrange` (:pr:`825`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:83\nmsgid \"Disable CI pipeline for Python 3.6 (:pr:`823`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:84\nmsgid \"Update URLs in docs (:pr:`832`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:85\nmsgid \"Move upcoming changelog to GitHub-wiki (:pr:`822`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:86\nmsgid \"Change badges in readme (:pr:`854`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:87\nmsgid \"Exclude generated gRPC files from source control (:pr:`868`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:88\nmsgid \"Added linguist-generated attribute to ``.gitattributes`` (:pr:`877`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:89\nmsgid \"Cleanup: removed inheritance from ``object`` for some classes, refactor some imports (:pr:`795`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:90\nmsgid \"Change several ``str.format()`` to ``f``-strings (:pr:`867`)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.2.0-changelog.rst:91\nmsgid \"Update javascript renderer (:pr:`830`)\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.3.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:3\nmsgid \"v0.3.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:5\nmsgid \"February 1, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:7\nmsgid \"The changes since Manim Community release v0.2.0 are listed below.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:11\nmsgid \"New Features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:13\nmsgid \":pr:`945`: :meth:`~.Graph.change_layout` method for :class:`~.Graph` mobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:14\nmsgid \":pr:`943`: IPython %%manim magic\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:15\nmsgid \":pr:`970`: Added ``--version`` command line flag\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:16\nmsgid \":pr:`948`: Allow passing a code string to :class:`~.Code`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:17\nmsgid \":pr:`917`: Allow overriding new-style method animations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:18\nmsgid \":pr:`756`: Allow setting frame_height and frame_width via config file\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:19\nmsgid \":pr:`939`: Added custom font files support\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:20\nmsgid \":pr:`892`: Added ManimCommunity colors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:21\nmsgid \":pr:`922`: Tree layout for Graph mobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:22\nmsgid \":pr:`935`: Added code of conduct\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:23\nmsgid \":pr:`916`: Multi-column layout for partite graphs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:24\nmsgid \":pr:`742`: Units: Pixels, Munits, Percent in :mod:`~.utils.unit`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:25\nmsgid \":pr:`893`: Convenience method :meth:`~.Graph.from_networkx` for creating a graph from a networkx graph\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:28\nmsgid \"Bugfixes and Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:30\nmsgid \":pr:`988`: Fix Windows CI pipeline by adding missing LaTeX package\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:31\nmsgid \":pr:`961`: Added typings and docs for vectorized mobjects and bezier related functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:32\nmsgid \":pr:`977`: JupyterLab docker image and documentation for manim and IPython\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:33\nmsgid \":pr:`985`: Fix variable name for webgl renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:34\nmsgid \":pr:`954`: Fix edges lagging behind vertices in animations of graphs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:35\nmsgid \":pr:`980`: Allow usage of custom Pygments styles in Code\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:36\nmsgid \":pr:`952`: Allow passing tween information to the WebGL frontend\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:37\nmsgid \":pr:`978`: Fix ``possible_paths`` not printing in ``code_mobject``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:38\nmsgid \":pr:`976`: Update ``ManimPango``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:39\nmsgid \":pr:`967`: Automatically import plugins\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:40\nmsgid \":pr:`971`: Make ManimCommunity look consistent\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:41\nmsgid \":pr:`957`: Raise ``NotImplementedError`` when trying to chain overridden method animations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:42\nmsgid \":pr:`947`: Several fixes and improvements for :class:`~.PointCloundDot`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:43\nmsgid \":pr:`923`: Documentation: move installation instructions for developers to page for developers\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:44\nmsgid \":pr:`964`: Added unit test for :class:`~.NumberLine`'s unit vector\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:45\nmsgid \":pr:`960`: Magnitude of :class:`~.NumberLine`'s unit vector should be ``unit_size``, not 1\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:46\nmsgid \":pr:`958`: Fix code formatting in ``utils/debug.py``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:47\nmsgid \":pr:`953`: Update license year\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:48\nmsgid \":pr:`944`: Interpolate stroke opacity in :class:`~.FadeIn` and update ``stroke_opacity`` and ``fill_opacity`` in :meth:`~.VMobject.set_stroke` and :meth:`~.VMobject.set_fill`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:49\nmsgid \":pr:`865`: Rename ``get_submobject_index_labels`` to ``index_labels``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:50\nmsgid \":pr:`941`: Added keyword arguments ``x_min``, ``x_max``, ``y_min``, ``y_max`` to :class:`~.ThreeDAxes`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:51\nmsgid \":pr:`886`: Let the render progress bar show details about the rendered animation again\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:52\nmsgid \":pr:`936`: Fix :class:`~.BulletedList` TeX environment problem and add a typing to ``get_module``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:53\nmsgid \":pr:`938`: Remove dependency on progressbar\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:54\nmsgid \":pr:`937`: Change 'brew cask install' to 'brew install --cask' for CI pipeline\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:55\nmsgid \":pr:`933`: Make matrix work with lists again\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:56\nmsgid \":pr:`932`: Correctly parse ``log_dir`` option\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:57\nmsgid \":pr:`920`: Raise error if markup in :class:`~.MarkupText` is invalid\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:58\nmsgid \":pr:`929`: Raise an error if a :class:`~.Matrix` object is created with < 2-dimensional input\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:59\nmsgid \":pr:`907`: Make Scene.add_sound work again (when running with ``--disable_caching``)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:60\nmsgid \":pr:`906`: Allow new-style method animation to be used in animation groups\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:61\nmsgid \":pr:`908`: Removed deprecated command line arguments from documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:62\nmsgid \":pr:`903`: Tiny grammar improvements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.3.0-changelog.rst:63\nmsgid \":pr:`904`: Added blank line between imports and class example\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.4.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:3\nmsgid \"v0.4.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:5\nmsgid \"March 3, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:7\nmsgid \"The changes since Manim Community release v0.3.0 are listed below.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:10\nmsgid \"Breaking Changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:12\nmsgid \":pr:`915`: Manim's SVG engine has been reworked and is able to handle a wider variations of SVG files. In particular: fill and stroke properties are now retained from the original files. Breaking change: ``VMobjectFromSVGPathstring`` is deprecated and has been renamed to ``SVGPathMobject``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:16\nmsgid \"New Features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:18\nmsgid \":pr:`1026`: Add 3D Mobjects: :class:`~.Cone`, :class:`~.Cylinder`, :class:`~.Line3D`, :class:`~.Arrow3D` and :class:`~.Torus`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:19\nmsgid \":pr:`1047`: Add documentation and examples for :class:`~.Matrix`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:20\nmsgid \":pr:`1044`: ``register_font`` is available for macOS\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:21\nmsgid \":pr:`995`: Add generic :func:`~.Mobject.set` method and compatibility layer between properties and ``get_*``/``set_*`` methods\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:24\nmsgid \"Bugfixes and Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:26\nmsgid \":pr:`981`: Fixed hot reload functionality for the WebGL renderer on Windows\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:27\nmsgid \":pr:`1053`: Repair links to source code in stable version of documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:28\nmsgid \":pr:`1067`: Add ManimPango to ReadTheDocs requirements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:29\nmsgid \":pr:`1058`: Replace ``<color>`` syntax by Pango's ``<span foreground>`` for coloring parts of :class:`~.MarkupText` and allow using colors for underline, overline and strikethrough in MarkupText\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:30\nmsgid \":pr:`1063`: Fix documentation related to ``.animate``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:31\nmsgid \":pr:`1065`: Remove duplicate word 'vector'\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:32\nmsgid \":pr:`1060`: Update Linux installation instructions to mention the installation of Pango\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:33\nmsgid \":pr:`1050`: Ensure that the user-supplied stroke color and width gets applied to :class:`~.Cross`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:34\nmsgid \":pr:`1059`: More descriptive error when accessing an unhandled mobject attribute\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:35\nmsgid \":pr:`1048`: Use absolute path in ``make_and_open_docs.py``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:36\nmsgid \":pr:`1000`: Remove ``MovingCameraScene.setup`` and ``MovingCameraScene.camera_frame``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:37\nmsgid \":pr:`1051`: Corrections for setting stroke related attributes on :class:`~.VMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:38\nmsgid \":pr:`1043`: Make :class:`~.CubicBezier` explicitly accept four points\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:39\nmsgid \":pr:`1046`: Use any version of ``importlib-metadata``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:40\nmsgid \":pr:`1030`: Parse ``.log`` file and try to print LaTeX errors if compilation fails\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:41\nmsgid \":pr:`1015`: Documentation: Add more explicit instructions related to ``tlmgr``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:42\nmsgid \":pr:`1028`: Documentation: Update installation guide on mac with Apple Silicon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:43\nmsgid \":pr:`1032`: Remove ``Square.side_length`` property\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:44\nmsgid \":pr:`1031`: Fix link to wikipedia vector graphics page\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:45\nmsgid \":pr:`1021`: Documentation: Added example to :class:`~.CubicBezier`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:46\nmsgid \":pr:`1017`: Added ``progress_bar`` to ``digest_args`` to fix the ``--progress_bar`` CLI flag\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:47\nmsgid \":pr:`1018`: Remove redundancy in :class:`~.FunctionGraph` arguments\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:48\nmsgid \":pr:`1024`: Migrate ``width`` / ``height`` / ``depth`` to properties\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:49\nmsgid \":pr:`1022`: Fix ``-p`` flag when passing ``-s``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:50\nmsgid \":pr:`1008`: CI pipeline: fix release asset upload\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:51\nmsgid \":pr:`983`: Make sure last frame for animations with updaters is correct\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:52\nmsgid \":pr:`984`: Add manim version to CLI output, append version name for generated ``.gif`` and ``.png`` files, add version to metadata of rendered videos, change dark blue terminal text to default green\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:53\nmsgid \":pr:`993`: Fix setting Mobject color to a gradient by passing a list of colors in :meth:`~.VMobject.set_color`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:54\nmsgid \":pr:`1003`: Fix animation :class:`~.GrowArrow`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:55\nmsgid \":pr:`1010`: Disable STDIN interaction for ffmpeg concat.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:56\nmsgid \":pr:`969`: Fix the ``--tex_template`` CLI flag\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:57\nmsgid \":pr:`989`: Fix the ``manim cfg export`` subcommand\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:58\nmsgid \":pr:`1005`: Fix the feature where ``-`` is used as the filename\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.4.0-changelog.rst:59\nmsgid \":pr:`998`: Allow using hexadecimal color codes with 3 characters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.5.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:3\nmsgid \"v0.5.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:5\nmsgid \"April 02, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:10\nmsgid \"A total of 35 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:14\nmsgid \"Abel Aebker +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:15\n#: ../../source/changelog/0.5.0-changelog.rst:47\nmsgid \"Abhijith Muthyala\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:16\nmsgid \"AntonBallmaier +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:17\nmsgid \"Aron\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:18\n#: ../../source/changelog/0.5.0-changelog.rst:48\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:19\nmsgid \"Bogdan Stăncescu +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:20\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:21\n#: ../../source/changelog/0.5.0-changelog.rst:50\nmsgid \"Devin Neal\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:22\nmsgid \"GameDungeon +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:23\n#: ../../source/changelog/0.5.0-changelog.rst:51\nmsgid \"Hugues Devimeux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:24\n#: ../../source/changelog/0.5.0-changelog.rst:52\nmsgid \"Jason Villanueva\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:25\n#: ../../source/changelog/0.5.0-changelog.rst:53\nmsgid \"Kapil Sachdeva\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:26\n#: ../../source/changelog/0.5.0-changelog.rst:54\nmsgid \"KingWampy\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:27\nmsgid \"Lionel Ray +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:28\n#: ../../source/changelog/0.5.0-changelog.rst:57\nmsgid \"Mark Miller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:29\nmsgid \"Mohammad Al-Fetyani +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:30\n#: ../../source/changelog/0.5.0-changelog.rst:59\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:31\nmsgid \"Niklas Dewally +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:32\nmsgid \"Oliver +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:33\nmsgid \"Roopesh +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:34\nmsgid \"Seb Pearce +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:35\nmsgid \"aebkea +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:36\nmsgid \"friedkeenan\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:37\nmsgid \"hydrobeam +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:38\nmsgid \"kolibril13\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:39\nmsgid \"sparshg\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:40\nmsgid \"tfglynn +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:43\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:46\nmsgid \"Abel Aebker\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:49\nmsgid \"Bogdan Stăncescu\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:55\nmsgid \"Leo Torres\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:56\nmsgid \"Lionel Ray\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:58\nmsgid \"Mohammad Al-Fetyani\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:60\nmsgid \"Oliver\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:61\nmsgid \"Ricky Chon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:62\nmsgid \"vector67\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:65\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:67\nmsgid \"A total of 64 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:70\nmsgid \"Highlights\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:73\nmsgid \":pr:`1075`: Add OpenGL Renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:73\nmsgid \"Adds an OpenGLRenderer, OpenGLCamera, OpenGL-enabled Mobjects, and a ``--use_opengl_renderer`` flag. When this flag is passed, you can pass the ``-p`` flag to preview animations, the ``-w`` flag to generate video, and the ``-q`` flag to specify render quality. If you don't pass either the ``-p`` or the ``-w`` flag, nothing will happen. Scenes rendered with the OpenGL renderer must *only* use OpenGL-enabled Mobjects.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:76\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:80\nmsgid \":pr:`1124`: Deprecated :class:`ShowCreation` in favor of :class:`Create`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:79\nmsgid \"Deprecated :class:`ShowCreation` in favor of :class:`Create` across the library with the exception of the `show_creation` boolean variable `vector_space_scene.py`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:80\nmsgid \"Added a deprecation warning in the original :class:`ShowCreation` class.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:83\nmsgid \":pr:`1110`: Deprecated SmallDot + OpenGLSmallDot\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:83\nmsgid \"`SmallDot` isn't necessary and a deprecation warning will be raised. This will be removed in a future release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:86\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:91\nmsgid \":pr:`1037`: Added new fade and transform animations (:class:`~.TransformMatchingShapes`, :class:`~.TransformMatchingTex`, :class:`~.FadeTransform`) from 3b1b/manim\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:89\nmsgid \"Added new Fade animation: :class:`~FadeOutToPoint` Added :class:`~FadeTransform` and :class:`~FadeTransformPieces` for transforming mobjects and submobjects with a fade Added :class:`~TransformMatchingShapes` and :class:`~TransformMatchingTex` for transforming mobjects and tex that have matching parts\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:93\nmsgid \":pr:`1097`: Added 3D Mobject :class:`~.Dot3D`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:96\nmsgid \":pr:`1074`: Added jupyter media_width option to the config\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:100\nmsgid \":pr:`1107`: Added :class:`~.Unwrite` animation class to complement :class:`~.Write`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:100\nmsgid \"Added :class:`Unwrite` which inherits from :class:`~.Write`. It automatically reverses the animation of :class:`~.Write` by passing the reversed rate function, but it also takes an additional boolean parameter `reverse` which, if `False`, renders the animation from left to right (assuming text oriented in the usual way), but if `True`, it renders right to left.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:103\nmsgid \":pr:`1085`: Added :class:`~.Angle` and :class:`~.RightAngle` for intersecting lines\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:103\nmsgid \":class:`~.Angle` and :class:`~.RightAngle` both take two lines as input. If they intersect, or share a common vertex, an angle is drawn between them. Users can customize the look of the angle and also use a dotted right angle.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:106\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:108\nmsgid \":pr:`1144`: Improved quality of GIFs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:114\nmsgid \":pr:`1157`: Refresh triangulation on call to :meth:`~.OpenGLVMobject.apply_points_function`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:112\nmsgid \"Rotate called apply_points_function, which was previous not subclassed by OpenGLMobject - now it is. Then, the vertex normals can be updated too.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:114\nmsgid \"Additionally, the old_points matrix would change after rotating, making the old points / new points test irrelevant. This is addressed with a .copy call.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:116\nmsgid \":pr:`1151`: Added parametric function support to :class:`OpenGLSurface`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:119\nmsgid \":pr:`1139`: In-Code `config[\\\"preview\\\"]` Support\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:123\nmsgid \":pr:`1123`: Added caching, skipping, and user-specified background colors to the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:123\nmsgid \"OpenGL play logic has been improved to support caching and skipping with `-n` argument ( it is now similar to Cairo play logic). A random bug was fixed in OpenGLSurface and OpenGL background color can now be changed via `background_color` argument.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:128\nmsgid \":pr:`1118`: Allow passing animation arguments with .animate syntax\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:126\nmsgid \"Users will now be able to do things like `obj.animate(run_time=2).method(arg)` if they want to specify animation arguments for an individual `.animate` call, and can still not specify any arguments like `obj.animate.method(arg)`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:128\nmsgid \"Passing animation arguments is only allowed directly after `.animate` is accessed, if passed elsewhere then a `ValueError` is raised.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:132\nmsgid \":pr:`718`: Rotating the numbers in y axis\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:131\nmsgid \"In Axes, the y axis will be rotated 90deg but the numbers are also rotated and shouldn't be. Fixes this issue.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:135\nmsgid \":pr:`1070`: Raise FileNotFoundError when unable to locate the .cfg file specified via ``--config_file``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:135\nmsgid \"Raising the error will stop script execution and let the user know that there are problems with the `--config_file` location instead of reverting back to the default configuration.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:138\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:140\nmsgid \":pr:`1224`: Fixed :class:`~.ShowIncreasingSubsets`, :class:`~.ShowSubmobjectsOneByOne`, and :class:`~.AddTextLetterByLetter`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:143\nmsgid \":pr:`1201`: Prevent crash on :meth:`~.Scene.embed` for empty scenes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:146\nmsgid \":pr:`1192`: Fixed issue when an animation is cached, manim can't merge the partial movie files.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:150\nmsgid \":pr:`1193`: Fixed using :class:`~.Animation` without a child :class:`~.Mobject` in :class:`~.AnimationGroup`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:150\nmsgid \"`AnimationGroup` may now take `Animation` objects which do not have a child `Mobject`, such as `Wait`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:152\nmsgid \":pr:`1170`: Fixed minor SVG parsing bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:155\nmsgid \":pr:`1159`: Added support for multiple transforms in the same SVG element\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:159\nmsgid \":pr:`1156`: Fixed :class:`~.DrawBorderThenFill` to support OpenGL and improved type hints for some functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:159\nmsgid \"Fixed a bug in :class:`~.DrawBorderThenFill` that prevented :class:`~.Write` animations from working with :class:`~.OpenGLVMobjects` and slightly improved type hints for some animation functions to include :class:`~.OpenGLVMobject`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:162\nmsgid \":pr:`1134`: Fixed the `-a` flag.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:162\nmsgid \"The ``-a`` / ``--write-all`` flag was broken. When used, it would cause Manim to crash just after beginning to render the second scene.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:165\nmsgid \":pr:`1115`: Fixed bugs in :class:`~.OpenGLMobject` and added :class:`ApplyMethod` support\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:165\nmsgid \"Fixed undefined variables and converted :class:`Mobject` to :class:`OpenGLMobject`. Also, fixed assert statement in :class:`ApplyMethod`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:171\nmsgid \":pr:`1092`: Refactored coordinate_systems.py, fixed bugs, added :class:`~.NumberPlane` test\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:168\nmsgid \"The default behavior of :meth:`~.Mobject.rotate` is to rotate about the center of :class:`~.Mobject`. :class:`~.NumberLine` is symmetric about the point at the number 0 only when ``|x_min|`` == ``|x_max|``. Ideally, the rotation should coincide with the point at number 0 on the line.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:171\nmsgid \"Added a regression test and additionally fixed some bugs introduced in :pr:`718`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:174\nmsgid \":pr:`1078`: Removed stray print statements from `__main__.py`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:174\nmsgid \"Uses rich's print traceback instead and fixes an issue in printing the version twice when `manim --version` is called.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:177\nmsgid \":pr:`1086`: Fixed broken line spacing in :class:`~.Text`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:177\nmsgid \"The `line_spacing` kwarg was missing when creating :class:`Text` Mobjects; this adds it.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:180\nmsgid \":pr:`1083`: Corrected the shape of :class:`~.Torus`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:180\nmsgid \":class:`Torus` draws a surface with an elliptical cross-section when `minor_radius` is different from 1. This PR ensures the cross-section is always a circle.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:183\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:185\nmsgid \":pr:`1217`: Copyedited the document on testing in our documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:188\nmsgid \":pr:`1206`: Added Docstrings to :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:191\nmsgid \":pr:`1218`: Removed BezierSpline from the example gallery\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:194\nmsgid \":pr:`1219`: Updated Dockerfile (include dependencies for building documentation), moved documentation to main README\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:198\nmsgid \":pr:`1209`: Added :ref_methods: to the manim directive\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:198\nmsgid \"This allows class methods to be linked in the documentation. Checkout the `example references <https://docs.manim.community/en/latest/examples.html#movingaround>`_ below the code to see how this is used!\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:200\nmsgid \":pr:`1204`: Added rotation example to example gallery\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:203\nmsgid \":pr:`1137`: Added GitHub Wiki pages on adding testing/documentation to Sphinx Docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:206\nmsgid \":pr:`1114`: Added examples for :class:`~.Ellipse`, :class:`~.Polygon`, :class:`~.RegularPolygon`, :class:`~.Triangle` and :class:`~.RoundedRectangle`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:209\nmsgid \":pr:`1195`: Removed SmallDot from example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:212\nmsgid \":pr:`1130`: Added pre-commit to run black and flake8, updated contributing documentation accordingly\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:216\nmsgid \":pr:`1138`: Moved previous version changelogs to separate files; Added a Script to generate future changelogs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:216\nmsgid \"This script quickly generates a changelog for whoever is making the release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:218\nmsgid \":pr:`1190`: Added note in contributing guide to read the latest version of the documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:221\nmsgid \":pr:`1188`: Added sounds example to docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:224\nmsgid \":pr:`1165`: Added documentation for installing Manim on Colab\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:227\nmsgid \":pr:`1128`: Added examples for :class:`~.DashedLine`, :class:`~.TangentLine`, :class:`~.Elbow`, :class:`~.Arrow`, :class:`~.Vector`, :class:`~.DoubleArrow`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:230\nmsgid \":pr:`1177`: Replace links to the latest version of the documentation to the stable version\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:233\nmsgid \":pr:`1077`: Added details to :func:`~.Mobject.get_critical_point`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:236\nmsgid \":pr:`1154`: Fixed some typing hints. (ints to floats)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:239\nmsgid \":pr:`1036`: Added :class:`~.SurroundingRectangle` to the example gallery\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:242\nmsgid \":pr:`1103`: Added documentation and examples for Square, Dot, Circle and Rectangle\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:245\nmsgid \":pr:`1101`: Added documentation to :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:249\nmsgid \":pr:`1088`: Added new svg files to documentation and imports\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:249\nmsgid \"In particular, SVGPathMobject, VMobjectFromPathstring, and the style_utils functions to manim's namespace.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:252\nmsgid \":pr:`1076`: Improve documentation for GraphScene\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:252\nmsgid \"Updated `coords_to_point` and `point_to_coords` under `manim/scene/graph_scene.py` as the dosctring of each function confusingly described the opposite of what it is supposed to do.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:255\nmsgid \"Changes concerning the testing system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:257\nmsgid \":pr:`1160`: Enable CI testing for OpenGL\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:261\nmsgid \":pr:`1100`: Rewrote test cases to use sys.executable in the command instead of \\\"python\\\"\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:261\nmsgid \"Tests would fail due to `capture()` not spawning a subshell in the correct environment, so when python was called, the test would be unable to find necessary packages.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:263\nmsgid \":pr:`1079`: Removed the hardcoded value, `manim`, in `test_version.py`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:267\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:269\nmsgid \":pr:`1213`: Updated TinyTex dependencies\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:272\nmsgid \":pr:`1187`: Add CodeCov to Github Workflow\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:275\nmsgid \":pr:`1166`: CI: Use poetry's cache dir rather than pip\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:281\nmsgid \":pr:`1071`: Enable pytest-cov based code coverage\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:279\nmsgid \"Include pytest-cov as a python module as part of developer dependencies\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:280\nmsgid \"In updating poetry to include pytest-cov, manimpango moved from version 0.2.3 to 0.2.4, and libpango1.0-dev needed to be installed in Ubuntu.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:281\nmsgid \"Add to the CI workflow (`ci.yml`) to create and upload test coverage.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:283\nmsgid \":pr:`1073`: Removed \\\"one line summary\\\" from PULL_REQUEST_TEMPLATE.md\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:287\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:289\nmsgid \":pr:`1167`: Merge :class:`~.OpenGLMobject` and :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:292\nmsgid \":pr:`1164`: Fixed single PEP8 style in `cairo_renderer.py`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:295\nmsgid \":pr:`1140`: Flake8 Compat & Code Cleanup\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:305\nmsgid \":pr:`1019`: Refactored :meth:`~.Scene.play`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:299\nmsgid \"Removed the _**three**_ decorators of :meth:`~.Scene.play`, in particular: caching logic and file writer logic are now included within :meth:`~.Scene.play` (it wasn't possible before, because `scene.wait` and `scene.play` were two different things).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:300\nmsgid \"Added `is_static_wait` attributes to Wait. (<=> if wait is a frozen frame).\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:301\nmsgid \"Renamed and moved `scene.add_static_frame` to `renderer.freeze_current_frame`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:302\nmsgid \"Now when calling play without animation, it raises `ValueError` instead of just a warning.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:303\nmsgid \"Fixed :pr:`874` by modifying `renderer.update_skipping_status`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:304\nmsgid \"`renderer` starts the animation with `scene.begin_animations` (`scene.compile_animation_data` used to do this)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.5.0-changelog.rst:305\nmsgid \"The run time and the time progression generation is now done in `scene.play_internal` although it'd make more sense that renderer processes it later.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.6.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:3\nmsgid \"v0.6.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:5\nmsgid \"May 02, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:10\nmsgid \"A total of 40 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:14\n#: ../../source/changelog/0.6.0-changelog.rst:47\nmsgid \"Abel Aebker\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:15\n#: ../../source/changelog/0.6.0-changelog.rst:48\nmsgid \"Abhijith Muthyala\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:16\nmsgid \"Adam Ryczkowski +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:17\nmsgid \"Alex Lembcke +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:18\n#: ../../source/changelog/0.6.0-changelog.rst:51\nmsgid \"Anton Ballmaier\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:19\n#: ../../source/changelog/0.6.0-changelog.rst:52\nmsgid \"Aron\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:20\n#: ../../source/changelog/0.6.0-changelog.rst:53\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:21\n#: ../../source/changelog/0.6.0-changelog.rst:54\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:22\nmsgid \"Deniz Hasler +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:23\n#: ../../source/changelog/0.6.0-changelog.rst:56\nmsgid \"Devin Neal\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:24\nmsgid \"Elisha Hollander +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:25\nmsgid \"Erik Tastepe +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:26\n#: ../../source/changelog/0.6.0-changelog.rst:60\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:27\n#: ../../source/changelog/0.6.0-changelog.rst:61\nmsgid \"Jason Villanueva\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:28\n#: ../../source/changelog/0.6.0-changelog.rst:63\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:29\n#: ../../source/changelog/0.6.0-changelog.rst:64\nmsgid \"Mark Miller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:30\n#: ../../source/changelog/0.6.0-changelog.rst:65\nmsgid \"Mohammad Al-Fetyani\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:31\n#: ../../source/changelog/0.6.0-changelog.rst:66\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:32\nmsgid \"Newell Jensen +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:33\nmsgid \"Nidhal Baccouri +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:34\nmsgid \"Nikhil Garuda +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:35\nmsgid \"Peilonrayz +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:36\n#: ../../source/changelog/0.6.0-changelog.rst:71\nmsgid \"Raghav Goel\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:37\nmsgid \"Ricky Chon +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:38\n#: ../../source/changelog/0.6.0-changelog.rst:73\nmsgid \"friedkeenan\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:39\nmsgid \"kamilczerwinski22 +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:40\n#: ../../source/changelog/0.6.0-changelog.rst:74\nmsgid \"sparshg\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:43\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:46\nmsgid \"Aathish Sivasubrahmanian\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:49\nmsgid \"Adam Ryczkowski\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:50\nmsgid \"Alex Lembcke\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:55\nmsgid \"Deniz Hasler\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:57\nmsgid \"Elisha Hollander\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:58\nmsgid \"GameDungeon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:59\nmsgid \"Hugues Devimeux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:62\nmsgid \"KingWampy\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:67\nmsgid \"Nidhal Baccouri\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:68\nmsgid \"Nikhil Garuda\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:69\nmsgid \"Oliver\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:70\nmsgid \"Philipp Imhof\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:72\nmsgid \"Ricky Chon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:77\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:79\nmsgid \"A total of 112 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:82\nmsgid \"Breaking changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:85\nmsgid \":pr:`1347`: Restructure vector_field module and add documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:85\nmsgid \":class`~.VectorField` is renamed to :class:`~.ArrowVectorField` and a new class :class:`~.VectorField` is added as a superclass for :class:`~.ArrowVectorField` and :class:`~.StreamLines`. :class:`~.AnimatedStreamLines` is removed. It's functionality is moved to :class:`~.StreamLines`. Added a lot of new options when working with vector fields. :class:`~.ShowPassingFlashWithThinningStrokeWidth` was moved to the indication module.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:91\nmsgid \":pr:`1161`: Upgrades to CoordinateSystem and graphing.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:88\nmsgid \"Breaking changes were introduced to :class:`~.Axes`, :class:`~.ThreeDAxes`, :class:`~.NumberPlane` and :class:`~.NumberLine` All the above now use lists to construct their ranges as opposed to explicitly defining these values. `x_range` has replaced `x_min`, `x_max` and defining the step is much easier with `x_step` --> ``x_range``  :  ``[x_min, x_max, x_step]``. There were also many upgrades to these classes which improve their functionality and appearance.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:91\nmsgid \"``NumberLineOld`` was introduced to continue support for :class:`~.GraphScene`, although we are moving away from GraphScene and intend to deprecate it in a future release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:107\nmsgid \":pr:`1013`: Refactored the Command Line Interface to use Click instead of Argparse\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:94\nmsgid \"This change breaks the CLI API to organize the structure of Manim Community's commands, options, and arguments.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:96\nmsgid \"To be more in line with POSIX compliant CLI conventions, options for commands are given *BEFORE* their arguments. In Argparse: ``manim basic.py -p -ql`` With Click: ``manim -p -ql basic.py``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:100\nmsgid \"Although this is primarily a refactor and most of the common options are still there, some options have been added/removed. Use the ``manim`` command's ``--help`` option, or simply run the command without providing options/arguments to view the help page with the full list of subcommands/options/arguments.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:102\nmsgid \"Added a ``--fps``/``--frame_rate`` option which allows for custom fps that don't have to be integer (i.e. 29.97, 23.98, etc.). Users no longer have to specify the FPS from within a config file. Additionally, the ``--webgl_renderer_fps`` option has been removed. Use ``--fps`` or ``--frame_rate`` instead.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:103\nmsgid \"Added a ``--renderer`` option which you can use to select your choice of renderer (e.g. ``--renderer=opengl``). There are currently *THREE* renderers to choose from!\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:104\nmsgid \"Removed the ``--background_color`` option. Reassigned the ``--background_color`` option's shorthand ``-c`` to ``--config_file``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:105\nmsgid \"Removed the ``--leave_progress_bars`` option. Use ``--progress_bars=leave`` instead.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:106\nmsgid \"Removed the deprecated render quality flags, in particular: ``-l``, ``-m``, ``-h``, ``-k``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:107\nmsgid \"Removed the ``--sound`` option. It lost support long ago with the removal of SoX.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:110\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:116\nmsgid \":pr:`1431`: Fix CLI bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:113\nmsgid \"Fixed conflict with ``-f`` which was previously assigned to both ``--show_in_file_browser`` and ``--format`` by removing ``-f`` from ``--format``. A warning is issued that ``-f`` will soon move to ``--format``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:114\nmsgid \"Added back in flags to render the files as gif/last frame. Deprecated them in favor of ``--format``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:115\nmsgid \"Fixed the broken ``--output_file``/``-o`` option.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:116\nmsgid \"Fixed an issue where the ``-qh`` quality option was interpreted as ``-q`` ``-h``, prompting the help page.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:118\nmsgid \":pr:`1354`: Refactored a few functions in space_ops.py, deprecated :func:`~.angle_between`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:122\nmsgid \":pr:`1370`: Remove TexMobject and TextMobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:122\nmsgid \"TexMobject and TextMobject have been deprecated for a while, they are now fully removed. Use Tex or MathTex instead.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:124\nmsgid \":pr:`1349`: Removed the deprecated ``SmallDot`` mobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:127\nmsgid \":pr:`1259`: Removed deprecated CairoText class\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:130\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:132\nmsgid \":pr:`1386`: Implement utility methods for adding/removing vertices and edges of graphs; allow custom mobjects as vertices\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:136\nmsgid \":pr:`1385`: Added :meth:`~.Axes.get_line_graph` for plotting a line graph\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:136\nmsgid \"Added :meth:`~.Axes.get_line_graph` that returns a line graph from lists of points along x, y and z (optional) axes.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:139\nmsgid \":pr:`1381`: Hot reloading for the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:139\nmsgid \"Rerun scene when the input file is modified\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:148\nmsgid \":pr:`1383`: Overhaul of the :mod:`~.animation.indication` module interfaces\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:142\nmsgid \"Added class `Circumscribe` combining functionality of `CircleIndicate`, `AnimationOnSurroundingRectangle`, `ShowPassingFlashAround`, `ShowCreationThenDestructionAround`, `ShowCreationThenFadeAround`, which have all been deprecated.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:143\nmsgid \"Changes to `Flash`: `flash_radius` parameter now defines inner radius of the animation. Added new parameter `time_width`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:144\nmsgid \"`ShowCreationThenDestruction` has been deprecated in favor of `ShowPassingFlash`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:145\nmsgid \"Changes to `ApplyWave`: New implementation giving more flexibility with new parameters `wave_func`, `time_width` and`ripples`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:146\nmsgid \"Renamed `WiggleOutThenIn` to `Wiggle` (`WiggleOutThenIn` has been deprecated)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:147\nmsgid \"Added documentation and examples to all the above\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:148\nmsgid \"Other minor enhancements and bug-fixes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:150\nmsgid \":pr:`1348`: Added :class:`~.Polyhedron`, and platonic solids :class:`~.Tetrahedron`, :class:`~.Octahedron`, :class:`~.Icosahedron` and :class:`~.Dodecahedron`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:154\nmsgid \":pr:`1285`: Add :meth:`~.Scene.interactive_embed` for OpenGL rendering\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:154\nmsgid \":meth:`~.Scene.interactive_embed` allows interaction with Scene via mouse and keyboard as well as dynamic commands via an iPython terminal.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:157\nmsgid \":pr:`1261`: Render image automatically if no animation is played in a scene\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:157\nmsgid \"If no animations in scene and asked to preview/render a video, preview/render an image instead of raising a confusing error.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:160\nmsgid \":pr:`1200`: Add text and SVG mobjects to OpenGL\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:160\nmsgid \"Added OpenGL-compatible text and SVG mobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:163\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:166\nmsgid \":pr:`1398`: Fix and enhance `Mobject.arrange_in_grid`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:166\nmsgid \"`arrange_in_grid` now actually arranges submobjects in a grid. Added new parameters `buff`, `cell_alignment`, `row_alignments`, `col_alignments`, `row_heights`, `col_widths`, `flow_order`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:168\nmsgid \":pr:`1407`: Fix bug and rename :meth:`vector_coordinate_label` to :meth:`~.Vector.coordinate_label` and move it to :class:`geometry.py`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:171\nmsgid \":pr:`1380`: Allow image objects as background images\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:175\nmsgid \":pr:`1391`: Add `path_arc` support to `.animate` syntax\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:175\nmsgid \"The parameter `path_arc` of :class:`~.Transform` now works with the `.animate` syntax\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:178\nmsgid \":pr:`1364`: Added :meth:`~.Mobject.match_points`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:178\nmsgid \"Added :func:`~.Mobject.match_points`, which transforms the points, positions and submobjects of a Mobject to match that of the other while keeping style unchanged.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:180\nmsgid \":pr:`1363`: Change of TeX compiler and output file format\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:184\nmsgid \":pr:`1359`: Make FILE a required argument\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:184\nmsgid \"Make `FILE` a required argument, `manim/cli/render/commands.py`:L30\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:186\nmsgid \":pr:`1304`: Improve Tex string splitting at double braces: only split for double brace groups\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:190\nmsgid \":pr:`1340`: Add OpenGL support to the new transform animations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:190\nmsgid \"Made `FadeTransform`, `FadeTransformPieces`, `TransformMatchingShapes` and `TransformMatchingTex` compatible with OpenGL rendering.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:193\nmsgid \":pr:`1343`: Make TexTemplate() simple, but keep Tex()'s default template\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:193\nmsgid \"TexTemplate() now returns a simple tex template.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:195\nmsgid \":pr:`1321`: Add OpenGL support to :class:`~.AnimationGroup`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:200\nmsgid \":pr:`1302`: Raise appropriate errors in :meth:`~.VMobject.point_from_proportion`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:199\nmsgid \"Raise an error if the ``alpha`` argument is not between 0 and 1.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:200\nmsgid \"Raise an error if the :class:`~.VMobject` has no points.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:202\nmsgid \":pr:`1315`: Fix performance issues with :meth:`~.VMobject.get_arc_length`, stemming from :pr:`1274`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:205\nmsgid \":pr:`1320`: Add `jpeg` extension to the default image extensions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:209\nmsgid \":pr:`1234`: Added new method :meth:`~.Mobject.get_midpoint`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:209\nmsgid \"Implemented :meth:`~.Mobject.get_midpoint` to return the point that is the middle of the stroke line of an mobject.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:211\nmsgid \":pr:`1237`: Notify user if they are using an outdated version of Manim\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:214\nmsgid \":pr:`1308`: Improved :class:`~.ManimBanner` animations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:217\nmsgid \":pr:`1275`: Add SVG <line> element support to :class:`~.SVGMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:220\nmsgid \":pr:`1238`: Add parameter ``about_point`` for :meth:`~.Mobject.rotate`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:223\nmsgid \":pr:`1260`: Change Brace from Tex to SVG (#1258)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:226\nmsgid \":pr:`1122`: Support for specifying the interpolation algorithms for individual ImageMobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:229\nmsgid \":pr:`1283`: Set default value of keyword ``random_seed`` in :class:`~.Scene` to ``None`` (was 0 and fixed before)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:236\nmsgid \":pr:`1220`: Added sanity checks to :meth:`~.Mobject.add_to_back` for Mobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:233\nmsgid \"Add Mobject `add_to_back` sanity checks: - Raises ValueError when Mobject tries to add itself - Raises TypeError when a non-Mobject is added - Filters out incoming duplicate submobjects if at least one instance of that submobject exists in the list\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:239\nmsgid \":pr:`1249`: Set corners of :class:`~.Rectangle` in counterclockwise direction\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:239\nmsgid \"This improves the look of transformations between rectangles and other simple mobjects.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:241\nmsgid \":pr:`1248`: Add Copy function to TexTemplate\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:245\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:247\nmsgid \":pr:`1368`: Added a check to ensure checking for the latest version was successful\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:251\nmsgid \":pr:`1413`: Prevent duplication of the same mobject when adding to submobjects via :meth:`~.Mobject.add_to_back`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:251\nmsgid \"Fixes #1412\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:253\nmsgid \":pr:`1395`: SVG transforms now handle exponent notation (6.02e23)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:256\nmsgid \":pr:`1355`: Rewrite `put_start_and_end_on` to work in 3D\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:259\nmsgid \":pr:`1346`: Fixed errors introduced by stray print in :class:`~.MathTex`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:262\nmsgid \":pr:`1305`: Automatically remove long tick marks not within the range of the :class:`~NumberLine`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:265\nmsgid \":pr:`1296`: Fix random pipeline TeX failures\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:270\nmsgid \":pr:`1274`: Fix :meth:`~.VMobject.point_from_proportion` to account for the length of curves.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:269\nmsgid \"Add :meth:`~.VMobject.get_nth_curve_function_with_length` and associated functions.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:270\nmsgid \"Change :meth:`~.VMobject.point_from_proportion` to use these functions to account for curve length.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:273\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:277\nmsgid \":pr:`1430`: Un-deprecated GraphScene (will be deprecated later), fixed an old-style call to NumberPlane\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:276\nmsgid \"More work is required in order to fully replace `GraphScene` via `Axes`, thus `GraphScene` is not deprecated yet.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:277\nmsgid \"Fixed one example in which the old `NumberPlane` syntax was used.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:279\nmsgid \":pr:`1425`: Added a \\\"How to Cite Manim\\\" section to the Readme\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:283\nmsgid \":pr:`1387`: Added Guide to Contribute Examples from GitHub Wiki to Documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:283\nmsgid \"Added a Guide\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:285\nmsgid \":pr:`1424`: Fixed all current docbuild warnings\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:288\nmsgid \":pr:`1389`: Adding Admonitions Tutorial to docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:291\nmsgid \":pr:`1341`: Reduce complexity of ThreeDSurfacePlot example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:294\nmsgid \":pr:`1362`: Quick reference to modules\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:298\nmsgid \":pr:`1376`: Add flake8 and isort in docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:298\nmsgid \"added 'flake8' and 'isort' usages to docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:301\nmsgid \":pr:`1360`: Grammatical error corrections in documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:301\nmsgid \"changed a few sentences in docs/source\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:303\nmsgid \":pr:`1351`: Some more typehints\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:306\nmsgid \":pr:`1358`: Fixed link to installation instructions for developers\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:309\nmsgid \":pr:`1338`: Added documentation guidelines for type hints\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:312\nmsgid \":pr:`1342`: Multiple ValueTracker example for docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:315\nmsgid \":pr:`1210`: Added tutorial chapter on coordinates of an mobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:318\nmsgid \":pr:`1335`: Added import statements to examples in documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:321\nmsgid \":pr:`1245`: Added filled angle Example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:324\nmsgid \":pr:`1328`: Docs: Update Brace example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:327\nmsgid \":pr:`1326`: Improve documentation of :class:`~.ManimMagic` (in particular: fix documented order of CLI flags)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:330\nmsgid \":pr:`1323`: Blacken Docs Strings\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:333\nmsgid \":pr:`1300`: Added typehints for :class:`~.ValueTracker`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:336\nmsgid \":pr:`1301`: Added further docstrings and typehints to :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:339\nmsgid \":pr:`1298`: Add double backquotes for rst code samples (value_tracker.py)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:343\nmsgid \":pr:`1297`: Change docs to use viewcode extension instead of linkcode\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:343\nmsgid \"Switched ``sphinx.ext.linkcode`` to ``sphinx.ext.viewcode`` and removed ``linkcode_resolve`` in ``conf.py``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:345\nmsgid \":pr:`1246`: Added docstrings for :class:`~.ValueTracker`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:348\nmsgid \":pr:`1251`: Switch documentation from guzzle-sphinx-theme to furo\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:351\nmsgid \":pr:`1232`: Further docstrings and examples for :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:354\nmsgid \":pr:`1291`: Grammar improvements in README.md\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:357\nmsgid \":pr:`1269`: Add documentation about :meth:`~.set_color_by_tex`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:360\nmsgid \":pr:`1284`: Updated readme by providing the correct link to the example_scenes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:363\nmsgid \":pr:`1029`: Added example jupyter notebook into the examples folders\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:367\nmsgid \":pr:`1279`: Added sphinx requirements to pyproject.toml\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:367\nmsgid \"New contributors who wanted to build the sphinx documentation had an extra step that could be removed by making use of ``poetry install``. This removes the developer's need for ``pip install -r requirements.txt``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:369\nmsgid \":pr:`1268`: Added documentation explaining the differences between manim versions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:372\nmsgid \":pr:`1247`: Added warning for the usage of `animate`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:375\nmsgid \":pr:`1242`: Added an example for the manim colormap\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:378\nmsgid \":pr:`1239`: Add TinyTex installation instructions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:381\nmsgid \":pr:`1231`: Improve changelog generation script\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:385\nmsgid \"Changes concerning the testing system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:387\nmsgid \":pr:`1299`: Red pixels (different value) now appear over green pixels (same value) in GraphicalUnitTest\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:391\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:394\nmsgid \":pr:`1436`: Cache poetry venv with `pyproject.toml` hash in key\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:394\nmsgid \"Cache poetry venv with `pyproject.toml` hash in key\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:397\nmsgid \":pr:`1435`: CI: Update poetry cache when new version is released\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:397\nmsgid \"Fix `test_version` failure in CI when using cached poetry venv\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:399\nmsgid \":pr:`1427`: Add URL's to pyproject.toml\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:402\nmsgid \":pr:`1421`: Updated changelog generator's labels and removed pre-commit bot from changelog\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:405\nmsgid \":pr:`1339`: CI: Fix macOS installation error from creating file in read-only file system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:409\nmsgid \":pr:`1257`: CI: Caching ffmpeg, tinytex dependencies and poetry venv\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:409\nmsgid \"CI: Caching ffmpeg, tinytex dependencies and poetry venv\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:411\nmsgid \":pr:`1294`: Added mixed-line-ending to .pre-commit-config.yaml\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:414\nmsgid \":pr:`1278`: Fixed flake8 errors and removed linter/formatter workflows\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:417\nmsgid \":pr:`1270`: Added isort to pre_commit file\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:422\nmsgid \":pr:`1263`: CI: Turn off experimental installer for poetry to fix installation errors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:421\nmsgid \"Turn off experimental installer for poetry to prevent manim installation errors for packages.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:422\nmsgid \"Downgrade py39 to py38 for flake checks as `pip` does not enjoy py39, along with `poetry`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:425\nmsgid \":pr:`1255`: CI: Fix macOS pipeline failure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:425\nmsgid \"Update `ci.yml` to update and upgrade brew if necessary before installing dependencies, and remove the unsupported `dvisvgm.86_64-darwin` package.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:427\nmsgid \":pr:`1254`: Removed the comment warning that GitHub doesn't allow uploading video in the issue templates.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:430\nmsgid \":pr:`1216`: Use actions/checkout for cloning repository; black-checks\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:433\nmsgid \":pr:`1235`: Fixed version of decorator at <5.0.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:437\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:439\nmsgid \":pr:`1411`: Change `Union[float, int]` to just `float` according to PEP 484\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:442\nmsgid \":pr:`1241`: Type Annotations: Fixing errors showing up in static type checking tool mypy\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:446\nmsgid \":pr:`1319`: Fix mean/meant typo\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:446\nmsgid \"Fix typo in docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:448\nmsgid \":pr:`1313`: Singular typo fix on the Quickstart page in documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:452\nmsgid \":pr:`1292`: Remove unnecessary imports from files\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:452\nmsgid \"Imports reduced in a bunch of files\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:454\nmsgid \":pr:`1295`: Fix grammar and typos in the CODE OF CONDUCT\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:458\nmsgid \":pr:`1293`: Minor fixes - reduce lines\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:458\nmsgid \"Remove unnecessary lines\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:460\nmsgid \":pr:`1281`: Remove all Carriage Return characters in our files\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:463\nmsgid \":pr:`1178`: Format Imports using Isort\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:466\nmsgid \":pr:`1233`: Fix deprecation warning for ``--use_opengl_renderer`` and ``--use_webgl_renderer``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:469\nmsgid \":pr:`1282`: Fix typing hints in vectorized_mobject.py based on mypy\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.6.0-changelog.rst:473\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.7.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:3\nmsgid \"v0.7.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:5\nmsgid \"June 01, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:10\nmsgid \"A total of 45 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:14\nmsgid \"André +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:15\n#: ../../source/changelog/0.7.0-changelog.rst:53\nmsgid \"Anton Ballmaier\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:16\n#: ../../source/changelog/0.7.0-changelog.rst:55\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:17\nmsgid \"Clar Fon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:18\n#: ../../source/changelog/0.7.0-changelog.rst:56\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:19\n#: ../../source/changelog/0.7.0-changelog.rst:57\nmsgid \"Devin Neal\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:20\n#: ../../source/changelog/0.7.0-changelog.rst:59\nmsgid \"Hugues Devimeux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:21\nmsgid \"Iced-Tea3 +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:22\n#: ../../source/changelog/0.7.0-changelog.rst:61\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:23\n#: ../../source/changelog/0.7.0-changelog.rst:62\nmsgid \"Jason Villanueva\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:24\nmsgid \"Jerónimo Squartini +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:25\n#: ../../source/changelog/0.7.0-changelog.rst:64\nmsgid \"KingWampy\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:26\n#: ../../source/changelog/0.7.0-changelog.rst:65\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:27\nmsgid \"Max Stoumen +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:28\n#: ../../source/changelog/0.7.0-changelog.rst:67\nmsgid \"Mohammad Al-Fetyani\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:29\n#: ../../source/changelog/0.7.0-changelog.rst:68\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:30\nmsgid \"NeoPlato\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:31\nmsgid \"Newell Jensen\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:32\n#: ../../source/changelog/0.7.0-changelog.rst:69\nmsgid \"Nikhil Garuda\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:33\nmsgid \"Nikhil Sharma +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:34\nmsgid \"PaulCMurdoch +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:35\n#: ../../source/changelog/0.7.0-changelog.rst:71\nmsgid \"Philipp Imhof\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:36\n#: ../../source/changelog/0.7.0-changelog.rst:72\nmsgid \"Raghav Goel\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:37\nmsgid \"Robert West +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:38\nmsgid \"Ryan McCauley +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:39\nmsgid \"Skaft +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:40\nmsgid \"SwiddisZwei +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:41\nmsgid \"e4coder +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:42\n#: ../../source/changelog/0.7.0-changelog.rst:78\nmsgid \"friedkeenan\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:43\nmsgid \"malte-v +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:44\n#: ../../source/changelog/0.7.0-changelog.rst:79\nmsgid \"ralphieraccoon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:45\n#: ../../source/changelog/0.7.0-changelog.rst:80\nmsgid \"sparshg\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:48\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:51\nmsgid \"Aathish Sivasubrahmanian\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:52\nmsgid \"Abhijith Muthyala\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:54\nmsgid \"Aron\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:58\nmsgid \"GameDungeon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:60\nmsgid \"Iced-Tea3\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:63\nmsgid \"Jerónimo Squartini\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:66\nmsgid \"Mark Miller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:70\nmsgid \"Oliver\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:73\nmsgid \"Ricky Chon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:74\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:75\nmsgid \"Skaft\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:76\nmsgid \"SwiddisZwei\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:77\nmsgid \"e4coder\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:83\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:85\nmsgid \"A total of 87 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:88\nmsgid \"Breaking changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:92\nmsgid \":pr:`1521`: Improve :class:`~.Animation` docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:91\nmsgid \"Improve documentation of the :class:`~.Animation` class.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:92\nmsgid \"Unify the signature of ``get_all_mobjects``. Now it always returns a sequence of :class:`Mobjects <.Mobject>`. This breaks using  ``FadeTransform.get_all_mobjects`` as ``Group``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:95\nmsgid \":pr:`1470`: Drop support for Python 3.6\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:95\nmsgid \"Manim won't work on Python 3.6 anymore.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:98\nmsgid \"Highlights\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:100\nmsgid \":pr:`1447`: Added :class:`~.PolarPlane` for polar coordinates.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:109\nmsgid \":pr:`1490`: Added :class:`~.Polygram`, rework the polygon inheritance tree, and add :class:`~.Star`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:104\nmsgid \"Add :class:`~.Polygram`, a generalized :class:`~.Polygon` that allows for disconnected sets of edges.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:105\nmsgid \"Make :class:`~.Polygon` inherit from :class:`~.Polygram`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:106\nmsgid \"Add :func:`~.regular_vertices`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:107\nmsgid \"Add :class:`~.RegularPolygram`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:108\nmsgid \"Make :class:`~.RegularPolygon` inherit from :class:`~.RegularPolygram`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:109\nmsgid \"Add :class:`~.Star`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:112\nmsgid \":pr:`1462`: OpenGL: Added :class:`~.Shader`, :class:`~.Mesh`, and :class:`~.FullScreenQuad`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:112\nmsgid \"Add Shader and Mesh objects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:117\nmsgid \":pr:`1418`: Added project management commands\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:115\nmsgid \"``manim init`` - quickly sets up default files for a manim project.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:116\nmsgid \"``manim new project`` - lets the user set project settings. It also creates the project inside a new folder of name <project_name>\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:117\nmsgid \"``manim new scene`` - used to quickly insert new scenes into files. If ``file name`` is not provided ``main.py`` is used as default.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:120\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:123\nmsgid \":pr:`1598`: Update examples to use :class:`~.Axes` and deprecate :class:`~.GraphScene`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:123\nmsgid \":class:`~.GraphScene` has been deprecated and its functionality has been shifted to :class:`~.Axes`. See the updated example gallery for sample usage.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:126\nmsgid \":pr:`1454`: Fading module enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:126\nmsgid \"Moved functionality of all Fading classes to :class:`~.FadeIn` and :class:`~.FadeOut`. All other fading classes have been deprecated.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:128\nmsgid \":pr:`1375`: Deleted the deprecated ``ShowCreation`` in favor of :class:`~.Create`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:132\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:134\nmsgid \":pr:`1566`: Added the ability to add gridlines to a :class:`~.Rectangle`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:137\nmsgid \":pr:`1548`: Added :class:`~.ArcBrace`, a subclass of :class:`~.Brace`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:141\nmsgid \":pr:`1559`: Update VGroup to support item assignment (#1530)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:141\nmsgid \"Support indexed item-assignment for VGroup\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:143\nmsgid \":pr:`1518`: Allow fading multiple Mobjects in one Animation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:146\nmsgid \":pr:`1422`: Added :func:`~.override_animation` decorator\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:154\nmsgid \":pr:`1504`: Color module enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:150\nmsgid \"Replaced ``BLUE_E`` with what was previously ``DARK_BLUE`` and removed ``DARK_BLUE``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:151\nmsgid \"Added alias ``LIGHTER_GRAY`` for ``GRAY_A``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:152\nmsgid \"Added ``PURE_RED``, ``PURE_BLUE`` and renamed ``GREEN_SCREEN`` to ``PURE_GREEN``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:153\nmsgid \"All gray colors are now also available using British spelling (including ``GREY_BROWN``)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:154\nmsgid \"Replaced color example in the docs. It can now be used as a quick reference for all color names.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:156\nmsgid \":pr:`1272`: Implement metaclass approach in geometry module to make mobjects compatible with cairo and opengl rendering\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:160\nmsgid \":pr:`1404`: Added two deprecation decorators\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:160\nmsgid \"Added two function decorators ``deprecated`` and ``deprecated_params`` as a consistent way of deprecating code.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:163\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:165\nmsgid \":pr:`1572`: OpenGL compatibility via metaclass: :class:`~.TracedPath`, :class:`~.ParametricFunction`, :class:`~.Brace`, :class:`~.VGroup`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:168\nmsgid \":pr:`1472`: Porting methods from :class:`~.GraphScene` to :class:`~.CoordinateSystem`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:171\nmsgid \":pr:`1589`: OpenGL compatibility via metaclass: :class:`~.ValueTracker`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:175\nmsgid \":pr:`1564`: Add extra notes for TeX compilation errors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:175\nmsgid \"Add hint to use custom ``TexTemplate`` on TeX compilation errors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:177\nmsgid \":pr:`1584`: Added a check for ``0`` in :meth:`~.round_corners`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:181\nmsgid \":pr:`1586`: Add OpenGLMobject support to all ``isinstance`` occurrences\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:181\nmsgid \"This PR increases the support for OpenGL in the remaining animation classes and in other places where appropriate.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:183\nmsgid \":pr:`1577`: Added new metaclass ConvertToOpenGL (replacing MetaVMobject), restore IntelliSense\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:187\nmsgid \":pr:`1562`: Improved VectorField's Nudge Accuracy Per Step\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:187\nmsgid \"Implemented the Runge-Kutta algorithm in VectorField's nudge function. This increases the accuracy as an object moves along a vector field. This also increases efficiency as the nudge function requires less loops to achieve accuracy than the previous implementation.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:189\nmsgid \":pr:`1480`: Add logging info to tex errors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:194\nmsgid \":pr:`1567`: Compatibility Fixes with ManimPango v0.3.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:193\nmsgid \"ManimPango v0.3.0+ is required for Manim now.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:194\nmsgid \"Show errors from Pango when Markup isn't correct\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:196\nmsgid \":pr:`1512`: OpenGL compatibility via metaclass: graph\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:199\nmsgid \":pr:`1511`: OpenGL compatibility via metaclass: svg_mobject, text_mobject, tex_mobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:202\nmsgid \":pr:`1502`: Added ``center`` parameter to :class:`~.Sphere` and ``point`` parameter to :class:`~.Dot3D`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:206\nmsgid \":pr:`1486`: Update of ``rate_functions``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:206\nmsgid \"Changed the picture for the non standard rate functions.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:208\nmsgid \":pr:`1495`: Ported value_tracker to OpenGL\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:212\nmsgid \":pr:`1382`: Expand documentation, testing, and functionality of ValueTrackers; remove ExponentialValueTracker\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:212\nmsgid \"Added more documentation and inline operators to ValueTracker and ComplexValueTracker. Brought coverage for value_tracker.py to 100%. Removed ExponentialValueTracker.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:214\nmsgid \":pr:`1475`: Add SVG elliptical arc support\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:218\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:220\nmsgid \":pr:`1574`: Fixed error when processing SVG with omitted elliptical arc command\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:226\nmsgid \":pr:`1596`: Fix indexing for non-whitespace tex arg separator\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:224\nmsgid \"Fixes #1568\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:226\nmsgid \"Fix issue when setting the arg_separator of a Tex object as a non-whitespace character(s). The method `break_up_by_substrings(self)` was not accounting for the separator when setting the index.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:228\nmsgid \":pr:`1588`: Fixed multiple animations being saved in the same file\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:231\nmsgid \":pr:`1571`: Fix tests after introducing parallelization\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:234\nmsgid \":pr:`1545`: Fix outdated parameters for :class:`LinearTransformationScene` and add an example + typing.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:239\nmsgid \":pr:`1513`: Fixed rotation of gradients while rotating a VMobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:238\nmsgid \"Fixed the direction of gradient which remained the same while rotating VMobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:239\nmsgid \"Added ``rotate_sheen_direction()`` method in VMobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:241\nmsgid \":pr:`1570`: Output errors to stderr\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:244\nmsgid \":pr:`1560`: Declare ``*.npz`` ``*.wav`` ``*.png`` as binary in ``.gitattributes``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:248\nmsgid \":pr:`1211`: Refactored scene caching and fixed issue when a different hash was produced when copying a mobject in the scene\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:248\nmsgid \"Refactored internal scene-caching mechanism and fixed bug when an inconsistent hash was produced when copying a mobject.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:250\nmsgid \":pr:`1527`: Improved handling of substring isolation within sqrt, and fixed a bug with transform_mismatch for the matching shape transforms\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:253\nmsgid \":pr:`1526`: Fix fading\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:256\nmsgid \":pr:`1523`: Fix multiple FadeIn / Out only working on VMobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:260\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:262\nmsgid \":pr:`1599`: Added example for :class:`~.Annulus`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:265\nmsgid \":pr:`1415`: New example for gallery and some docs refinements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:271\nmsgid \":pr:`1509`: Copyedited Documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:269\nmsgid \"Added a link to Manim Community GitHub page in ``for_dev.rst``. Fixed :meth:`~.Mobject.get_start`  and added ``roll`` link in ``building_blocks-rst`` Added language to code blocks in ``configuration.rst``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:274\nmsgid \":pr:`1384`: Added typings to space_ops.py\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:274\nmsgid \"Added Typehints to most of the functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:276\nmsgid \":pr:`1500`: Example for :meth:`~.apply_complex_function`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:279\nmsgid \":pr:`1551`: Fixed the typo for Admonitions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:282\nmsgid \":pr:`1550`: Restructuring of Contribution Section\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:285\nmsgid \":pr:`1541`: Fixing broken links and other minor doc things\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:288\nmsgid \":pr:`1516`: Update docs to use ``t_range`` instead of ``t_min`` and ``t_max`` in :class:`~.ParametricFunction`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:291\nmsgid \":pr:`1508`: Update troubleshooting docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:294\nmsgid \":pr:`1485`: Added :class:`~.Title` example for the docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:297\nmsgid \":pr:`1439`: Cleaning ``Sequence`` typehints\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:300\nmsgid \":pr:`1440`: Added Scoop installation docs (Windows)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:303\nmsgid \":pr:`1452`: Refine typehints at :class:`~.Angle`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:306\nmsgid \":pr:`1458`: Refine docs of :class:`~.Text` ( add ``disable_ligatures=True`` for t2c)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:309\nmsgid \":pr:`1449`: Added :class:`~.PointCloudDot` example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:312\nmsgid \":pr:`1473`: Added easy example for :meth:`~.arrange_in_grid`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:315\nmsgid \":pr:`1402`: Added typestring parser checker\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:318\nmsgid \":pr:`1451`: Reduce complexity of AngleExample\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:322\nmsgid \":pr:`1441`: Add inheritance diagrams to reference page\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:322\nmsgid \"Added inheritance diagrams to the reference page as a quick navigation method.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:324\nmsgid \":pr:`1457`: Fixing broken doc links\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:327\nmsgid \":pr:`1445`: Remove $ from tutorial commands\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:331\nmsgid \"Changes concerning the testing system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:333\nmsgid \":pr:`1556`: Try pytest-xdist for parallelization in tests\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:337\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:340\nmsgid \":pr:`1505`: Add docs reference to PR template\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:340\nmsgid \"Added documentation link to the Pull Request Template.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:342\nmsgid \":pr:`1499`: Updated Discord links in the docs to point towards a standardized redirect\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:345\nmsgid \":pr:`1461`: Build the docs - Logging\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:348\nmsgid \":pr:`1481`: pyproject.toml: poetry_core -> poetry-core\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:351\nmsgid \":pr:`1477`: Update RDT sphinx package to version 3.5.3\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:354\nmsgid \":pr:`1460`: Create CONTRIBUTING.md\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:358\nmsgid \":pr:`1453`: manim_directive: fix image links in docs - Windows\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:358\nmsgid \"Use POSIX path on Windows to link images so documentation can build locally.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:361\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:363\nmsgid \":pr:`1465`: Added typings and description to some functions in :mod:`~.coordinate_systems`.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:367\nmsgid \":pr:`1552`: Removed unwanted parameters in geometry\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:367\nmsgid \"Removed ``anchors_span_full_range``, ``close_new_points``, ``anchors_span_full_range``, ``preserve_tip_size_when_scaling``, ``mark_paths_closed`` and ``close_new_points``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:369\nmsgid \":pr:`1597`: Removed hilite_me and insert_line_numbers_in_html from global name space\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:372\nmsgid \":pr:`1535`: Update dependencies and fix tests\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:375\nmsgid \":pr:`1544`: Adding spell checker as a pre-commit hook\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:378\nmsgid \":pr:`1542`: Swapping a pango markup link in docs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:381\nmsgid \":pr:`1531`: Don't use deprecated methods in deprecation.py\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:384\nmsgid \":pr:`1492`: Remove stray print statements introduced in #1404\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:387\nmsgid \":pr:`1471`: Fix Some Warnings from lgtm\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:391\nmsgid \"Changes that needed to be reverted again\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:393\nmsgid \":pr:`1606`: Bring back ``DARK_BLUE``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.7.0-changelog.rst:397\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.8.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:3\nmsgid \"v0.8.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:5\nmsgid \"July 02, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:10\nmsgid \"A total of 37 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:14\n#: ../../source/changelog/0.8.0-changelog.rst:51\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:15\nmsgid \"Bill Shillito +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:16\nmsgid \"Darigov Research +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:17\n#: ../../source/changelog/0.8.0-changelog.rst:53\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:18\n#: ../../source/changelog/0.8.0-changelog.rst:54\nmsgid \"Devin Neal\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:19\nmsgid \"Iced-Tea3\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:20\n#: ../../source/changelog/0.8.0-changelog.rst:55\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:21\n#: ../../source/changelog/0.8.0-changelog.rst:56\nmsgid \"Jason Villanueva\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:22\n#: ../../source/changelog/0.8.0-changelog.rst:57\nmsgid \"KingWampy\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:23\n#: ../../source/changelog/0.8.0-changelog.rst:58\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:24\nmsgid \"MathInvariance +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:25\nmsgid \"Max Stoumen\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:26\nmsgid \"Mehmet Ali Özer +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:27\nmsgid \"Michael Pilosov +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:28\n#: ../../source/changelog/0.8.0-changelog.rst:61\nmsgid \"Mohammad Al-Fetyani\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:29\n#: ../../source/changelog/0.8.0-changelog.rst:62\nmsgid \"Naveen M K\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:30\n#: ../../source/changelog/0.8.0-changelog.rst:63\nmsgid \"Nikhil Garuda\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:31\n#: ../../source/changelog/0.8.0-changelog.rst:64\nmsgid \"Oliver\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:32\nmsgid \"PaulCMurdoch\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:33\n#: ../../source/changelog/0.8.0-changelog.rst:65\nmsgid \"Philipp Imhof\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:34\nmsgid \"PipedQuintes +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:35\n#: ../../source/changelog/0.8.0-changelog.rst:66\nmsgid \"Raghav Goel\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:36\n#: ../../source/changelog/0.8.0-changelog.rst:67\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:37\nmsgid \"Ujjayanta +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:38\nmsgid \"Vagrid +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:39\nmsgid \"andrehisatsuga +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:40\n#: ../../source/changelog/0.8.0-changelog.rst:70\nmsgid \"friedkeenan\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:41\nmsgid \"peaceheis +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:42\nmsgid \"yit6 +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:45\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:48\nmsgid \"Abhijith Muthyala\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:49\nmsgid \"Anton Ballmaier\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:50\nmsgid \"Aron\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:52\nmsgid \"Clar Fon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:59\nmsgid \"Mark Miller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:60\nmsgid \"MathInvariance\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:68\nmsgid \"Ujjayanta\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:69\nmsgid \"Vagrid\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:73\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:75\nmsgid \"A total of 76 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:78\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:80\nmsgid \":pr:`1616`: Remove all functions and classes that were deprecated until ``v0.6.0``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:84\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:87\nmsgid \":pr:`1716`: Rewrite stroke and fill shaders\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:87\nmsgid \"Rewrite vectorized mobject shaders to be compatible with transformation matrices.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:90\nmsgid \":pr:`1695`: Add option to justify text with :class:`~.MarkupText`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:90\nmsgid \"A new parameter ``justify`` is added to :class:`~.MarkupText`. It can be used to justify a paragraph of text.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:94\nmsgid \":pr:`1660`: Added support for ``.webm`` and transparency of videos in Jupyter notebooks\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:93\nmsgid \"Added support for generating ``webm`` videos via the command line flag ``--format=webm``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:94\nmsgid \"Added transparency support for Jupyter notebooks\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:96\nmsgid \":pr:`1553`: Add dearpygui integration\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:100\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:102\nmsgid \":pr:`1728`: Improved positioning and size of the OpenGL window; added some configuration options\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:105\nmsgid \":pr:`1733`: Let OpenGLMobject.copy return a deep copy by default\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:108\nmsgid \":pr:`1735`: Metaclass compatibility for `coordinate_system.py`, `Code` and `ParametricSurface`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:111\nmsgid \":pr:`1585`: OpenGL compatibility via metaclass for :class:`~.Matrix`, :class:`~.DecimalNumber`, :class:`~.Variable`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:114\nmsgid \":pr:`1713`: Exit the command line interface gracefully if no scene was chosen\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:119\nmsgid \":pr:`1652`: Refactored :class:`~.Mobject` and :class:`~.Scene` to no longer inherit from the abstract base class ``Container``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:118\nmsgid \"Moved tests in ``test_container.py`` for :class:`Container` that test :class:`~.Scene` and :class:`~.Mobject` to their own files.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:119\nmsgid \"Corrected various instances of incorrectly passed keyword arguments, or unused keyword arguments.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:121\nmsgid \":pr:`1693`: Made the default arrowhead size for :class:`~.Arrow3D` smaller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:127\nmsgid \":pr:`1678`: Allow some rate functions to assume values outside of [0, 1]; introduce clamping decorators\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:125\nmsgid \"Fixed animations so that certain rate functions (``running_start``, ``wiggle``, ``ease_in_back``, ``ease_out_back``, ``ease_in_out_back``, ``ease_in_elastic``, ``ease_out_elastic``, and ``ease_out_elastic``) can go outside the range from 0 to 1.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:126\nmsgid \"Fixed lag ratios so that they're spaced out evenly within the time interval and the rate functions are applied to each animation individually, rather than having the rate function determine when the animation starts.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:127\nmsgid \"Fixed faulty code for ``ease_in_out_expo``, ``ease_in_bounce``, ``ease_out_bounce``, and ``ease_in_out_bounce``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:129\nmsgid \":pr:`1649`: Made video file names in Jupyter notebook more readable\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:133\nmsgid \":pr:`1667`: Determine the default number of decimal places for :class:`~.NumberLine` labels automatically from the step size\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:133\nmsgid \"As an example: If the step size is set to 0.5, labels will now show at least one decimal place.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:135\nmsgid \":pr:`1608`: Color file paths in terminal; remove curly braces surrounding the file path in \\\"Partial movie file written in...\\\" messages\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:138\nmsgid \":pr:`1632`: OpenGL compatibility via metaclass: :class:`~.Group`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:142\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:144\nmsgid \":pr:`1740`: Fix pillow to <8.3.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:147\nmsgid \":pr:`1729`: Fix bug when using :class:`~.Text` with the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:150\nmsgid \":pr:`1675`: Fixed ignored fill and stroke colors for :class:`~.SVGMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:153\nmsgid \":pr:`1664`: Fixed accidental displacement in :class:`~.Axes` caused by ``include_numbers`` / ``numbers_to_include``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:156\nmsgid \":pr:`1670`: Fixed missing ``numpy`` import in OpenGL shader example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:159\nmsgid \":pr:`1636`: Fixed bugs and added examples to methods and classes in :mod:`manim.mobject.matrix`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:162\nmsgid \":pr:`1614`: Fix tick issues and improve tick placement for :class:`~.NumberLine`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:165\nmsgid \":pr:`1593`: Un-flip output of ``get_frame()`` when using the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:168\nmsgid \":pr:`1619`: Fix output of automatically detected LaTeX errors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:176\nmsgid \":pr:`1595`: Fixed a few CLI and rendering bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:172\nmsgid \"Corrected issue where gifs were being logged with an incorrect extension\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:173\nmsgid \"Fixed issue where videos were output when format was set to png\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:174\nmsgid \"Added logging for png output\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:175\nmsgid \"Added precedence handling when the ``write_to_movie`` flag would conflict with ``--format``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:176\nmsgid \"Fixed issue that caused png image output to be ignored when caching was enabled\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:178\nmsgid \":pr:`1635`: Added missing numpy import for :mod:`manim.mobject.probability`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:182\nmsgid \":pr:`1634`: Fixed OpenGL examples for MacOS\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:182\nmsgid \"Renamed deprecated ``gl_FragColor`` to ``fragColor``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:185\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:187\nmsgid \":pr:`1732`: Remove reference to ``--plugins`` flag\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:190\nmsgid \":pr:`1734`: Fix inheritance graph background color\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:193\nmsgid \":pr:`1698`: Added an example for :class:`~.PMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:196\nmsgid \":pr:`1690`: Added an example for :class:`~.CoordinateSystem`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:199\nmsgid \":pr:`1510`: Add a tutorial for using :class:`~.Text` and :class:`~.Tex`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:202\nmsgid \":pr:`1685`: Added an example and parameter description for :class:`~.AnnularSector`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:205\nmsgid \":pr:`1687`: Updated imports in ``geometry.py`` and added example to :class:`~.Arrow`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:208\nmsgid \":pr:`1681`: Added an example for :class:`~.NumberLine`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:211\nmsgid \":pr:`1697`: Added an example for :class:`~.PGroup`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:214\nmsgid \":pr:`1594`: Several improvements to the documentation design and layout\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:217\nmsgid \":pr:`1696`: Added an example for :class:`~.DashedVMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:220\nmsgid \":pr:`1637`: Added an example for :class:`~.FunctionGraph`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:223\nmsgid \":pr:`1626`: Added an example for :class:`~.Prism`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:226\nmsgid \":pr:`1712`: Added a second example for :class:`~.DoubleArrow`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:229\nmsgid \":pr:`1710`: Update copyright year in documentation to 2020-2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:232\nmsgid \":pr:`1708`: Fixed link to interactive example notebook\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:235\nmsgid \":pr:`1657`: Added an example for :class:`~.ParametricSurface`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:238\nmsgid \":pr:`1642`: Added examples and docstrings for :class:`~.BarChart`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:241\nmsgid \":pr:`1700`: Added an example for :meth:`~.Mobject.scale`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:244\nmsgid \":pr:`1689`: Added an example for :class:`~.SurroundingRectangle`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:247\nmsgid \":pr:`1627`: Added an example for :class:`~.Sphere`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:250\nmsgid \":pr:`1569`: Added example to demonstrate differences between :class:`~.Transform` and :class:`~.ReplacementTransform`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:253\nmsgid \":pr:`1647`: Added an example for :class:`~.Sector`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:256\nmsgid \":pr:`1673`: Updated documentation examples for :class:`~.Text` and :class:`~.MarkupText`: set ``weight=BOLD`` instead of ``style``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:259\nmsgid \":pr:`1650`: Added an example for :class:`~.ArcBetweenPoints`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:262\nmsgid \":pr:`1628`: Added an example for :class:`~.NumberPlane`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:265\nmsgid \":pr:`1646`: Added an example for :class:`~.Underline`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:268\nmsgid \":pr:`1659`: Added more details to the Google Colab installation instructions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:271\nmsgid \":pr:`1658`: Updated python requirement in the documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:274\nmsgid \":pr:`1639`: Added an example for :class:`~.SampleSpace`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:277\nmsgid \":pr:`1640`: Added an example for :class:`~.Point`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:280\nmsgid \":pr:`1643`: Fixed ``RightArcAngleExample`` for :class:`~.Angle` in documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:283\nmsgid \":pr:`1617`: Visually improved an example in our tutorial\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:286\nmsgid \":pr:`1641`: Added an example for :class:`~.ComplexPlane`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:289\nmsgid \":pr:`1644`: Added an example for :class:`~.BackgroundRectangle`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:292\nmsgid \":pr:`1633`: Added an example for :class:`~.Integer`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:295\nmsgid \":pr:`1630`: Added an example for :class:`~.Arc`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:298\nmsgid \":pr:`1631`: Added an example for :class:`~.BulletedList`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:301\nmsgid \":pr:`1620`: Fixed reference to command line interface help command\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:305\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:307\nmsgid \":pr:`1623`: CI: branch rename: master -> main\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:310\nmsgid \":pr:`1621`: Revert default template and add new templates\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:313\nmsgid \":pr:`1573`: PR template for the manim hackathon\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:317\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:319\nmsgid \":pr:`1720`: Renamed incorrect references of ``master`` to ``main``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:322\nmsgid \":pr:`1692`: Removed redundant warning in CLI parsing\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:325\nmsgid \":pr:`1651`: Small code cleanup for :class:`~.Polygram`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:328\nmsgid \":pr:`1610`: Changed one image extension to lowercase letters\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.8.0-changelog.rst:332\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog/0.9.0-changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:3\nmsgid \"v0.9.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:0\nmsgid \"Date\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:5\nmsgid \"August 02, 2021\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:8\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:10\nmsgid \"A total of 35 people contributed to this release. People with a '+' by their names authored a patch for the first time.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:14\n#: ../../source/changelog/0.9.0-changelog.rst:47\nmsgid \"Alex Lembcke\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:15\n#: ../../source/changelog/0.9.0-changelog.rst:48\nmsgid \"Benjamin Hackl\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:16\n#: ../../source/changelog/0.9.0-changelog.rst:49\nmsgid \"Darylgolden\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:17\n#: ../../source/changelog/0.9.0-changelog.rst:50\nmsgid \"Devin Neal\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:18\nmsgid \"Harivinay +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:19\n#: ../../source/changelog/0.9.0-changelog.rst:52\nmsgid \"Hugues Devimeux\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:20\nmsgid \"Jared Hughes +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:21\n#: ../../source/changelog/0.9.0-changelog.rst:54\nmsgid \"Jason Villanueva\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:22\nmsgid \"Kadatatlu Kishore +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:23\n#: ../../source/changelog/0.9.0-changelog.rst:55\nmsgid \"KingWampy\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:24\nmsgid \"LED Me Explain +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:25\n#: ../../source/changelog/0.9.0-changelog.rst:56\nmsgid \"Laith Bahodi\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:26\n#: ../../source/changelog/0.9.0-changelog.rst:58\nmsgid \"Mohammad Al-Fetyani\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:27\nmsgid \"Noam Zaks\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:28\n#: ../../source/changelog/0.9.0-changelog.rst:59\nmsgid \"Oliver\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:29\nmsgid \"PaulCMurdoch\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:30\nmsgid \"Raghav Prabhakar +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:31\nmsgid \"Ryan McCauley\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:32\nmsgid \"Suhail Sherif +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:33\nmsgid \"Taektiek +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:34\nmsgid \"Udeshya Dhungana +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:35\nmsgid \"UraniumCronorum +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:36\nmsgid \"Vinh H. Pham (Vincent) +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:37\nmsgid \"ccn +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:38\nmsgid \"icedcoffeeee +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:39\nmsgid \"sahilmakhijani +\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:40\n#: ../../source/changelog/0.9.0-changelog.rst:64\nmsgid \"sparshg\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:43\nmsgid \"The patches included in this release have been reviewed by the following contributors.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:46\nmsgid \"Abhijith Muthyala\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:51\nmsgid \"Harivinay\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:53\nmsgid \"Jan-Hendrik Müller\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:57\nmsgid \"Lino\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:60\nmsgid \"Raghav Goel\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:61\nmsgid \"Suhail Sherif\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:62\nmsgid \"icedcoffeeee\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:63\nmsgid \"sahilmakhijani\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:67\nmsgid \"Pull requests merged\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:69\nmsgid \"A total of 55 pull requests were merged for this release.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:72\nmsgid \"Highlights\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:75\nmsgid \":pr:`1677`: Added a new :class:`~.Table` mobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:75\nmsgid \"This brings easy-to-use and customizable tables to Manim. Several examples for this new mobject can be found at :mod:`the module documentation page <.mobject.table>` and its subpages.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:78\nmsgid \"Deprecated classes and functions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:82\nmsgid \":pr:`1848`: Deprecated parameters for :class:`~.DashedLine` and :class:`~.DashedVMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:81\nmsgid \"``dash_spacing`` is an unused parameter\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:82\nmsgid \"``positive_space_ratio`` has been replaced with the shorter name ``dashed_ratio``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:92\nmsgid \":pr:`1773`: Remove all classes and functions that were deprecated until ``v0.7.0`` and ``v0.8.0``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:85\nmsgid \"The classes ``FadeInFrom``, ``FadeOutAndShift``, ``FadeOutToPoint``, ``FadeInFromPoint``, ``FadeInFromLarge``, ``VFadeIn``, ``VFadeOut``, ``VFadeInThenOut`` have been removed, use :class:`~.FadeIn` or :class:`~.FadeOut` with appropriate keyword arguments instead.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:88\nmsgid \"The classes ``CircleIndicate``, ``ShowCreationThenDestruction``, ``AnimationOnSurroundingRectangle``, ``ShowPassingFlashAround``, ``ShowCreationThenDestructionAround``, ``ShowCreationThenFadeAround``, ``WiggleOutThenIn``, ``TurnInsideOut`` have been removed. Use :class:`~.Circumscribe`, :class:`~.ShowPassingFlash`, or :class:`~.Wiggle` instead.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:90\nmsgid \"The classes ``OpenGLTexMobject`` and ``OpenGLTextMobject`` have been removed, use :class:`~.MathTex` and :class:`~.Tex` instead. Also, ``VMobjectFromSVGPathstring`` has been removed, use :class:`~.SVGPathMobject` instead.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:92\nmsgid \"Finally, the utility functions ``get_norm`` and ``cross`` have been removed (use the corresponding Numpy methods instead), and the function ``angle_between`` has been replaced with ``angle_between_vectors``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:96\nmsgid \":pr:`1731`: Deprecated :class:`~.ParametricSurface` parameters\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:95\nmsgid \"``u_min`` and ``u_max`` have been replaced by ``u_range``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:96\nmsgid \"``v_min`` and ``v_max`` have been replaced by ``v_range``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:99\nmsgid \"New features\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:103\nmsgid \":pr:`1780`: Allow non-numerical values to be added to :class:`~.NumberLine` and :class:`~.Axes`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:102\nmsgid \"Added :meth:`.NumberLine.add_labels` method to :class:`~.NumberLine` which accepts a dictionary of positions/values.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:103\nmsgid \":meth:`.CoordinateSystem.add_coordinates` now accepts a dictionary too.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:105\nmsgid \":pr:`1719`: Added a :class:`~.Broadcast` animation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:109\nmsgid \":pr:`1765`: Added a static method :meth:`.Circle.from_three_points` for defining a circle from three points\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:109\nmsgid \"Added a new :func:`~.perpendicular_bisector` function in ``space_ops.py``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:112\nmsgid \":pr:`1686`: Added :meth:`.ParametricSurface.set_fill_by_value`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:112\nmsgid \"This method enables a color gradient to be applied to a :class:`~.ParametricSurface`, including the ability to define at which points the colors should be centered.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:115\nmsgid \"Enhancements\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:117\nmsgid \":pr:`1833`: Added OpenGL compatibility for :class:`~.VDict`, :meth:`~.Axes.get_line_graph` and :class:`~.FocusOn`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:121\nmsgid \":pr:`1760`: Added ``window_size`` flag to manually adjust the size of the OpenGL window\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:121\nmsgid \"Accepts a tuple in the form: ``x,y``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:124\nmsgid \":pr:`1823`: Reworked :class:`~.DashedVMobject`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:124\nmsgid \"Rewritten the logic to generate dashes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:129\nmsgid \":pr:`1808`: OpenGL renderer updates\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:127\nmsgid \"Adds model matrices to all OpenGLVMobjects\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:128\nmsgid \"Improved performance on vectorized mobject shaders\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:129\nmsgid \"Added updaters that are part of the scene rather than a mobject\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:132\nmsgid \":pr:`1787`: Made :class:`~.DecimalNumber` apply color to the ellipsis\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:132\nmsgid \"Made color apply to the dots when `show_ellipsis` is set to true in `DecimalNumber`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:134\nmsgid \":pr:`1775`: Let :class:`~.Create` work on :class:`~.OpenGLSurface`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:137\nmsgid \":pr:`1757`: Added warning when there is a large number of items to hash.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:140\nmsgid \":pr:`1774`: Add the ``reverse`` parameter to :class:`~.Write`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:144\nmsgid \"Fixed bugs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:146\nmsgid \":pr:`1722`: Fixed ``remover=True`` for :class:`~.AnimationGroup`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:151\nmsgid \":pr:`1727`: Fixed some hot reload issues and compatibility with IDEs\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:150\nmsgid \"Fixed interactive embed issue where it would fail when running on non-tty terminals\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:151\nmsgid \"Fixed issue where file observer would error after the second run as the first observer was not closed\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:153\nmsgid \":pr:`1844`: Fixed the oversized :class:`~.Code` window with the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:159\nmsgid \":pr:`1821`: Fixed issues concerning ``frame_center`` in :class:`~.ThreeDScene`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:157\nmsgid \"Changing ``frame_center`` in a :class:`~.ThreeDScene` now actually changes the camera position.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:158\nmsgid \"An animation with only ``frame_center`` animated will now be rendered properly.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:159\nmsgid \"A black dot is not created at the origin once ``frame_center`` is animated.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:161\nmsgid \":pr:`1826`: Fixed scaling issue with :meth:`.BarChart.change_bar_values`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:164\nmsgid \":pr:`1839`: Allow passing arguments to ``.animate`` with the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:167\nmsgid \":pr:`1791`: :meth:`~.Mobject.set_z_index` now sets all submobjects' ``z_index`` value\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:170\nmsgid \":pr:`1792`: Fixed bug that caused dry runs to fail when using the PNG format\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:173\nmsgid \":pr:`1790`: Fixed an import from ``manimlib``\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:176\nmsgid \":pr:`1782`: Fixed :class:`~.Tex` not working properly with the OpenGL renderer\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:179\nmsgid \":pr:`1783`: Fixed :meth:`~.OpenGLMobject.shuffle` function and added :meth:`~.invert` to OpenGL\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:182\nmsgid \":pr:`1786`: Fixed :class:`~.DecimalNumber` not working properly when the number of digits changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:185\nmsgid \":pr:`1763`: Fixed not being able to set some CLI flags in the configuration file\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:189\nmsgid \":pr:`1776`: :meth:`.CoordinateSystem.get_riemann_rectangles` now uses the graph's range instead of the axes range\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:189\nmsgid \"If no range specified, `get_riemann_rectangles` generates the rectangles only where the area is correctly bounded\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:191\nmsgid \":pr:`1770`: Rewrote :meth:`.OpenGLMobject.put_start_and_end_on` to work correctly in 3D\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:194\nmsgid \":pr:`1736`: Fixed :class:`~.LinearTransformationScene` crashing on multiple animations\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:198\nmsgid \"Documentation-related changes\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:200\nmsgid \":pr:`1852`: Fixed docs for :meth:`.Coordinate_system.add_coordinates` and moved :class: `~.Code` example\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:206\nmsgid \":pr:`1807`: Updated installation instructions\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:204\nmsgid \"Added a warning about the incompatibility of different versions of Manim in the README\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:205\nmsgid \"Modified the admonition warning in the documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:206\nmsgid \"Removed duplicated information from the README (``pip install manim`` is already covered in the docs)\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:208\nmsgid \":pr:`1739`: Added a section on creating a custom animation to the \\\"Manim's building blocks\\\" tutorial\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:211\nmsgid \":pr:`1835`: Updated documentation with information about reworked graphical unit test system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:214\nmsgid \":pr:`1845`: Improve ``ThreeDSurfacePlot`` example in example gallery\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:217\nmsgid \":pr:`1842`: Removed instructions on installing Poetry from Developer Installation documentation, reference Poetry's documentation instead\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:220\nmsgid \":pr:`1829`: Switch the order of Scoop and Chocolatey in the docs for the Windows Installation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:223\nmsgid \":pr:`1827`: Added ``robots.txt`` to prevent old versions of documentation from showing in search results\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:226\nmsgid \":pr:`1819`: Removed mention of ``-h`` CLI flag from documentation\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:229\nmsgid \":pr:`1813`: Removed unused variables from tutorial\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:232\nmsgid \":pr:`1815`: Added codespell to the list of used linters in the contribution guidelines\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:235\nmsgid \":pr:`1778`: Improve sidebar structure of the documentation's reference manual\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:238\nmsgid \":pr:`1749`: Added documentation and example for :meth:`.VMobject.set_fill`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:241\nmsgid \":pr:`1743`: Edited the developer installation instructions to include information on cloning the repository\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:244\nmsgid \":pr:`1706`: Rework example for :class:`~.Variable`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:248\nmsgid \"Changes concerning the testing system\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:250\nmsgid \":pr:`1836`: Converted all the graphical tests to the new syntax\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:254\nmsgid \":pr:`1802`: Refactored graphical unit testing system, and implemented multi frames tests\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:254\nmsgid \"This PR introduces a new ``@frames_comparison`` decorator which allows writing simple ``construct``-like functions as tests. Control data for new tests can be easily generated by calling ``pytest --set_test``.\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:257\nmsgid \"Changes to our development infrastructure\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:259\nmsgid \":pr:`1830`: Be more concise about the documentation URL in the PR template\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:263\nmsgid \"Code quality improvements and similar refactors\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:265\nmsgid \":pr:`1851`: Renamed ``Tabular`` to :class:`~.Table`\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:268\nmsgid \":pr:`1817`: Remove pillow version requirement\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:271\nmsgid \":pr:`1806`: Fixed spelling mistake\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:274\nmsgid \":pr:`1745`: Updated the BibTeX template in the README to Manim v0.9.0\"\nmsgstr \"\"\n\n#: ../../source/changelog/0.9.0-changelog.rst:278\nmsgid \"New releases\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/changelog.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/conduct.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/conduct.md:3\nmsgid \"Code of Conduct\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:7\nmsgid \"TL;DR Be excellent to each other; we're a community after all. If you run into issues with others in our community, please [contact](https://www.manim.community/discord/) a Manim Community Dev, or Moderator.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:9\nmsgid \"Purpose\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:11\nmsgid \"The Manim Community includes members of varying skills, languages, personalities, cultural backgrounds, and experiences from around the globe. Through these differences, we continue to grow and collectively improve upon an open-source animation engine. When working in a community, it is important to remember that you are interacting with humans on the other end of your screen. This code of conduct will guide your interactions and keep Manim a positive environment for our developers, users, and fundamentally our growing community.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:15\nmsgid \"Our Community\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:17\nmsgid \"Members of Manim Community are respectful, open, and considerate. Behaviors that reinforce these values contribute to our positive environment, and include:\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:19\nmsgid \"**Being respectful.** Respectful of others, their positions, experiences, viewpoints, skills, commitments, time, and efforts.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:21\nmsgid \"**Being open.** Open to collaboration, whether it's on problems, Pull Requests, issues, or otherwise.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:23\nmsgid \"**Being considerate.** Considerate of their peers -- other Manim users and developers.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:25\nmsgid \"**Focusing on what is best for the community.** We're respectful of the processes set forth in the community, and we work within them.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:27\nmsgid \"**Showing empathy towards other community members.** We're attentive in our communications, whether in person or online, and we're tactful when approaching differing views.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:29\nmsgid \"**Gracefully accepting constructive criticism.** When we disagree, we are courteous in raising our issues.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:31\nmsgid \"**Using welcoming and inclusive language.** We're accepting of all who wish to take part in our activities, fostering an environment where anyone can participate and everyone can make a difference.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:35\nmsgid \"Our Standards\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:37\nmsgid \"Every member of our community has the right to have their identity respected. Manim Community is dedicated to providing a positive environment for everyone, regardless of age, gender identity and expression, sexual orientation, disability, physical appearance, body size, ethnicity, nationality, race, religion (or lack thereof), education, or socioeconomic status.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:41\nmsgid \"Inappropriate Behavior\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:43\nmsgid \"Examples of unacceptable behavior by participants include:\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:45\nmsgid \"Harassment of any participants in any form\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:46\nmsgid \"Deliberate intimidation, stalking, or following\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:47\nmsgid \"Logging or taking screenshots of online activity for harassment purposes\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:48\nmsgid \"Publishing others' private information, such as a physical or electronic address, without explicit permission\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:49\nmsgid \"Violent threats or language directed against another person\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:50\nmsgid \"Incitement of violence or harassment towards any individual, including encouraging a person to commit suicide or to engage in self-harm\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:51\nmsgid \"Creating additional online accounts in order to harass another person or circumvent a ban\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:52\nmsgid \"Sexual language and imagery in online communities or any conference venue, including talks\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:53\nmsgid \"Insults, put-downs, or jokes that are based upon stereotypes, that are exclusionary, or that hold others up for ridicule\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:54\nmsgid \"Excessive swearing\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:55\nmsgid \"Unwelcome sexual attention or advances\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:56\nmsgid \"Unwelcome physical contact, including simulated physical contact (eg, textual descriptions like \\\"hug\\\" or \\\"backrub\\\") without consent or after a request to stop\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:57\nmsgid \"Pattern of inappropriate social contact, such as requesting/assuming inappropriate levels of intimacy with others\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:58\nmsgid \"Sustained disruption of online community discussions, in-person presentations, or other in-person events\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:59\nmsgid \"Continued one-on-one communication after requests to cease\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:60\nmsgid \"Other conduct that is inappropriate for a professional audience including people of many different backgrounds Community members asked to stop any inappropriate behavior are expected to comply immediately.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:65\nmsgid \"Manim Community Online Spaces\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:67\nmsgid \"This Code of Conduct applies to the following online spaces:\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:69\nmsgid \"The [ManimCommunity GitHub Organization](https://github.com/ManimCommunity) and all of its repositories\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:71\nmsgid \"The Manim [Discord](https://www.manim.community/discord/)\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:73\nmsgid \"The Manim [Reddit](https://www.reddit.com/r/manim/)\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:75\nmsgid \"The Manim [Twitter](https://twitter.com/manim\\\\_community/)\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:77\nmsgid \"This Code of Conduct applies to every member in official Manim Community online spaces, including:\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:79\nmsgid \"Moderators\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:81\nmsgid \"Maintainers\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:83\nmsgid \"Developers\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:85\nmsgid \"Reviewers\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:87\nmsgid \"Contributors\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:89\nmsgid \"Users\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:91\nmsgid \"All community members\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:95\nmsgid \"Consequences\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:97\nmsgid \"If a member's behavior violates this code of conduct, the Manim Community Code of Conduct team may take any action they deem appropriate, including, but not limited to: warning the offender, temporary bans, deletion of offending messages, and expulsion from the community and its online spaces. The full list of consequences for inappropriate behavior is listed below in the Enforcement Procedures.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:101\nmsgid \"Thank you for helping make this a welcoming, friendly community for everyone.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:105\nmsgid \"Contact Information\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:107\nmsgid \"If you believe someone is violating the code of conduct, or have any other concerns, please contact a Manim Community Dev, or Moderator immediately. They can be reached on Manim's Community [Discord](https://www.manim.community/discord/).\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:117\nmsgid \"Enforcement Procedures\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:119\nmsgid \"This document summarizes the procedures the Manim Community Code of Conduct team uses to enforce the Code of Conduct.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:123\nmsgid \"Summary of processes\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:125\nmsgid \"When the team receives a report of a possible Code of Conduct violation, it will:\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:127\nmsgid \"Acknowledge the receipt of the report.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:128\nmsgid \"Evaluate conflicts of interest.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:129\nmsgid \"Call a meeting of code of conduct team members without a conflict of interest.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:130\nmsgid \"Evaluate the reported incident.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:131\nmsgid \"Propose a behavioral modification plan.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:132\nmsgid \"Propose consequences for the reported behavior.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:133\nmsgid \"Vote on behavioral modification plan and consequences for the reported person.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:134\nmsgid \"Contact Manim Community moderators to approve the behavioral modification plan and consequences.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:135\nmsgid \"Follow up with the reported person.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:136\nmsgid \"Decide further responses.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:137\nmsgid \"Follow up with the reporter.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:140\nmsgid \"Acknowledge the report\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:142\nmsgid \"Reporters should receive an acknowledgment of the receipt of their report within 48 hours.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:146\nmsgid \"Conflict of interest policy\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:148\nmsgid \"Examples of conflicts of interest include:\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:150\nmsgid \"You have a romantic or platonic relationship with either the reporter or the reported person. It's fine to participate if they are an acquaintance.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:151\nmsgid \"The reporter or reported person is someone you work closely with. This could be someone on your team or someone who works on the same project as you.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:152\nmsgid \"The reporter or reported person is a maintainer who regularly reviews your contributions\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:153\nmsgid \"The reporter or reported person is your metamour.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:154\nmsgid \"The reporter or reported person is your family member Committee members do not need to state why they have a conflict of interest, only that one exists. Other team members should not ask why the person has a conflict of interest.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:157\nmsgid \"Anyone who has a conflict of interest will remove themselves from the discussion of the incident, and recluse themselves from voting on a response to the report.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:161\nmsgid \"Evaluating a report\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:163\nmsgid \"Jurisdiction\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:165\nmsgid \"*Is this a Code of Conduct violation?* Is this behavior on our list of inappropriate behavior? Is it borderline inappropriate behavior? Does it violate our community norms?\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:166\nmsgid \"*Did this occur in a space that is within our Code of Conduct's scope?* If the incident occurred outside the community, but a community member's mental health or physical safety may be negatively impacted if no action is taken, the incident may be in scope. Private conversations in community spaces are also in scope.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:167\nmsgid \"Impact\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:169\nmsgid \"*Did this incident occur in a private conversation or a public space?* Incidents that all community members can see will have a more negative impact.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:170\nmsgid \"*Does this behavior negatively impact a marginalized group in our community?* Is the reporter a person from a marginalized group in our community? How is the reporter being negatively impacted by the reported person's behavior? Are members of the marginalized group likely to disengage with the community if no action was taken on this report?\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:171\nmsgid \"*Does this incident involve a community leader?* Community members often look up to community leaders to set the standard of acceptable behavior\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:172\nmsgid \"Risk\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:174\nmsgid \"*Does this incident include sexual harassment?*\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:175\nmsgid \"*Does this pose a safety risk?* Does the behavior put a person's physical safety at risk? Will this incident severely negatively impact someone's mental health?\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:176\nmsgid \"*Is there a risk of this behavior being repeated?* Does the reported person understand why their behavior was inappropriate? Is there an established pattern of behavior from past reports?\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:179\nmsgid \"Reports which involve higher risk or higher impact may face more severe consequences than reports which involve lower risk or lower impact.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:183\nmsgid \"Propose consequences\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:185\nmsgid \"What follows are examples of possible consequences of an incident report. This list of consequences is not exhaustive, and the Manim Community Code of Conduct team reserves the right to take any action it deems necessary.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:187\nmsgid \"Possible private responses to an incident include:\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:189\nmsgid \"Nothing, if the behavior was determined to not be a Code of Conduct violation\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:190\nmsgid \"A warning\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:191\nmsgid \"A final warning\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:192\nmsgid \"Temporarily removing the reported person from the community's online space(s)\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:193\nmsgid \"Permanently removing the reported person from the community's online space(s)\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:194\nmsgid \"Publishing an account of the incident\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:197\nmsgid \"Team vote\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:199\nmsgid \"Some team members may have a conflict of interest and may be excluded from discussions of a particular incident report. Excluding those members, decisions on the behavioral modification plans and consequences will be determined by a two-thirds majority vote of the Manim Community Code of Conduct team.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:203\nmsgid \"Moderators approval\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:205\nmsgid \"Once the team has approved the behavioral modification plans and consequences, they will communicate the recommended response to the Manim Community moderators. The team should not state who reported this incident. They should attempt to anonymize any identifying information from the report.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:207\nmsgid \"Moderators are required to respond with whether they accept the recommended response to the report. If they disagree with the recommended response, they should provide a detailed response or additional context as to why they disagree. Moderators are encouraged to respond within a week.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:209\nmsgid \"In cases where the moderators disagree on the suggested resolution for a report, the Manim Community Code of Conduct team may choose to notify the Manim Community Moderators.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:213\nmsgid \"Follow up with the reported person\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:215\nmsgid \"The Manim Community Code of Conduct team will work with Manim Community moderators to draft a response to the reported person. The response should contain:\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:217\nmsgid \"A description of the person's behavior in neutral language\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:218\nmsgid \"The negative impact of that behavior\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:219\nmsgid \"A concrete behavioral modification plan\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:220\nmsgid \"Any consequences of their behavior The team should not state who reported this incident. They should attempt to anonymize any identifying information from the report. The reported person should be discouraged from contacting the reporter to discuss the report. If they wish to apologize to the reporter, the team can accept the apology on behalf of the reporter.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:225\nmsgid \"Decide further responses\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:227\nmsgid \"If the reported person provides additional context, the Manim Community Code of Conduct team may need to re-evaluate the behavioral modification plan and consequences.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:229\nmsgid \"Follow up with the reporter\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:231\nmsgid \"A person who makes a report should receive a follow-up response stating what action was taken in response to the report. If the team decided no response was needed, they should provide an explanation why it was not a Code of Conduct violation. Reports that are not made in good faith (such as \\\"reverse sexism\\\" or \\\"reverse racism\\\") may receive no response.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:233\nmsgid \"The follow-up should be sent no later than one week after the receipt of the report. If deliberation or follow-up with the reported person takes longer than one week, the team should send a status update to the reporter.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:237\nmsgid \"Changes to Code of Conduct\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:239\nmsgid \"When discussing a change to the Manim Community code of conduct or enforcement procedures, the Manim Community Code of Conduct team will follow this decision-making process:\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:241\nmsgid \"**Brainstorm options.** Team members should discuss any relevant context and brainstorm a set of possible options. It is important to provide constructive feedback without getting side-tracked from the main question.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:242\nmsgid \"**Vote.** Proposed changes to the code of conduct will be decided by a two-thirds majority of all voting members of the Code of Conduct team. Team members are listed in the charter. Currently active voting members are listed in the following section.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:243\nmsgid \"**Board Vote.** Once a working draft is in place for the Code of Conduct and procedures, the Code of Conduct team shall provide the Manim Community Moderators with a draft of the changes. The Manim Community Moderators will vote on the changes at a board meeting.\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:246\nmsgid \"Current list of voting members\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:248\nmsgid \"All available Community Developers (i.e. those with \\\"write\\\" permissions, or above, on the Manim Community GitHub organization).\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:252\nmsgid \"License\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:254\nmsgid \"This Code of Conduct is licensed under the [Creative Commons Attribution-ShareAlike 3.0 Unported License](https://creativecommons.org/licenses/by-sa/3.0/).\"\nmsgstr \"\"\n\n#: ../../source/conduct.md:258\nmsgid \"Attributions\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/contributing/admonitions.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/contributing/admonitions.rst:3\nmsgid \"Adding Admonitions\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:6\nmsgid \"Adding Blocks for Tip, Note, Important etc. (Admonitions)\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:8\nmsgid \"The following directives are called Admonitions. You can use them to point out additional or important information. Here are some examples:\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:13\nmsgid \"See also\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:21\nmsgid \"Some ideas at :mod:`~.tex_mobject`, :class:`~.Mobject`, :meth:`~.Mobject.add_updater`, :attr:`~.Mobject.depth`, :func:`~.make_config_parser`\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:28\nmsgid \"Note\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:36\nmsgid \"A note\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:39\nmsgid \"Tip\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:47\nmsgid \"A tip\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:49\nmsgid \"You may also use the admonition **hint**, but this is very similar and **tip** is more commonly used in the documentation.\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:53\nmsgid \"Important\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:61\nmsgid \"Some important information which should be considered.\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:64\nmsgid \"Warning\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:72\nmsgid \"Some text pointing out something that people should be warned about.\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:74\nmsgid \"You may also use the admonitions **caution** or even **danger** if the severity of the warning must be stressed.\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:78\nmsgid \"Attention\"\nmsgstr \"\"\n\n#: ../../source/contributing/admonitions.rst:86\nmsgid \"A attention\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/contributing/development.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/contributing/development.rst:3\nmsgid \"Manim Development Process\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:6\nmsgid \"For first-time contributors\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:7\nmsgid \"Install git:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:9\nmsgid \"For instructions see https://git-scm.com/.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:12\nmsgid \"Fork the project. Go to https://github.com/ManimCommunity/manim and click the \\\"fork\\\" button to create a copy of the project for you to work on. You will need a GitHub account. This will allow you to make a \\\"Pull Request\\\" (PR) to the ManimCommunity repo later on.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:17\nmsgid \"Clone your fork to your local computer:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:23\nmsgid \"GitHub will provide both a SSH (``git@github.com:<your-username>/manim.git``) and HTTPS (``https://github.com/<your-username>/manim.git``) URL for cloning. You can use SSH if you have SSH keys setup.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:29\nmsgid \"Do not clone the ManimCommunity repository. You must clone your own fork.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:32\nmsgid \"Change the directory to enter the project folder:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:38\nmsgid \"Add the upstream repository, ManimCommunity:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:44\nmsgid \"Now, ``git remote -v`` should show two remote repositories named:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:46\nmsgid \"``origin``, your forked repository\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:47\nmsgid \"``upstream`` the ManimCommunity repository\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:49\nmsgid \"Install Manim:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:51\nmsgid \"Follow the steps in our :doc:`installation instructions <../installation>` to install **Manim's dependencies**, primarily ``ffmpeg`` and ``LaTeX``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:55\nmsgid \"We recommend using `Poetry <https://python-poetry.org>`__ to manage your developer installation of Manim. Poetry is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on, and it will manage (install / update) them for you. In addition, Poetry provides a simple interface for managing virtual environments.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:62\nmsgid \"If you choose to use Poetry as well, follow `Poetry's installation guidelines <https://python-poetry.org/docs/master/#installation>`__ to install it on your system, then run ``poetry install`` from your cloned repository. Poetry will then install Manim, as well as create and enter a virtual environment. You can always re-enter that environment by running ``poetry shell``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:69\nmsgid \"In case you want to install extra dependencies that are defined in the ``[tool.poetry.extras]``  section of ``pyproject.toml``, this can be done by passing the ``-E`` flag, for example ``poetry install -E jupyterlab -E gui``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:73\nmsgid \"In case you decided against Poetry, you can install Manim via pip by running ``python3 -m pip install .``. Note that due to our development infrastructure being based on Poetry, we currently do not support editable installs via ``pip``, so you will have to re-run this command every time you make changes to the source code.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:82\nmsgid \"The following steps assume that you chose to install and work with Poetry.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:85\nmsgid \"Install Pre-Commit:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:91\nmsgid \"This will ensure during development that each of your commits is properly formatted against our linter and formatters, ``black``, ``flake8``, ``isort`` and ``codespell``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:95\nmsgid \"You are now ready to work on manim!\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:98\nmsgid \"Develop your contribution\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:100\nmsgid \"Checkout your local repository's main branch and pull the latest changes from ManimCommunity, ``upstream``, into your local repository:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:108\nmsgid \"Create a branch for the changes you want to work on rather than working off of your local main branch:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:115\nmsgid \"This ensures you can easily update your local repository's main with the first step and switch branches to work on multiple features.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:118\nmsgid \"Write some awesome code!\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:120\nmsgid \"You're ready to make changes in your local repository's branch. You can add local files you've changed within the current directory with ``git add .``, or add specific files with\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:128\nmsgid \"and commit these changes to your local history with ``git commit``. If you have installed pre-commit, your commit will succeed only if none of the hooks fail.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:134\nmsgid \"When crafting commit messages, it is highly recommended that you adhere to `these guidelines <https://www.conventionalcommits.org/en/v1.0.0/>`_.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:137\nmsgid \"Add new or update existing tests.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:139\nmsgid \"Depending on your changes, you may need to update or add new tests. For new features, it is required that you include tests with your PR. Details of our testing system are explained in the :doc:`testing guide <testing>`.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:144\nmsgid \"Update docstrings and documentation:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:146\nmsgid \"Update the docstrings (the text in triple quotation marks) of any functions or classes you change and include them with any new functions you add. See the :doc:`documentation guide <docstrings>` for more information about how we prefer our code to be documented. The content of the docstrings will be rendered in the :doc:`reference manual <../reference>`.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:154\nmsgid \"Use the :mod:`manim directive for Sphinx <manim.utils.docbuild.manim_directive>` to add examples to the documentation!\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:157\nmsgid \"As far as development on your local machine goes, these are the main steps you should follow.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:161\nmsgid \"Polishing Changes and Submitting a Pull Request\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:163\nmsgid \"As soon as you are ready to share your local changes with the community so that they can be discussed, go through the following steps to open a pull request. A pull request signifies to the ManimCommunity organization, \\\"Here are some changes I wrote; I think it's worthwhile for you to maintain them.\\\"\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:171\nmsgid \"You do not need to have everything (code/documentation/tests) complete to open a pull request (PR). If the PR is still under development, please mark it as a draft. Community developers will still be able to review the changes, discuss yet-to-be-implemented changes, and offer advice; however, the more complete your PR, the quicker it will be merged.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:177\nmsgid \"Update your fork on GitHub to reflect your local changes:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:183\nmsgid \"Doing so creates a new branch on your remote fork, ``origin``, with the contents of your local repository on GitHub. In subsequent pushes, this local branch will track the branch ``origin`` and ``git push`` is enough.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:188\nmsgid \"Make a pull request (PR) on GitHub.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:190\nmsgid \"In order to make the ManimCommunity development team aware of your changes, you can make a PR to the ManimCommunity repository from your fork.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:195\nmsgid \"Make sure to select ``ManimCommunity/manim`` instead of ``3b1b/manim`` as the base repository!\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:198\nmsgid \"Choose the branch from your fork as the head repository - see the screenshot below.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:204\nmsgid \"Please make sure you follow the template (this is the default text you are shown when first opening the 'New Pull Request' page).\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:208\nmsgid \"Your changes are eligible to be merged if:\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:210\nmsgid \"there are no merge conflicts\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:211\nmsgid \"the tests in our pipeline pass\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:212\nmsgid \"at least one (two for more complex changes) Community Developer approves the changes\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:214\nmsgid \"You can check for merge conflicts between the current upstream/main and your branch by executing ``git pull upstream main`` locally. If this generates any merge conflicts, you need to resolve them and push an updated version of the branch to your fork of the repository.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:219\nmsgid \"Our pipeline consists of a series of different tests that ensure that manim still works as intended and that the code you added sticks to our coding conventions.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:223\nmsgid \"**Code style**: We use the code style imposed by `Black <https://black.readthedocs.io/en/stable/>`_, `isort <https://pycqa.github.io/isort/>`_ and `flake8 <https://flake8.pycqa.org/en/latest/>`_. The GitHub pipeline makes sure that the (Python) files changed in your pull request also adhere to this code style. If this step of the pipeline fails, fix your code formatting automatically by running ``black <file or directory>`` and ``isort <file or directory>``. To fix code style problems, run ``flake8 <file or directory>`` for a style report, and then fix the problems manually that were detected by ``flake8``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:232\nmsgid \"**Tests**: The pipeline runs manim's test suite on different operating systems (the latest versions of Ubuntu, MacOS, and Windows) for different versions of Python. The test suite consists of two different kinds of tests: integration tests and doctests. You can run them locally by executing ``poetry run pytest`` and ``poetry run pytest --doctest-modules manim``, respectively, from the root directory of your cloned fork.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:239\nmsgid \"**Documentation**: We also build a version of the documentation corresponding to your pull request. Make sure not to introduce any Sphinx errors, and have a look at the built HTML files to see whether the formatting of the documentation you added looks as you intended. You can build the documentation locally by running ``make html`` from the ``docs`` directory. Since the inheritance diagrams require you to have `Graphviz <https://graphviz.org/>`_ installed locally.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:246\nmsgid \"Finally, if the pipeline passes and you are satisfied with your changes: wait for feedback and iterate over any requested changes. You will likely be asked to edit or modify your PR in one way or another during this process. This is not an indictment of your work, but rather a strong signal that the community wants to merge your changes! Once approved, your changes may be merged!\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:253\nmsgid \"Further useful guidelines\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:255\nmsgid \"When submitting a PR, please mention explicitly if it includes breaking changes.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:257\nmsgid \"When submitting a PR, make sure that your proposed changes are as general as possible, and ready to be taken advantage of by all of manim's users. In particular, leave out any machine-specific configurations, or any personal information it may contain.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:262\nmsgid \"If you are a maintainer, please label issues and PRs appropriately and frequently.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:265\nmsgid \"When opening a new issue, if there are old issues that are related, add a link to them in your new issue (even if the old ones are closed).\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:268\nmsgid \"When submitting a code review, it is highly recommended that you adhere to `these general guidelines <https://conventionalcomments.org/>`_.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:271\nmsgid \"If you find stale or inactive issues that seem to be irrelevant, please post a comment saying 'This issue should be closed', and a community developer will take a look.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:275\nmsgid \"Please do as much as possible to keep issues, PRs, and development in general as tidy as possible.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:279\nmsgid \"You can find examples for the ``docs`` in several places: the :doc:`Example Gallery <../examples>`, :doc:`Tutorials <../tutorials/index>`, and :doc:`Reference Classes <../reference>`.\"\nmsgstr \"\"\n\n#: ../../source/contributing/development.rst:283\nmsgid \"In case you are contributing, please have a look at this flowchart:\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/contributing/docstrings.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/contributing/docstrings.rst:3\nmsgid \"Adding Docstrings\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:5\nmsgid \"A docstring is a string literal that is used right after the definition of a module, function, class, or method. They are used to document our code. This page will give you a set of guidelines to write efficient and correct docstrings.\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:11\nmsgid \"Formatting the Docstrings\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:13\nmsgid \"Please begin the description of the class/function in the same line as the 3 quotes:\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:31\nmsgid \"NumPy Format\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:32\nmsgid \"The Manim Community uses numpy format for the documentation.\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:34\nmsgid \"Use the numpy format for sections and formatting - see https://numpydoc.readthedocs.io/en/latest/format.html.\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:37\nmsgid \"This includes:\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:39\nmsgid \"The usage of ``Attributes`` to specify ALL ATTRIBUTES that a class can have and a brief (or long, if needed) description.\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:43\nmsgid \"Also, ``__init__`` parameters should be specified as ``Parameters`` **on the class docstring**, *rather than under* ``__init__``. Note that this can be omitted if the parameters and the attributes are the same (i.e., dataclass) - priority should be given to the ``Attributes`` section, in this case, which must **always be present**, unless the class specifies no attributes at all. (See more on Parameters in number 2 of this list.)\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:51\n#: ../../source/contributing/docstrings.rst:151\nmsgid \"Example:\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:83\nmsgid \"The usage of ``Parameters`` on functions to specify how every parameter works and what it does. This should be excluded if the function has no parameters. Note that you **should not** specify the default value of the parameter on the type. On the documentation render, this is already specified on the function's signature. If you need to indicate a further consequence of value omission or simply want to specify it on the docs, make sure to **specify it in the parameter's DESCRIPTION**.\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:92\n#: ../../source/contributing/docstrings.rst:128\nmsgid \"See an example on list item 4.\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:96\nmsgid \"When documenting varargs (args and kwargs), make sure to document them by listing the possible types of each value specified, like this:\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:109\nmsgid \"Note that, if the kwargs expect specific values, those can be specified in a section such as ``Other Parameters``:\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:120\nmsgid \"The usage of ``Returns`` to indicate what is the type of this function's return value and what exactly it returns (i.e., a brief - or long, if needed - description of what this function returns). Can be omitted if the function does not explicitly return (i.e., always returns ``None`` because ``return`` is never specified, and it is very clear why this function does not return at all). In all other cases, it should be specified.\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:130\nmsgid \"The usage of ``Examples`` in order to specify an example of usage of a function **is highly encouraged** and, in general, should be specified for *every function* unless its usage is **extremely obvious**, which can be debatable. Even if it is, it's always a good idea to add an example in order to give a better orientation to the documentation user. Use the following format for Python code:\"\nmsgstr \"\"\n\n#: ../../source/contributing/docstrings.rst:144\nmsgid \"Also, if this is a video- or animation-related change, please try to add an example GIF or video if possible for demonstration purposes.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/contributing/examples.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/contributing/examples.rst:3\nmsgid \"Adding Examples\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:5\nmsgid \"This is a page for adding examples to the documentation. Here are some guidelines you should follow before you publish your examples.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:9\nmsgid \"Guidelines for examples\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:11\nmsgid \"Everybody is welcome to contribute examples to the documentation. Since straightforward examples are a great resource for quickly learning manim, here are some guidelines.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:15\nmsgid \"What makes a great example\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:19\nmsgid \"As soon as a new version of manim is released, the documentation will be a snapshot of that version. Examples contributed after the release will only be shown in the latest documentation.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:22\nmsgid \"Examples should be ready to copy and paste for use.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:24\nmsgid \"Examples should be brief yet still easy to understand.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:26\nmsgid \"Examples don't require the ``from manim import *`` statement, this will be added automatically when the docs are built.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:28\nmsgid \"There should be a balance of animated and non-animated examples.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:30\nmsgid \"As manim makes animations, we can include lots of animated examples; however, our RTD has a maximum 20 minutes to build. Animated examples should only be used when necessary, as last frame examples render faster.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:32\nmsgid \"Lots of examples (e.g. size of a plot-axis, setting opacities, making texts, etc.) will also work as images. It is a lot more convenient to see the end product immediately instead of waiting for an animation to reveal it.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:34\nmsgid \"Please ensure the examples run on the current main branch when you contribute an example.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:36\nmsgid \"If the functions used are confusing for people, make sure to add comments in the example to explain what they do.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:39\nmsgid \"How examples are structured\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:41\nmsgid \"Examples can be organized into chapters and subchapters.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:43\nmsgid \"When you create examples, the beginning example chapter should focus on only one functionality. When the functionality is simple, multiple ideas can be illustrated under a single example.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:45\nmsgid \"As soon as simple functionalities are explained, the chapter may include more complex examples which build on the simpler ideas.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:48\nmsgid \"Writing examples\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:50\nmsgid \"When you want to add/edit examples, they can be found in the ``docs/source/`` directory, or directly in the manim source code (e.g. ``manim/mobject/mobject.py``). The examples are written in ``rst`` format and use the manim directive (see :mod:`manim.utils.docbuild.manim_directive` ), ``.. manim::``. Every example is in its own block, and looks like this:\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:67\nmsgid \"In the building process of the docs, all ``rst`` files are scanned, and the manim directive (``.. manim::``) blocks are identified as scenes that will be run by the current version of manim. Here is the syntax:\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:72\nmsgid \"``.. manim:: [SCENE_NAME]`` has no indentation and ``SCENE_NAME`` refers to the name of the class below.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:74\nmsgid \"The flags are followed in the next line (no blank line here!), with the indentation level of one tab.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:76\nmsgid \"All possible flags can be found at :mod:`manim.utils.docbuild.manim_directive`.\"\nmsgstr \"\"\n\n#: ../../source/contributing/examples.rst:78\nmsgid \"In the example above, the ``Formula1`` following ``.. manim::`` is the scene that the directive expects to render; thus, in the python code, the class has the same name: ``class Formula1(Scene)``.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/contributing/internationalization.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/contributing/internationalization.rst:3\nmsgid \"Internationalization\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:5\nmsgid \"Thank you for your interest in localizing Manim! Please read the instructions below to get started. You are also encouraged, though not required, to join our `Discord server <https://manim.community/discord>`__.\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:11\nmsgid \"Signing up\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:13\nmsgid \"You will first need to create an account for our project. Go to our `project homepage <https://translate.manim.community/>`__ and click the sign up button at the top right hand corner. Follow the instructions to create an account. After creating an account, you should return back to our homepage. Click the Manim project to contribute translations for the main library.\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:21\nmsgid \"Contributing\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:24\nmsgid \"Keep in mind that Manim is still a work in progress. Tutorials and documentation are always subject to change. When a developer implements a new feature, they are not forced to respect any translations. This means that parts of the translation might become outdated over time.\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:29\nmsgid \"That being said, improving the documentation and making it more accessible is still highly encouraged. And even if your work gets outdated and requires change, you or someone else can simply adjust the translation. Your efforts are not in vail!\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:35\nmsgid \"Voting\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:37\nmsgid \"To ensure that our translations are of good quality, we use crowdsourcing and voting to approve good translations and reject bad ones. The current threshold for a translation being accepted is 3 votes; this may change as we gauge the level of activity in the community and the quality of translations.\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:43\nmsgid \"To vote on translations, first click on a language you would like to help with, then click the \\\"translate all\\\" button. You should then enter the translation editor. Next to the search bar, you will see a funnel-like icon - click it and select the \\\"Need to Be Voted\\\" option to see translations that need to be voted on. You can then select a string on the left sidebar, view the translations at the bottom and vote with the + and - icons for good and poor translations respectively.\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:52\nmsgid \"Translations\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:54\nmsgid \"You can also help with contributing translations directly. Follow the steps above to enter the translation editor (instead of clicking \\\"Translate all\\\", you may also choose to translate strings from a specific file by clicking them). Crowdin's on-screen tutorial should guide you through the process.\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:61\nmsgid \"Translation guidelines\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:63\nmsgid \"In general, follow the conventions for technical writing in your target language. You may want to refer to similar, high quality sources (eg. Python's documentation in your language) for guidance. Note that code blocks, code literals, names and pseudonyms should be left unchanged.\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:69\nmsgid \"Proofreading\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:71\nmsgid \"For certain languages with a significant number of speakers within the Manim Community, an additional step of proofreading is used after crowdsourcing to further ensure the quality of our translations. Proofreaders are trusted community members who will look over and give the final approval on translations. If you would like to be a proofreader, please email translations@manim.community with the answers to the following questions:\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:79\nmsgid \"What is your Crowdin username?\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:80\nmsgid \"What is your Discord username (optional)?\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:81\nmsgid \"What is your GitHub username (optional)?\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:82\nmsgid \"List the languages you speak, and your level of fluency with them.\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:83\nmsgid \"What language(s) are you applying to be a proofreader for?\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:84\nmsgid \"Do you have any previous experience with translations?\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:85\nmsgid \"If yes, give us more details.\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:86\nmsgid \"How will you ensure the quality of translations, should you become a proofreader?\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:89\nmsgid \"Please note that you don't need to have prior translation experience to be a proofreader, just a commitment to maintaining a good quality of translations.\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:94\nmsgid \"Errors\"\nmsgstr \"\"\n\n#: ../../source/contributing/internationalization.rst:97\nmsgid \"Source errors\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/contributing/performance.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/contributing/performance.rst:3\nmsgid \"Improving performance\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:5\nmsgid \"One of Manim's main flaws as an animation library is its slow performance. As of time of writing (January 2022), the library is still very unoptimized. As such, we highly encourage contributors to help out in optimizing the code.\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:10\nmsgid \"Profiling\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:12\nmsgid \"Before the library can be optimized, we first need to identify the bottlenecks in performance via profiling. There are numerous Python profilers available for this purpose; some examples include cProfile and Scalene.\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:17\nmsgid \"Running an animation as a script\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:19\nmsgid \"Most instructions for profilers assume you can run the python file directly as a script from the command line. While Manim animations are usually run from the command-line, we can run them as scripts by adding something like the following to the bottom of the file:\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:30\nmsgid \"Where ``SceneName`` is the name of the scene you want to run. You can then run the file directly, and can thus follow the instructions for most profilers.\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:34\nmsgid \"An example: profiling with cProfile and SnakeViz\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:36\nmsgid \"Install SnakeViz:\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:42\nmsgid \"cProfile is included with in Python's standard library and does not need to be installed.\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:44\nmsgid \"Suppose we want to profile ``SquareToCircle``. Then we add and save the following code to ``square_to_circle.py``:\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:64\nmsgid \"Now run the following in the terminal:\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:70\nmsgid \"This will create a file called ``square_to_circle.txt``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/performance.rst:72\nmsgid \"Now, we can run SnakeViz on the profile file:\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/contributing/references.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/contributing/references.rst:3\nmsgid \"Adding References\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:6\nmsgid \"Reference to types in documentation\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:8\nmsgid \"Always specify types with the correct **role** (see https://www.sphinx-doc.org/en/1.7/domains.html#python-roles) for the sake of proper rendering. E.g.: Use ``:class:`int``` to refer to an int type, and in general ``:class:`<path>`​`` to refer to a certain class (see ``Path specification`` below). See after for more specific instructions.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:16\nmsgid \"Path specifications\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:18\nmsgid \"If it's on stdlib: Use ``<name>`` directly. If it's a class, just the name is enough. If it's a method (``:meth:``) or attribute (``:attr:``), dotted names may be used (e.g. ``:meth:`str.to_lower`​``).\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:23\nmsgid \"Example: ``:class:`int`​``, ``:class:`str`​``, ``:class:`float`​``, ``:class:`bool`​``\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:26\nmsgid \"If it's on the same file as the docstring or, for methods and attributes, under the same class, then the name may also be specified directly.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:30\nmsgid \"Example: ``:class:`MyClass`​`` referring to a class in the same file; ``:meth:`push`​`` referring to a method in the same class; ``:meth:`MyClass.push`​`` referring to a method in a different class in the same file; ``:attr:`color`​`` referring to an attribute in the same class; ``:attr:`MyClass.color`​`` referring to an attribute in a different class in the same file.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:37\nmsgid \"If it's on a different file, then you may either use the full dotted name (e.g. ``~manim.animations.Animation``) or simply use the shortened way (``~.Animation``). Note that, if there is ambiguity, then the full dotted name must be used where the actual class can't be deduced. Also, note the ``~`` before the path - this is so that it displays just ``Animation`` instead of the full location in the rendering. It can be removed for disambiguation purposes only.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:45\nmsgid \"Example: ``:class:`~.Animation`​``, ``:meth:`~.VMobject.set_color`​``, ``:attr:`~.VMobject.color`​``\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:48\nmsgid \"If it's a class from a different module, specify the full dotted syntax.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:51\nmsgid \"Example: ``:class:`numpy.ndarray`​`` for a numpy ndarray.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:54\nmsgid \"Reference type specifications\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:56\nmsgid \"**The following instructions refer to types of attributes, parameters, and return values.** When specifying a type mid-text, it does not necessarily have to be typeset. However, if it's a class name, a method, or an enum's attribute/variant, then it is recommended to be typeset at least on the first occurrence of the name so that the users can quickly jump to the related documentation.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:63\nmsgid \"Class names should be wrapped in ``:class:`path_goes_here`​``. See examples in the subsection above.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:65\nmsgid \"Method names should be wrapped in ``:meth:`path_goes_here`​``. See examples in the subsection above.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:67\nmsgid \"Attribute names should be wrapped in ``:attr:`path_goes_here`​``. See examples in the subsection above.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:69\nmsgid \"If ``None`` can also be specified, use ``Optional[type]``, where ``type`` must follow the guidelines in the current section.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:72\nmsgid \"Example: ``Optional[:class:`str`]`` means you can either specify a ``str`` or ``None``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:75\nmsgid \"If more than one type is possible, use ``Union[type_1, type_2, (...), type_n]``, where all the ``type_n`` must follow the guidelines in the current section. Note that, if one of these types is ``None``, then the Union should be wrapped with ``Optional`` instead.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:81\nmsgid \"Example: ``Union[:class:`str`, :class:`int`]`` for either ``str`` or ``int``. ``Optional[Union[:class:`int`, :class:`bool`]]`` for either ``int``, ``bool`` or ``None``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:85\nmsgid \"**Dictionaries:** Use ``Dict[key_type, value_type]``, where ``key_type`` and ``value_type`` must follow the guidelines in the current section.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:89\nmsgid \"Example: ``Dict[:class:`str`, :class:`~.Mobject`]`` is a dictionary that maps strings to Mobjects. ``Dict[:class:`str`, Union[:class:`int`, :class:`MyClass`]]`` is a dictionary that maps a string to either an int or an instance of ``MyClass``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:95\nmsgid \"**If the parameter is a list:** Note that it is very rare to require the parameter to be exactly a ``list`` type. One could usually specify a ``tuple`` instead, for example. So, in order to cover all cases, consider:\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:100\nmsgid \"If the parameter only needs to be an ``Iterable``, i.e., if the function only requires being able to iterate over this parameter's value (e.g. can be a ``list``, ``tuple``, ``str``, but also ``zip()``, ``iter()`` and so on), then specify ``Iterable[type_here]``, where ``type_here`` is the type of the iterable's yielded elements and should follow the format in the present section (``Type specifications``).\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:108\nmsgid \"Example: ``Iterable[:class:`str`]`` for any iterable of strings; ``Iterable[:class:`~.Mobject`]`` for an iterable of Mobjects; etc.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:111\nmsgid \"If you require being able to index the parameter (i.e. ``x[n]``) or retrieve its length (i.e. ``len(x)``), or even just pass it to a function that requires any of those, then specify ``Sequence``, which allows any list-like object to be specified (e.g. ``list``, ``tuple``...)\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:117\nmsgid \"Example: ``Sequence[:class:`str`]`` for a sequence of strings; ``Sequence[Union[:class:`str`, :class:`int`]]`` for a sequence of integers or strings.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:121\nmsgid \"If you EXPLICITLY REQUIRE it to be a ``list`` for some reason, then use ``List[type]``, where ``type`` is the type that any element in the list will have. It must follow the guidelines in the current section.\"\nmsgstr \"\"\n\n#: ../../source/contributing/references.rst:126\nmsgid \"**If the return type is a list or tuple:** Specify ``List[type]`` for a list, ``Tuple[type_a, type_b, (...), type_n]`` for a tuple (if the elements are all different) or ``Tuple[type, ...]`` (if all elements have the same type). Each ``type_n`` on those representations corresponds to elements in the returned list/tuple and must follow the guidelines in the current section.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/contributing/testing.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/contributing/testing.rst:3\nmsgid \"Adding Tests\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:4\nmsgid \"If you are adding new features to manim, you should add appropriate tests for them. Tests prevent manim from breaking at each change by checking that no other feature has been broken and/or been unintentionally modified.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:9\nmsgid \"How Manim tests\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:11\nmsgid \"Manim uses pytest as its testing framework. To start the testing process, go to the root directory of the project and run pytest in your terminal. Any errors that occur during testing will be displayed in the terminal.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:15\nmsgid \"Some useful pytest flags:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:17\nmsgid \"``-x`` will make pytest stop at the first failure it encounters\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:19\nmsgid \"``-s`` will make pytest display all the print messages (including those during scene generation, like DEBUG messages)\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:21\nmsgid \"``--skip_slow`` will skip the (arbitrarily) slow tests\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:23\nmsgid \"``--show_diff`` will show a visual comparison in case a unit test is failing.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:27\nmsgid \"How it Works\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:29\nmsgid \"At the moment there are three types of tests:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:31\nmsgid \"Unit Tests:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:33\nmsgid \"Tests for most of the basic functionalities of manim. For example, there a test for ``Mobject``, that checks if it can be added to a Scene, etc.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:36\nmsgid \"Graphical unit tests: Because ``manim`` is a graphics library, we test frames. To do so, we create test scenes that render a specific feature. When pytest runs, it compares the result of the test to the control data, either at 6 fps or just the last frame. If it matches, the tests pass. If the test and control data differ, the tests fail. You can use ``--show_diff`` flag with ``pytest`` to visually see the differences.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:42\nmsgid \"Videos format tests:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:44\nmsgid \"As Manim is a video library, we have to test videos as well. Unfortunately, we cannot directly test video content as rendered videos can differ slightly depending on the system (for reasons related to ffmpeg). Therefore, we only compare video configuration values, exported in .json.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:51\nmsgid \"Architecture\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:53\nmsgid \"The ``manim/tests`` directory looks like this:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:122\nmsgid \"The Main Directories\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:124\nmsgid \"``control_data/``:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:126\nmsgid \"The directory containing control data. ``control_data/graphical_units_data/`` contains the expected and correct frame data for graphical tests, and ``control_data/videos_data/`` contains the .json files used to check videos.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:129\nmsgid \"``test_graphical_units/``:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:131\nmsgid \"Contains graphical tests.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:133\nmsgid \"``test_scene_rendering/``:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:135\nmsgid \"For tests that need to render a scene in some way, such as tests for CLI flags (end-to-end tests).\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:138\nmsgid \"``utils/``:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:140\nmsgid \"Useful internal functions used by pytest.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:142\nmsgid \"fixtures are not contained here, they are in ``conftest.py``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:144\nmsgid \"``helpers/``:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:146\nmsgid \"Helper functions for developers to setup graphical/video tests.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:149\nmsgid \"Adding a New Test\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:152\nmsgid \"Unit Tests\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:154\nmsgid \"Pytest determines which functions are tests by searching for files whose names begin with \\\"test\\\\_\\\", and then within those files for functions beginning with \\\"test\\\" and classes beginning with \\\"Test\\\". These kinds of tests must be in ``tests/`` (e.g. ``tests/test_container.py``).\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:160\nmsgid \"Graphical Unit Test\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:162\nmsgid \"The test must be written in the correct file (i.e. the file that corresponds to the appropriate category the feature belongs to) and follow the structure of unit tests.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:165\nmsgid \"For example, to test the ``Circle`` VMobject which resides in ``manim/mobject/geometry.py``, add the CircleTest to ``test/test_geometry.py``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:169\nmsgid \"The name of the module is indicated by the variable __module_test__, that **must** be declared in any graphical test file. The module name is used to store the graphical control data.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:172\nmsgid \"You will need to use the ``frames_comparison`` decorator to create a test. The test function **must** accept a parameter named ``scene`` that will be used like ``self`` in a standard ``construct`` method.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:175\nmsgid \"Here's an example in ``test_geometry.py``:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:190\nmsgid \"The decorator can be used with or without parentheses. **By default, the test only tests the last frame. To enable multi-frame testing, you have to set ``last_frame=False`` in the parameters.**\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:199\nmsgid \"You can also specify, when needed, which base scene you need (ThreeDScene, for example) :\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:208\nmsgid \"Feel free to check the documentation of ``@frames_comparison`` for more.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:210\nmsgid \"Note that tests name must follow the syntax ``test_<thing_to_test>``, otherwise pytest will not recognize it as a test.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:213\nmsgid \"If you run pytest now, you will get a ``FileNotFound`` error. This is because you have not created control data for your test.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:216\nmsgid \"To create the control data for your test, you have to use the flag ``--set_test`` along with pytest. For the example above, it would be\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:223\nmsgid \"(``-s`` is here to see manim logs, so you can see what's going on).\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:225\nmsgid \"Please make sure to add the control data to git as soon as it is produced with ``git add <your-control-data.npz>``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:229\nmsgid \"Videos tests\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:231\nmsgid \"To test videos generated, we use the decorator ``tests.utils.videos_tester.video_comparison``:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:254\nmsgid \"``assert exit*\\\\ code == 0, err`` is used in case of the command fails to run. The decorator takes two arguments: json name and the path to where the video should be generated, starting from the ``media/`` dir.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:258\nmsgid \"Note the fixtures here:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:260\nmsgid \"tmp_path is a pytest fixture to get a tmp_path. Manim will output here, according to the flag ``--media_dir``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:262\nmsgid \"``manim_cfg_file`` fixture that return a path pointing to ``test_scene_rendering/standard_config.cfg``. It's just to shorten the code, in the case multiple tests need to use this cfg file.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:264\nmsgid \"``simple_scenes_path`` same as above, except for ``test_scene_rendering/simple_scene.py``\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:266\nmsgid \"You have to generate a ``.json`` file first to be able to test your video. To do that, use ``helpers.save_control_data_from_video``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:269\nmsgid \"For instance, a test that will check if the l flag works properly will first require rendering a video using the -l flag from a scene. Then we will test (in this case, SquareToCircle), that lives in ``test_scene_rendering/simple_scene.py``. Change directories to ``tests/``, create a file (e.g. ``create\\\\_data.py``) that you will remove as soon as you're done. Then run:\"\nmsgstr \"\"\n\n#: ../../source/contributing/testing.rst:280\nmsgid \"Running this will save ``control_data/videos_data/SquareToCircleWithlFlag.json``, which will look like this:\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/contributing/typings.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/contributing/typings.rst:3\nmsgid \"Adding Typings\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:6\nmsgid \"Adding type hints to functions and parameters\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:9\nmsgid \"This section is still a work in progress.\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:11\nmsgid \"If you've never used type hints before, this is a good place to get started: https://realpython.com/python-type-checking/#hello-types.\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:14\nmsgid \"When adding type hints to manim, there are some guidelines that should be followed:\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:16\nmsgid \"Coordinates have the typehint ``Sequence[float]``, e.g.\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:23\nmsgid \"``**kwargs`` has no typehint\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:25\nmsgid \"Mobjects have the typehint \\\"Mobject\\\", e.g.\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:33\nmsgid \"Colors have the typehint ``Color``, e.g.\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:40\nmsgid \"As ``float`` and ``Union[int, float]`` are the same, use only ``float``\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:42\nmsgid \"For numpy arrays use the typehint ``np.ndarray``\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:44\nmsgid \"Functions that does not return a value should get the type hint ``None``. (This annotations help catch the kinds of subtle bugs where you are trying to use a meaningless return value. )\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:51\nmsgid \"Parameters that are None by default should get the type hint ``Optional``\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:65\nmsgid \"The ``__init__()`` method always should have None as its return type.\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:67\nmsgid \"Functions and lambda functions should get the typehint ``Callable``\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:74\nmsgid \"Assuming that typical path objects are either Paths or strs, one can use the typehint ``typing.Union[str, pathlib.Path]``\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:77\nmsgid \"As a helper for tool for typesets, you can use `typestring-parser <https://github.com/Dominik1123/typestring-parser>`_ which can be accessed by first installing it via ``pip`` - ``pip install typestring-parser`` and then using ``from typestring_parser import parse``.\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:96\nmsgid \"Missing Sections for typehints are:\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:97\nmsgid \"Tools for typehinting\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:98\nmsgid \"Link to MyPy\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:99\nmsgid \"Mypy and numpy import errors: https://realpython.com/python-type-checking/#running-mypy\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:100\nmsgid \"Where to find the alias\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:101\nmsgid \"When to use Object and when to use \\\"Object\\\".\"\nmsgstr \"\"\n\n#: ../../source/contributing/typings.rst:102\nmsgid \"The use of a TypeVar on the type hints for copy().\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/contributing.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/contributing.rst:3\nmsgid \"Contributing\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:5\nmsgid \"Manim is currently undergoing a major refactor. In general, contributions implementing new features will not be accepted in this period. Other contributions unrelated to cleaning up the codebase may also take a longer period of time to be reviewed. This guide may quickly become outdated quickly; we highly recommend joining our `Discord server <https://www.manim.community/discord/>`__ to discuss any potential contributions and keep up to date with the latest developments.\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:12\nmsgid \"Thank you for your interest in contributing to Manim! However you have decided to contribute or interact with the community, please always be civil and respect other members of the community. If you haven't read our :doc:`code of conduct<conduct>`, do so here. Manim is Free and Open Source Software (FOSS) for mathematical animations. As such, **we welcome everyone** who is interested in mathematics, pedagogy, computer animations, open-source, software development, and beyond. Manim accepts many kinds of contributions, some are detailed below:\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:21\nmsgid \"Code maintenance and development\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:22\nmsgid \"DevOps\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:23\nmsgid \"Documentation\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:24\nmsgid \"Developing educational content & narrative documentation\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:25\nmsgid \"Plugins to extend Manim functionality\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:26\nmsgid \"Testing (graphical, unit & video)\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:27\nmsgid \"Website design and development\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:28\nmsgid \"Translating documentation and docstrings\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:30\nmsgid \"To get an overview of what our community is currently working on, check out `our development project board <https://github.com/orgs/ManimCommunity/projects/7/views/1>`__.\"\nmsgstr \"\"\n\n#: ../../source/contributing.rst:34\nmsgid \"Please ensure that you are reading the latest version of this guide by ensuring that \\\"latest\\\" is selected in the version switcher.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/examples.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/examples.rst:3\nmsgid \"Example Gallery\"\nmsgstr \"\"\n\n#: ../../source/examples.rst:5\nmsgid \"This gallery contains a collection of best practice code snippets together with their corresponding video/image output, illustrating different functionalities all across the library. These are all under the MIT license, so feel free to copy & paste them to your projects. Enjoy this taste of Manim!\"\nmsgstr \"\"\n\n#: ../../source/examples.rst:13\nmsgid \"This gallery is not the only place in our documentation where you can see explicit code and video examples: there are many more in our :doc:`reference manual </reference>` -- see, for example, our documentation for the modules :mod:`~.tex_mobject`, :mod:`~.geometry`, :mod:`~.moving_camera_scene`, and many more.\"\nmsgstr \"\"\n\n#: ../../source/examples.rst:19\nmsgid \"Check out our `interactive Jupyter environment <https://mybinder.org/v2/gh/ManimCommunity/jupyter_examples/HEAD?filepath=basic_example_scenes.ipynb>`_ which allows running the examples online, without requiring a local installation.\"\nmsgstr \"\"\n\n#: ../../source/examples.rst:23\nmsgid \"Also, visit our `Twitter <https://twitter.com/manim_community/>`_ for more *manimations*!\"\nmsgstr \"\"\n\n#: ../../source/examples.rst:29\nmsgid \"Basic Concepts\"\nmsgstr \"\"\n\n#: ../../source/examples.rst:134\nmsgid \"Animations\"\nmsgstr \"\"\n\n#: ../../source/examples.rst:216\nmsgid \"You can use multiple ValueTrackers simultaneously.\"\nmsgstr \"\"\n\n#: ../../source/examples.rst:310\nmsgid \"Plotting with Manim\"\nmsgstr \"\"\n\n#: ../../source/examples.rst:496\nmsgid \"Special Camera Settings\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/faq/general.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/faq/general.md:1\nmsgid \"FAQ: General Usage\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:3\nmsgid \"Why does Manim say that \\\"there are no scenes inside that module\\\"?\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:5\nmsgid \"There are two main reasons why this error appears: if you have edited the file containing your `Scene` class and forgot to save it, or if you have accidentally passed the name of a wrong file to `manim`, this is a likely outcome. Check that you have spelled everything correctly.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:10\nmsgid \"Otherwise you are likely mixing up Manim versions. See {ref}`this FAQ answer <different-versions>` for an explanation regarding why there are different versions. Under the assumption that you are trying to use the `manim` executable from the terminal to run a scene that has been written for the community version (i.e., there is `from manim import *`, or more specifically `from manim import Scene`)\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:18\nmsgid \"No matter what code I put in my file, Manim only renders a black frame! Why?\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:20\nmsgid \"If you are using the usual pattern to write a `Scene`, i.e.,\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:27\nmsgid \"then double check whether you have spelled `construct` correctly. If the method containing your code is not called `construct` (or if you are not calling a different, custom method from `construct`), Manim will not call your method and simply output a black frame.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:34\nmsgid \"What are the default measurements for Manim's scene?\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:36\nmsgid \"The scene measures 8 units in height and has a default ratio of 16:9, which means that it measures {math}`8 \\\\cdot 16 / 9 = 14 + 2/9` units in width. The origin is in the center of the scene, which means that, for example, the upper left corner of the scene has coordinates `[-7-1/9, 4, 0]`.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:43\nmsgid \"How do I find out which keyword arguments I can pass when creating a `Mobject`?\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:45\nmsgid \"Let us consider some specific example, like the {class}`.Circle` class. When looking at its documentation page, only two specific keyword arguments are listed (`radius`, and `color`). Besides these concrete arguments, there is also a catchall `**kwargs` argument which captures all other arguments that are passed to `Circle`, and passes them on to the base class of {class}`.Circle`, {class}`.Arc`.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:51\nmsgid \"The same holds for {class}`.Arc`: some arguments are explicitly documented, and there is again a catchall `**kwargs` argument that passes unprocessed arguments to the next base class -- and so on.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:55\nmsgid \"The most important keyword arguments relevant to styling your mobjects are the ones that are documented for the base classes {class}`.VMobject` and {class}`.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:61\nmsgid \"Can Manim render a video with transparent background?\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:63\nmsgid \"Yes: simply pass the CLI flag `-t` (or its long form `--transparent`). Note that the default video file format does not support transparency, which is why Manim will output a `.mov` instead of a `.mp4` when rendering with a transparent background. Other movie file formats that support transparency can be obtained by passing `--format=webm` or `--format=gif`.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:72\nmsgid \"I have watched a video where a creator ran command X, but it does not work for me. Why?\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:74\nmsgid \"The video you have been watching is likely outdated. If you want to follow along, you either need to use the same version used in the video, or modify the code (in many cases it is just a method having been renamed etc.) accordingly. Check the video description, in some cases creators point out whether changes need to be applied to the code shown in the video.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:82\nmsgid \"When using `Tex` or `MathTex`, some letters are missing. How can I fix this?\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:84\nmsgid \"It is possible that you have to (re)build some fonts used by LaTeX. For some distributions, you can do this manually by running\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:89\nmsgid \"We recommend consulting the documentation of your LaTeX distribution for more information.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:94\nmsgid \"I want to translate some code from `manimgl` to `manim`, what do I do with `CONFIG` dictionaries?\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:96\nmsgid \"The community maintained version has dropped the use of `CONFIG` dictionaries very early, with {doc}`version v0.2.0 </changelog/0.2.0-changelog>` released in January 2021.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:100\nmsgid \"Before that, Manim's classes basically processed `CONFIG` dictionaries by mimicking inheritance (to properly process `CONFIG` dictionaries set by parent classes) and then assigning all of the key-value-pairs in the dictionary as attributes of the corresponding object.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:105\nmsgid \"In situations where there is not much inheritance going on, or for any custom setting, you should set these attributes yourself. For example, for an old-style `Scene` with custom attributes like\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:114\nmsgid \"should be written as\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:122\nmsgid \"In situations where values should be properly inherited, the arguments should be added to the initialization function of the class. An old-style mobject `Thing` could look like\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:135\nmsgid \"where `stroke_color` and `fill_opacity` are arguments that concern the parent class of `Thing`, and `my_awesome_argument` is a custom argument that only concerns `Thing`. A version without `CONFIG` could look like this:\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:150\nmsgid \"My installation does not support converting PDF to SVG, help?\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:152\nmsgid \"This is an issue with `dvisvgm`, the tool shipped with LaTeX that transforms LaTeX output to a `.svg` file that Manim can parse.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:156\nmsgid \"First, make sure your ``dvisvgm`` version is at least 2.4 by checking the output of\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:163\nmsgid \"If you do not know how to update `dvisvgm`, please refer to your LaTeX distributions documentation (or the documentation of your operating system, if `dvisvgm` was installed as a system package).\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:167\nmsgid \"Second, check whether your ``dvisvgm`` supports PostScript specials. This is needed to convert from PDF to SVG. Run:\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:174\nmsgid \"If the output to this command does **not** contain `ps  dvips PostScript specials`, this is a bad sign. In this case, run\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:181\nmsgid \"If the output does **not** contain `--libgs=filename`, this means your `dvisvgm` does not currently support PostScript. You must get another binary.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:184\nmsgid \"If, however, `--libgs=filename` appears in the help, that means that your `dvisvgm` needs the Ghostscript library to support PostScript. Search for `libgs.so` (on Linux, probably in `/usr/local/lib` or `/usr/lib`) or `gsdll32.dll` (on 32-bit Windows, probably in `C:\\\\windows\\\\system32`) or `gsdll64.dll` (on 64-bit Windows, also probably in `C:\\\\windows\\\\system32`) or `libgsl.dylib` (on MacOS, probably in `/usr/local/lib` or `/opt/local/lib`). Please look carefully, as the file might be located elsewhere, e.g. in the directory where Ghostscript is installed.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:193\nmsgid \"When you have found the library, try (on MacOS or Linux)\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:200\nmsgid \"or (on Windows)\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:207\nmsgid \"You should now see `ps    dvips PostScript specials` in the output. Refer to your operating system's documentation to find out how you can set or export the environment variable ``LIBGS`` automatically whenever you open a shell.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:211\nmsgid \"As a last check, you can run\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:217\nmsgid \"(while still having `LIBGS` set to the correct path, of course.) If `dvisvgm` can find your Ghostscript installation, it will be shown in the output together with the version number.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:221\nmsgid \"If you do not have the necessary library on your system, please refer to your operating system's documentation to find out where you can get it and how you have to install it.\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:225\nmsgid \"If you are unable to solve your problem, check out the [dvisvgm FAQ](https://dvisvgm.de/FAQ/).\"\nmsgstr \"\"\n\n#: ../../source/faq/general.md:230\nmsgid \"Where can I find more resources for learning Manim?\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/faq/help.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/faq/help.md:1\nmsgid \"FAQ: Getting Help\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:3\nmsgid \"How do I animate X? Why do I get error Y? Can someone help me?\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:5\nmsgid \"Before asking the community, please make sure that the issue you are having is not already discussed in our {doc}`FAQ section </faq/index>` sufficiently well so that you can resolve the problem yourself. You can also try to use your favorite search engine, if you are lucky you might find a blog post, a question on [StackOverflow](https://stackoverflow.com/questions/tagged/manim), or a post in the [r/manim subreddit](https://reddit.com/r/manim).\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:12\nmsgid \"If this is not the case, please take a moment to properly prepare your question: the better you manage to explain what exactly it is you are struggling with, the more efficient people will be able to help you. Regardless of the platform you choose in the next step, StackOverflow has a good guide on [asking good questions](https://stackoverflow.com/help/how-to-ask).\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:18\nmsgid \"As soon as you have a good idea of what exactly you want to ask, pick one of the following communication channels:\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:21\nmsgid \"The community is most active [in our Discord server](https://manim.community/discord/). Click the link to join, then pick one of the `#manim-help` channels in the sidebar, and post your question there. If you are comfortable with using Discord, try to search for your problem using the search function of our server; perhaps people have been talking about it before!\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:26\nmsgid \"We are also monitoring questions on [StackOverflow](https://stackoverflow.com/questions/tagged/manim) that are tagged with `manim`.\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:29\nmsgid \"Many people are also active in our [r/manim subreddit](https://reddit.com/r/manim), feel free to post there if you are an avid Redditor -- but be aware that Discord or StackOverflow might be better choices.\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:32\nmsgid \"And finally, you can also start a new [discussion on GitHub](https://github.com/ManimCommunity/manim/discussions) if you dislike all other options.\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:35\nmsgid \"In all of these channels, please make sure to abide by Manim's {doc}`Code of Conduct </conduct>` -- in short, be *excellent* to one another: be friendly and patient, considerate, and respectful.\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:41\nmsgid \"What should I do if nobody answers my question?\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:43\nmsgid \"Try and see whether your question can be improved: did you include all relevant information (in case of errors: the full stack trace, the code that you were rendering, and the command you used to run Manim?). In case you used a very long example, is it possible to construct a more minimal version that has the same (faulty) behavior?\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:49\nmsgid \"If you posted in one of our help channels on Discord and your question got buried, you are allowed to ping the `@Manim Helper` role to bring it to the attention of the volunteers who are willing to take a look. Please refrain from pinging the role immediately when asking your question for the first time, this is considered impolite.\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:54\nmsgid \"You can also try to post your question to a different channel if you feel that you are not having any success with your initial choice -- but please do not spam your question in all of our communication channels (and in particular for Discord: please don't use multiple help channels at once).\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:59\nmsgid \"In the end, it is as for most open-source projects: our community members are volunteers. If you do not receive a quick answer to your question, it may be because nobody knows the answer, or because your question is not clear enough, or it could be that everyone who can help you with your problem is busy doing other things.\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:67\nmsgid \"The library does not behave as documented, or something broke in a new release. What should I do?\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:69\nmsgid \"Sounds like you have found a bug. One of the best ways of contributing to the development of Manim is by reporting it!\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:72\nmsgid \"Check our list of known issues and feature requests [in our GitHub repository](https://github.com/ManimCommunity/manim/issues). If the problem you have found is not listed there yet (use the search function; also check whether there is a corresponding closed issue, it is possible that your problem has already been resolved and will be fixed with the next release), please consider the following steps to submit a new issue.\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:80\nmsgid \"If you are unsure whether or not you should file a new issue for some odd behavior that you found, feel free to ask the community developers, preferably in one of our `#manim-dev` channels in [our Discord](https://manim.community/discord/).\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:85\nmsgid \"Make sure you are running the latest released version of Manim, your problem might otherwise already be fixed in a more recent version. Check the {doc}`/changelog` for a full list of changes between Manim releases.\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:89\nmsgid \"Choose the correct category for your report when [creating a new issue](https://github.com/ManimCommunity/manim/issues/new/choose). We have dedicated issue templates for *bug reports*, *feature requests*, and *installation issues*. If your report falls into one of these categories, read the issue template carefully! Instructions are given in the `<!-- ... -->` sections of the text field. If you want to suggest a new feature without concrete implementation details, see {ref}`the instructions given in this answer <creating-suggestions>`.\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:98\nmsgid \"For bug reports: prepare a minimal example that can be used to illustrate the issue. Examples with hundreds of lines are very inefficient and tedious to debug. Your problem needs to be reproducible for others, so please make sure to prepare a suitable example.\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:103\nmsgid \"This is mentioned in the bug report template as well, but it is very important: if you report that some code raises an error, make sure to include the full terminal output, from the command you used to run the library up to and including the last line with the error message. Read carefully: if the message mentions that there is another relevant log file, include this other file as well!\"\nmsgstr \"\"\n\n#: ../../source/faq/help.md:112\nmsgid \"I have an idea for a really cool feature that should be implemented, where should I share my idea?\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/faq/index.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/faq/index.rst:4\n#: ../../source/faq/index.rst:4\nmsgid \"Table of Contents\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/faq/installation.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/faq/installation.md:1\nmsgid \"FAQ: Installation\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:4\nmsgid \"Why are there different versions of Manim?\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:6\nmsgid \"Manim was originally created by Grant Sanderson as a personal project and for use in his YouTube channel, [3Blue1Brown](https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw). As his channel gained popularity, many grew to like the style of his animations and wanted to use manim for their own projects. However, as manim was only intended for personal use, it was very difficult for other users to install and use it.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:13\nmsgid \"In late 2019, Grant started working on faster OpenGL rendering in a new branch, known as the `shaders` branch. In mid-2020, a group of developers forked it into what is now the community edition; this is the version documented on this website. In early 2021, Grant merged the shaders branch back into master, making it the default branch in his repository -- and this is what `manimgl` is. The old version, before merging the `shaders` branch is sometimes referred to as `ManimCairo` and is, at this point, only useful for one singular purpose: rendering Grant's old videos locally on your machine. It is still available in his GitHub repository in form of the `cairo-backend` branch.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:22\nmsgid \"To summarize:\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:23\nmsgid \"[**Manim**, or **ManimCE**](https://manim.community) refers to the community maintained version of the library. This is the version documented on this website; the package name on PyPI is [`manim`](https://pypi.org/project/manim/).\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:26\nmsgid \"[ManimGL](https://github.com/3b1b/manim) is the latest released version of the version of the library developed by Grant \\\"3b1b\\\" Sanderson. It has more experimental features and breaking changes between versions are not documented. Check out its documentation [here](https://3b1b.github.io/manim/index.html); on PyPI the package name is [`manimgl`](https://pypi.org/project/manimgl/).\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:31\nmsgid \"[ManimCairo](https://github.com/3b1b/manim/tree/cairo-backend) is the name that is sometimes used for the old, pre-OpenGL version of `manimgl`. The latest version of it is available [on PyPI as `manimlib`](https://pypi.org/project/manimgl/), but note that if you intend to use it to compile some old project of Grant, you will likely have to install the exact version from the time the project was created from source.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:40\nmsgid \"Which version should I use?\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:42\nmsgid \"We recommend the community maintained version especially for beginners. It has been developed to be more stable, better tested and documented (!), and quicker to respond to community contributions. It is also perfectly reasonable to start learning with the community maintained version and then switch to a different version later on.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:47\nmsgid \"If you do not care so much about documentation or stability, and would like to use the exact same version that Grant is using, then use ManimGL.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:50\nmsgid \"And as mentioned above, ManimCairo should only be used for (re)rendering old 3Blue1Brown projects (basically 2019 and before).\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:55\nmsgid \"What are the differences between Manim, ManimGL, ManimCairo? Can I tell for which version a scene was written for?\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:57\nmsgid \"You can! The thing that usually gives it away is the `import` statement at the top of the file; depending on how the code imports Manim you can tell for which version of the code it was written for:\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:61\nmsgid \"If the code imports from `manim` (i.e., `from manim import *`, `import manim as mn`, etc.), then the code you are reading is supposed to be run with the community maintained version.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:63\nmsgid \"If the import reads `import manimlib` (or `from manimlib import *`), you are likely reading a file to be rendered with ManimGL.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:65\nmsgid \"And if the import reads `from manimlib.imports import *`, or perhaps even `from big_ol_pile_of_manim_imports import *` you are reading a snippet that is supposed to be rendered with an early, or very early version of ManimCairo, respectively.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:71\nmsgid \"How do I know which version of Manim I have installed?\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:73\nmsgid \"Assuming you can run `manim` in your terminal and there is some output, check the first line of the text being produced. If you are using the community maintained version, the first line of any output will be `Manim Community <version number>`. If it does not say that, you are likely using ManimGL.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:78\nmsgid \"You can also check the list of packages you have installed: if typing `python` in your terminal spawns the interpreter that corresponds to the Python installation you use (might also be `py`, or `python3`, depending on your operating system), running `python -m pip list` will print a list of all installed packages. Check whether `manim` or `manimgl` appear in that list.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:84\nmsgid \"Similarly, you can use `python -m pip install <package name>` and `python -m pip uninstall <package name>` to install and uninstall packages from that list, respectively.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:90\nmsgid \"I am following the video guide X to install Manim, but some step fails. What do I do?\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:92\nmsgid \"It is only natural that there are many video guides on installing Manim out there, given that Manim is a library used for creating videos. Unfortunately however, (YouTube) videos can't be updated easily (without uploading a new one, that is) when some step in the installation process changes, and so there are many **severely outdated** resources out there.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:98\nmsgid \"This is why we strongly recommend following our {doc}`written installation guide </installation>` to guide you through the process. In case you prefer using a video guide regardless, please check whether the creator whose guide you have been watching has made a more recent version available, and otherwise please contact them directly. Asking for help in the community will likely lead to being suggested to follow our written guide.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:107\nmsgid \"Why does ManimPango fail to install when running `pip install manim`?\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:109\nmsgid \"This most likely means that pip was not able to use our pre-built wheels of the `manimpango` dependency. Let us know (via [Discord](https://www.manim.community/discord/) or by opening a [new issue on GitHub](https://github.com/ManimCommunity/ManimPango/issues/new)) which architecture you would like to see supported, and we'll see what we can do about it.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:116\nmsgid \"To fix errors when installing `manimpango`, you need to make sure you have all the necessary build requirements. Check out the detailed instructions given in [the BUILDING section](https://github.com/ManimCommunity/ManimPango#BUILDING) of [ManimPango's README](https://github.com/ManimCommunity/ManimPango).\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:123\nmsgid \"I am using Windows and get the error `X is not recognized as an internal or external command, operable program or batch file`\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:125\nmsgid \"Regardless of whether `X` says `python` or `manim`, this means that the executable you are trying to run is not located in one of the directories your system is looking for them (specified by the `PATH` variable). Take a look at the instructions {doc}`in the installation guide for Windows </installation/windows>`, or [this StackExchange answer](https://superuser.com/questions/143119/how-do-i-add-python-to-the-windows-path/143121#143121) to get help with editing the `PATH` variable manually.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:132\nmsgid \"If `python` is recognized but not `manim` or `pip`, you can try running commands by prepending `python -m`. That is, `manim` becomes `python -m manim`, and `pip` becomes `python -m pip`.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:138\nmsgid \"I have tried using Chocolatey (`choco install manimce`) to install Manim, but it failed!\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:140\nmsgid \"Make sure that you were running the command with administrator permissions, otherwise there can be problems. If this is not the issue, read Chocolatey's output carefully, it should mention a `.log` file containing information why the process failed.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:145\nmsgid \"You are welcome to take this file (and any other input you feel might be relevant) and submit it to Manim's community to ask for help with your problem. See the {doc}`FAQ on getting help </faq/help>` for instructions.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:151\nmsgid \"On Windows, when typing `python` or `python3` the Windows store is opened, can I fix this?\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:153\nmsgid \"Yes: you can remove these aliases with these steps:\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:155\nmsgid \"Go to the Windows Setting.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:156\nmsgid \"Under *Apps and Features* you will find application execution aliases.\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:157\nmsgid \"Within this menu, disable the alias(es) that are causing the issue (`python` and/or `python3`).\"\nmsgstr \"\"\n\n#: ../../source/faq/installation.md:162\nmsgid \"I am using Anaconda and get an `ImportError` mentioning that some Symbol is not found.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/faq/internals.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/faq/internals.md:1\nmsgid \"Where can I learn more about Manim's internal structure?\"\nmsgstr \"\"\n\n#: ../../source/faq/internals.md:3\nmsgid \"Efforts to document the internal structure of Manim is ongoing on our [wiki](https://github.com/ManimCommunity/manim/wiki/Developer-documentation-(WIP)).\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/faq/opengl.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/faq/opengl.md:1\nmsgid \"FAQ: OpenGL rendering\"\nmsgstr \"\"\n\n#: ../../source/faq/opengl.md:3\nmsgid \"Are there any resources on how the OpenGL renderer in the community maintained version can be used?\"\nmsgstr \"\"\n\n#: ../../source/faq/opengl.md:5\nmsgid \"Yes. Unfortunately, at this point, the official online documentation does not contain the relevant base classes like `OpenGLMobject` and `OpenGLVMobject` or specific OpenGL classes like `OpenGLSurface`, but documentation for some of them is available in form of docstrings [in the source code](https://github.com/ManimCommunity/manim/tree/main/manim/mobject/opengl).\"\nmsgstr \"\"\n\n#: ../../source/faq/opengl.md:11\nmsgid \"Furthermore, [this user guide by *aquabeam*](https://www.aquabeam.me/manim/opengl_guide/) can be helpful to get started using the OpenGL renderer.\"\nmsgstr \"\"\n\n#: ../../source/faq/opengl.md:16\nmsgid \"I am trying to run an interactive scene with `--renderer=opengl` and `Scene.interactive_embed`, but an error (`sqlite3.ProgrammingError`) is raised. How can I fix this?\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/guides/configuration.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/guides/configuration.rst:2\nmsgid \"Configuration\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:4\nmsgid \"Manim provides an extensive configuration system that allows it to adapt to many different use cases.  There are many configuration options that can be configured at different times during the scene rendering process.  Each option can be configured programmatically via `the ManimConfig class`_, at the time of command invocation via `command-line arguments`_, or at the time the library is first imported via `the config files`_.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:11\nmsgid \"The most common, simplest, and recommended way to configure Manim is via the command-line interface (CLI), which is described directly below.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:15\nmsgid \"Command-line arguments\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:17\nmsgid \"By far the most commonly used command in the CLI is the ``render`` command, which is used to render scene(s) to an output file. It is used with the following arguments:\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:24\nmsgid \"However, since Manim defaults to the :code:`render` command whenever no command is specified, the following form is far more common and can be used instead:\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:31\nmsgid \"An example of using the above form is:\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:37\nmsgid \"This asks Manim to search for a Scene class called :code:`SceneOne` inside the file ``file.py`` and render it with medium quality (specified by the ``-qm`` flag).\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:40\nmsgid \"Another frequently used flag is ``-p`` (\\\"preview\\\"), which makes manim open the rendered video after it's done rendering.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:43\nmsgid \"The ``-p`` flag does not change any properties of the global ``config`` dict.  The ``-p`` flag is only a command-line convenience.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:47\nmsgid \"Advanced examples\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:49\nmsgid \"To render a scene in high quality, but only output the last frame of the scene instead of the whole video, you can execute\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:56\nmsgid \"The following example specifies the output file name (with the :code:`-o` flag), renders only the first ten animations (:code:`-n` flag) with a white background (:code:`-c` flag), and saves the animation as a ``.gif`` instead of as a ``.mp4`` file (``--format=gif`` flag).  It uses the default quality and does not try to open the file after it is rendered.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:67\nmsgid \"A list of all CLI flags\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:75\nmsgid \"The ManimConfig class\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:77\nmsgid \"The most direct way of configuring Manim is through the global ``config`` object, which is an instance of :class:`.ManimConfig`.  Each property of this class is a config option that can be accessed either with standard attribute syntax or with dict-like syntax:\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:88\nmsgid \"The former is preferred; the latter is provided for backwards compatibility.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:91\nmsgid \"Most classes, including :class:`.Camera`, :class:`.Mobject`, and :class:`.Animation`, read some of their default configuration from the global ``config``.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:103\nmsgid \":class:`.ManimConfig` is designed to keep internal consistency.  For example, setting ``frame_y_radius`` will affect ``frame_height``:\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:114\nmsgid \"The global ``config`` object is meant to be the single source of truth for all config options.  All of the other ways of setting config options ultimately change the values of the global ``config`` object.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:118\nmsgid \"The following example illustrates the video resolution chosen for examples rendered in our documentation with a reference frame.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:140\nmsgid \"The config files\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:142\nmsgid \"As the last example shows, executing Manim from the command line may involve using many flags simultaneously.  This may become a nuisance if you must execute the same script many times in a short time period, for example, when making small incremental tweaks to your scene script.  For this reason, Manim can also be configured using a configuration file.  A configuration file is a file ending with the suffix ``.cfg``.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:149\nmsgid \"To use a local configuration file when rendering your scene, you must create a file with the name ``manim.cfg`` in the same directory as your scene code.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:152\nmsgid \"The config file **must** be named ``manim.cfg``. Currently, Manim does not support config files with any other name.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:155\nmsgid \"The config file must start with the section header ``[CLI]``.  The configuration options under this header have the same name as the CLI flags and serve the same purpose.  Take, for example, the following config file.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:167\nmsgid \"Config files are parsed with the standard python library ``configparser``. In particular, they will ignore any line that starts with a pound symbol ``#``.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:170\nmsgid \"Now, executing the following command\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:176\nmsgid \"is equivalent to executing the following command, provided that ``manim.cfg`` is in the same directory as <file.py>,\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:183\nmsgid \"The names of the configuration options admissible in config files are exactly the same as the **long names** of the corresponding command- line flags.  For example, the ``-c`` and ``--background_color`` flags are interchangeable, but the config file only accepts :code:`background_color` as an admissible option.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:189\nmsgid \"Since config files are meant to replace CLI flags, all CLI flags can be set via a config file.  Moreover, any config option can be set via a config file, whether or not it has an associated CLI flag.  See the bottom of this document for a list of all CLI flags and config options.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:194\nmsgid \"Manim will look for a ``manim.cfg`` config file in the same directory as the file being rendered, and **not** in the directory of execution.  For example,\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:201\nmsgid \"will use the config file found in ``path/to/file.py``, if any.  It will **not** use the config file found in the current working directory, even if it exists. In this way, the user may keep different config files for different scenes or projects, and execute them with the right configuration from anywhere in the system.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:207\nmsgid \"The file described here is called the **folder-wide** config file because it affects all scene scripts found in the same folder.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:212\nmsgid \"The user config file\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:214\nmsgid \"As explained in the previous section, a :code:`manim.cfg` config file only affects the scene scripts in its same folder.  However, the user may also create a special config file that will apply to all scenes rendered by that user. This is referred to as the **user-wide** config file, and it will apply regardless of where Manim is executed from, and regardless of where the scene script is stored.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:221\nmsgid \"The user-wide config file lives in a special folder, depending on the operating system.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:224\nmsgid \"Windows: :code:`UserDirectory`/AppData/Roaming/Manim/manim.cfg\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:225\nmsgid \"MacOS: :code:`UserDirectory`/.config/manim/manim.cfg\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:226\nmsgid \"Linux: :code:`UserDirectory`/.config/manim/manim.cfg\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:228\nmsgid \"Here, :code:`UserDirectory` is the user's home folder.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:231\nmsgid \"A user may have many **folder-wide** config files, one per folder, but only one **user-wide** config file.  Different users in the same computer may each have their own user-wide config file.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:235\nmsgid \"Do not store scene scripts in the same folder as the user-wide config file.  In this case, the behavior is undefined.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:238\nmsgid \"Whenever you use Manim from anywhere in the system, Manim will look for a user-wide config file and read its configuration.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:243\nmsgid \"Cascading config files\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:245\nmsgid \"What happens if you execute Manim and it finds both a folder-wide config file and a user-wide config file?  Manim will read both files, but if they are incompatible, **the folder-wide file takes precedence**.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:249\nmsgid \"For example, take the following user-wide config file\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:259\nmsgid \"and the following folder-wide file\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:267\nmsgid \"Then, executing :code:`manim <file.py> SceneName` will be equivalent to not using any config files and executing\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:274\nmsgid \"Any command-line flags have precedence over any config file.  For example, using the previous two config files and executing :code:`manim -c RED <file.py> SceneName` is equivalent to not using any config files and executing\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:283\nmsgid \"There is also a **library-wide** config file that determines Manim's default behavior and applies to every user of the library.  It has the least precedence, so any config options in the user-wide and any folder-wide files will override the library-wide file.  This is referred to as the *cascading* config file system.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:289\nmsgid \"**The user should not try to modify the library-wide file**. Contributors should receive explicit confirmation from the core developer team before modifying it.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:295\nmsgid \"Order of operations\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:304\nmsgid \"With so many different ways of configuring Manim, it can be difficult to know when each config option is being set.  In fact, this will depend on how Manim is being used.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:308\nmsgid \"If Manim is imported from a module, then the configuration system will follow these steps:\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:311\nmsgid \"The library-wide config file is loaded.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:312\nmsgid \"The user-wide and folder-wide files are loaded if they exist.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:313\nmsgid \"All files found in the previous two steps are parsed in a single :class:`ConfigParser` object, called ``parser``.  This is where *cascading* happens.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:316\nmsgid \":class:`logging.Logger` is instantiated to create Manim's global ``logger`` object. It is configured using the \\\"logger\\\" section of the parser, i.e. ``parser['logger']``.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:319\nmsgid \":class:`ManimConfig` is instantiated to create the global ``config`` object.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:320\nmsgid \"The ``parser`` from step 3 is fed into the ``config`` from step 5 via :meth:`ManimConfig.digest_parser`.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:322\nmsgid \"Both ``logger`` and ``config`` are exposed to the user.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:324\nmsgid \"If Manim is being invoked from the command line, all of the previous steps happen, and are complemented by:\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:327\nmsgid \"The CLI flags are parsed and fed into ``config`` via :meth:`~ManimConfig.digest_args`.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:329\nmsgid \"If the ``--config_file`` flag was used, a new :class:`ConfigParser` object is created with the contents of the library-wide file, the user-wide file if it exists, and the file passed via ``--config_file``.  In this case, the folder-wide file, if it exists, is ignored.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:333\nmsgid \"The new parser is fed into ``config``.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:334\nmsgid \"The rest of the CLI flags are processed.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:336\nmsgid \"To summarize, the order of precedence for configuration options, from lowest to highest precedence is:\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:339\nmsgid \"Library-wide config file,\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:340\nmsgid \"user-wide config file, if it exists,\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:341\nmsgid \"folder-wide config file, if it exists OR custom config file, if passed via ``--config_file``,\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:343\nmsgid \"other CLI flags, and\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:344\nmsgid \"any programmatic changes made after the config system is set.\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:348\nmsgid \"A list of all config options\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:369\nmsgid \"Accessing CLI command options\"\nmsgstr \"\"\n\n#: ../../source/guides/configuration.rst:371\nmsgid \"Entering ``manim``, or ``manim --help``, will open the main help page.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/guides/deep_dive.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/guides/deep_dive.rst:2\nmsgid \"A deep dive into Manim's internals\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:4\nmsgid \"**Author:** `Benjamin Hackl <https://benjamin-hackl.at>`__\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:6\nmsgid \"Disclaimer\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:8\nmsgid \"This guide reflects the state of the library as of version ``v0.16.0`` and primarily treats the Cairo renderer. The situation in the latest version of Manim might be different; in case of substantial deviations we will add a note below.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:14\nmsgid \"Introduction\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:16\nmsgid \"Manim can be a wonderful library, if it behaves the way you would like it to, and/or the way you expect it to. Unfortunately, this is not always the case (as you probably know if you have played with some manimations yourself already). To understand where things *go wrong*, digging through the library's source code is sometimes the only option -- but in order to do that, you need to know where to start digging.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:23\nmsgid \"This article is intended as some sort of life line through the render process. We aim to give an appropriate amount of detail describing what happens when Manim reads your scene code and produces the corresponding animation. Throughout this article, we will focus on the following toy example::\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:43\nmsgid \"Before we go into details or even look at the rendered output of this scene, let us first describe verbally what happens in this *manimation*. In the first three lines of the ``construct`` method, a :class:`.Square` and a :class:`.Circle` are initialized, then the square is added to the scene. The first frame of the rendered output should thus show an orange square.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:49\nmsgid \"Then the actual animations happen: the square first transforms into a circle, then a :class:`.Dot` is created (Where do you guess the dot is located when it is first added to the scene? Answering this already requires detailed knowledge about the render process.). The dot has an updater attached to it, and as the circle moves right, the dot moves with it. In the end, all mobjects are faded out.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:56\nmsgid \"Actually rendering the code yields the following video:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:75\nmsgid \"For this example, the output (fortunately) coincides with our expectations.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:78\nmsgid \"Overview\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:80\nmsgid \"Because there is a lot of information in this article, here is a brief overview discussing the contents of the following chapters on a very high level.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:83\nmsgid \"`Preliminaries`_: In this chapter we unravel all the steps that take place to prepare a scene for rendering; right until the point where the user-overridden ``construct`` method is ran. This includes a brief discussion on using Manim's CLI versus other means of rendering (e.g., via Jupyter notebooks, or in your Python script by calling the :meth:`.Scene.render` method yourself).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:88\nmsgid \"`Mobject Initialization`_: For the second chapter we dive into creating and handling Mobjects, the basic elements that should be displayed in our scene. We discuss the :class:`.Mobject` base class, how there are essentially three different types of Mobjects, and then discuss the most important of them, vectorized Mobjects. In particular, we describe the internal point data structure that governs how the mechanism responsible for drawing the vectorized Mobject to the screen sets the corresponding Bézier curves. We conclude the chapter with a tour into :meth:`.Scene.add`, the bookkeeping mechanism controlling which mobjects should be rendered.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:97\nmsgid \"`Animations and the Render Loop`_: And finally, in the last chapter we walk through the instantiation of :class:`.Animation` objects (the blueprints that hold information on how Mobjects should be modified when the render loop runs), followed by a investigation of the infamous :meth:`.Scene.play` call. We will see that there are three relevant parts in a :meth:`.Scene.play` call; a part in which the passed animations and keyword arguments are processed and prepared, followed by the actual \\\"render loop\\\" in which the library steps through a time line and renders frame by frame. The final part does some post-processing to save a short video segment (\\\"partial movie file\\\") and cleanup for the next call to :meth:`.Scene.play`. In the end, after all of :meth:`.Scene.construct` has been run, the library combines the partial movie files to one video.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:110\nmsgid \"And with that, let us get *in medias res*.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:113\nmsgid \"Preliminaries\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:116\nmsgid \"Importing the library\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:118\nmsgid \"Independent of how exactly you are telling your system to render the scene, i.e., whether you run ``manim -qm -p file_name.py ToyExample``, or whether you are rendering the scene directly from the Python script via a snippet like\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:129\nmsgid \"or whether you are rendering the code in a Jupyter notebook, you are still telling your python interpreter to import the library. The usual pattern used to do this is\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:136\nmsgid \"which (while being a debatable strategy in general) imports a lot of classes and functions shipped with the library and makes them available in your global name space. I explicitly avoided stating that it imports **all** classes and functions of the library, because it does not do that: Manim makes use of the practice described in `Section 6.4.1 of the Python tutorial <https://docs.python.org/3/tutorial/modules.html#importing-from-a-package>`__, and all module members that should be exposed to the user upon running the ``*``-import are explicitly declared in the ``__all__`` variable of the module.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:144\nmsgid \"Manim also uses this strategy internally: taking a peek at the file that is run when the import is called, ``__init__.py`` (see `here <https://github.com/ManimCommunity/manim/blob/main/manim/__init__.py>`__), you will notice that most of the code in that module is concerned with importing members from various different submodules, again using ``*``-imports.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:152\nmsgid \"If you would ever contribute a new submodule to Manim, the main ``__init__.py`` is where it would have to be listed in order to make its members accessible to users after importing the library.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:156\nmsgid \"In that file, there is one particular import at the beginning of the file however, namely::\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:161\nmsgid \"This initializes Manim's global configuration system, which is used in various places throughout the library. After the library runs this line, the current configuration options are set. The code in there takes care of reading the options in your ``.cfg`` files (all users have at least the global one that is shipped with the library) as well as correctly handling command line arguments (if you used the CLI to render).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:167\nmsgid \"You can read more about the config system in the :doc:`corresponding thematic guide </guides/configuration>`, and if you are interested in learning more about the internals of the configuration system and how it is initialized, follow the code flow starting in `the config module's init file <https://github.com/ManimCommunity/manim/blob/main/manim/_config/__init__.py>`__.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:173\nmsgid \"Now that the library is imported, we can turn our attention to the next step: reading your scene code (which is not particularly exciting, Python just creates a new class ``ToyExample`` based on our code; Manim is virtually not involved in that step, with the exception that ``ToyExample`` inherits from ``Scene``).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:178\nmsgid \"However, with the ``ToyExample`` class created and ready to go, there is a new excellent question to answer: how is the code in our ``construct`` method actually executed?\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:183\nmsgid \"Scene instantiation and rendering\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:185\nmsgid \"The answer to this question depends on how exactly you are running the code. To make things a bit clearer, let us first consider the case that you have created a file ``toy_example.py`` which looks like this::\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:208\nmsgid \"With such a file, the desired scene is rendered by simply running this Python script via ``python toy_example.py``. Then, as described above, the library is imported and Python has read and defined the ``ToyExample`` class (but, read carefully: *no instance of this class has been created yet*).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:213\nmsgid \"At this point, the interpreter is about to enter the ``tempconfig`` context manager. Even if you have not seen Manim's ``tempconfig`` before, it's name already suggests what it does: it creates a copy of the current state of the configuration, applies the changes to the key-value pairs in the passed dictionary, and upon leaving the context the original version of the configuration is restored. TL;DR: it provides a fancy way of temporarily setting configuration options.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:221\nmsgid \"Inside the context manager, two things happen: an actual ``ToyExample``-scene object is instantiated, and the ``render`` method is called. Every way of using Manim ultimately does something along of these lines, the library always instantiates the scene object and then calls its ``render`` method. To illustrate that this really is the case, let us briefly look at the two most common ways of rendering scenes:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:228\nmsgid \"**Command Line Interface.** When using the CLI and running the command ``manim -qm -p toy_example.py ToyExample`` in your terminal, the actual entry point is Manim's ``__main__.py`` file (located `here <https://github.com/ManimCommunity/manim/blob/main/manim/__main__.py>`__. Manim uses `Click <https://click.palletsprojects.com/en/8.0.x/>`__ to implement the command line interface, and the corresponding code is located in Manim's ``cli`` module (https://github.com/ManimCommunity/manim/tree/main/manim/cli). The corresponding code creating the scene class and calling its render method is located `here <https://github.com/ManimCommunity/manim/blob/ac1ee9a683ce8b92233407351c681f7d71a4f2db/manim/cli/render/commands.py#L139-L141>`__.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:238\nmsgid \"**Jupyter notebooks.** In Jupyter notebooks, the communication with the library is handled by the ``%%manim`` magic command, which is implemented in the ``manim.utils.ipython_magic`` module. There is :meth:`some documentation <.ManimMagic.manim>` available for the magic command, and the code creating the scene class and calling its render method is located `here <https://github.com/ManimCommunity/manim/blob/ac1ee9a683ce8b92233407351c681f7d71a4f2db/manim/utils/ipython_magic.py#L137-L138>`__.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:246\nmsgid \"Now that we know that either way, a :class:`.Scene` object is created, let us investigate what Manim does when that happens. When instantiating our scene object\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:253\nmsgid \"the ``Scene.__init__`` method is called, given that we did not implement our own initialization method. Inspecting the corresponding code (see `here <https://github.com/ManimCommunity/manim/blob/main/manim/scene/scene.py>`__) reveals that ``Scene.__init__`` first sets several attributes of the scene objects that do not depend on any configuration options set in ``config``. Then the scene inspects the value of ``config.renderer``, and based on its value, either instantiates a ``CairoRenderer`` or an ``OpenGLRenderer`` object and assigns it to its ``renderer`` attribute.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:261\nmsgid \"The scene then asks its renderer to initialize the scene by calling\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:267\nmsgid \"Inspecting both the default Cairo renderer and the OpenGL renderer shows that the ``init_scene`` method effectively makes the renderer instantiate a :class:`.SceneFileWriter` object, which basically is Manim's interface to ``ffmpeg`` and actually writes the movie file. The Cairo renderer (see the implementation `here <https://github.com/ManimCommunity/manim/blob/main/manim/renderer/cairo_renderer.py>`__) does not require any further initialization. The OpenGL renderer does some additional setup to enable the realtime rendering preview window, which we do not go into detail further here.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:276\nmsgid \"Currently, there is a lot of interplay between a scene and its renderer. This is a flaw in Manim's current architecture, and we are working on reducing this interdependency to achieve a less convoluted code flow.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:280\nmsgid \"After the renderer has been instantiated and initialized its file writer, the scene populates further initial attributes (notable mention: the ``mobjects`` attribute which keeps track of the mobjects that have been added to the scene). It is then done with its instantiation and ready to be rendered.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:285\nmsgid \"The rest of this article is concerned with the last line in our toy example script::\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:289\nmsgid \"This is where the actual magic happens.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:291\nmsgid \"Inspecting the `implementation of the render method <https://github.com/ManimCommunity/manim/blob/df1a60421ea1119cbbbd143ef288d294851baaac/manim/scene/scene.py#L211>`__ reveals that there are several hooks that can be used for pre- or postprocessing a scene. Unsurprisingly, :meth:`.Scene.render` describes the full *render cycle* of a scene. During this life cycle, there are three custom methods whose base implementation is empty and that can be overwritten to suit your purposes. In the order they are called, these customizable methods are:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:298\nmsgid \":meth:`.Scene.setup`, which is intended for preparing and, well, *setting up* the scene for your animation (e.g., adding initial mobjects, assigning custom attributes to your scene class, etc.),\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:301\nmsgid \":meth:`.Scene.construct`, which is the *script* for your screen play and contains programmatic descriptions of your animations, and\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:303\nmsgid \":meth:`.Scene.tear_down`, which is intended for any operations you might want to run on the scene after the last frame has already been rendered (for example, this could run some code that generates a custom thumbnail for the video based on the state of the objects in the scene -- this hook is more relevant for situations where Manim is used within other Python scripts).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:310\nmsgid \"After these three methods are run, the animations have been fully rendered, and Manim calls :meth:`.CairoRenderer.scene_finished` to gracefully complete the rendering process. This checks whether any animations have been played -- and if so, it tells the :class:`.SceneFileWriter` to close the pipe to ``ffmpeg``. If not, Manim assumes that a static image should be output which it then renders using the same strategy by calling the render loop (see below) once.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:318\nmsgid \"**Back in our toy example,** the call to :meth:`.Scene.render` first triggers :meth:`.Scene.setup` (which only consists of ``pass``), followed by a call of :meth:`.Scene.construct`. At this point, our *animation script* is run, starting with the initialization of ``orange_square``.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:325\nmsgid \"Mobject Initialization\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:327\nmsgid \"Mobjects are, in a nutshell, the Python objects that represent all the *things* we want to display in our scene. Before we follow our debugger into the depths of mobject initialization code, it makes sense to discuss Manim's different types of Mobjects and their basic data structure.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:334\nmsgid \"What even is a Mobject?\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:336\nmsgid \":class:`.Mobject` stands for *mathematical object* or *Manim object* (depends on who you ask 😄). The Python class :class:`.Mobject` is the base class for all objects that should be displayed on screen. Looking at the `initialization method <https://github.com/ManimCommunity/manim/blob/5d72d9cfa2e3dd21c844b1da807576f5a7194fda/manim/mobject/mobject.py#L94>`__ of :class:`.Mobject`, you will find that not too much happens in there:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:343\nmsgid \"some initial attribute values are assigned, like ``name`` (which makes the render logs mention the name of the mobject instead of its type), ``submobjects`` (initially an empty list), ``color``, and some others.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:346\nmsgid \"Then, two methods related to *points* are called: ``reset_points`` followed by ``generate_points``,\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:348\nmsgid \"and finally, ``init_colors`` is called.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:350\nmsgid \"Digging deeper, you will find that :meth:`.Mobject.reset_points` simply sets the ``points`` attribute of the mobject to an empty NumPy vector, while the other two methods, :meth:`.Mobject.generate_points` and :meth:`.Mobject.init_colors` are just implemented as ``pass``.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:355\nmsgid \"This makes sense: :class:`.Mobject` is not supposed to be used as an *actual* object that is displayed on screen; in fact the camera (which we will discuss later in more detail; it is the class that is, for the Cairo renderer, responsible for \\\"taking a picture\\\" of the current scene) does not process \\\"pure\\\" :class:`Mobjects <.Mobject>` in any way, they *cannot* even appear in the rendered output.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:362\nmsgid \"This is where different types of mobjects come into play. Roughly speaking, the Cairo renderer setup knows three different types of mobjects that can be rendered:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:366\nmsgid \":class:`.ImageMobject`, which represent images that you can display in your scene,\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:368\nmsgid \":class:`.PMobject`, which are very special mobjects used to represent point clouds; we will not discuss them further in this guide,\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:370\nmsgid \":class:`.VMobject`, which are *vectorized mobjects*, that is, mobjects that consist of points that are connected via curves. These are pretty much everywhere, and we will discuss them in detail in the next section.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:375\nmsgid \"... and what are VMobjects?\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:377\nmsgid \"As just mentioned, :class:`VMobjects <.VMobject>` represent vectorized mobjects. To render a :class:`.VMobject`, the camera looks at the ``points`` attribute of a :class:`.VMobject` and divides it into sets of four points each. Each of these sets is then used to construct a cubic Bézier curve with the first and last entry describing the end points of the curve (\\\"anchors\\\"), and the second and third entry describing the control points in between (\\\"handles\\\").\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:386\nmsgid \"To learn more about Bézier curves, take a look at the excellent online textbook `A Primer on Bézier curves <https://pomax.github.io/bezierinfo/>`__ by `Pomax <https://twitter.com/TheRealPomax>`__ -- there is an playground representing cubic Bézier curves `in §1 <https://pomax.github.io/bezierinfo/#introduction>`__, the red and yellow points are \\\"anchors\\\", and the green and blue points are \\\"handles\\\".\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:393\nmsgid \"In contrast to :class:`.Mobject`, :class:`.VMobject` can be displayed on screen (even though, technically, it is still considered a base class). To illustrate how points are processed, consider the following short example of a :class:`.VMobject` with 8 points (and thus made out of 8/4 = 2 cubic Bézier curves). The resulting :class:`.VMobject` is drawn in green. The handles are drawn as red dots with a line to their closest anchor.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:433\nmsgid \"Manually setting the points of your :class:`.VMobject` is usually discouraged; there are specialized methods that can take care of that for you -- but it might be relevant when implementing your own, custom :class:`.VMobject`.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:441\nmsgid \"Squares and Circles: back to our Toy Example\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:443\nmsgid \"With a basic understanding of different types of mobjects, and an idea of how vectorized mobjects are built we can now come back to our toy example and the execution of the :meth:`.Scene.construct` method. In the first two lines of our animation script, the ``orange_square`` and the ``blue_circle`` are initialized.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:450\nmsgid \"When creating the orange square by running\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:456\nmsgid \"the initialization method of :class:`.Square`, ``Square.__init__``, is called. `Looking at the implementation <https://github.com/ManimCommunity/manim/blob/5d72d9cfa2e3dd21c844b1da807576f5a7194fda/manim/mobject/geometry/polygram.py#L607>`__, we can see that the ``side_length`` attribute of the square is set, and then\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:466\nmsgid \"is called. This ``super`` call is the Python way of calling the initialization function of the parent class. As :class:`.Square` inherits from :class:`.Rectangle`, the next method called is ``Rectangle.__init__``. There, only the first three lines are really relevant for us::\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:476\nmsgid \"First, the initialization function of the parent class of :class:`.Rectangle` -- :class:`.Polygon` -- is called. The four positional arguments passed are the four corners of the polygon: ``UR`` is up right (and equal to ``UP + RIGHT``), ``UL`` is up left (and equal to ``UP + LEFT``), and so forth. Before we follow our debugger deeper, let us observe what happens with the constructed polygon: the remaining two lines stretch the polygon to fit the specified width and height such that a rectangle with the desired measurements is created.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:486\nmsgid \"The initialization function of :class:`.Polygon` is particularly simple, it only calls the initialization function of its parent class, :class:`.Polygram`. There, we have almost reached the end of the chain: :class:`.Polygram` inherits from :class:`.VMobject`, whose initialization function mainly sets the values of some attributes (quite similar to ``Mobject.__init__``, but more specific to the Bézier curves that make up the mobject).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:494\nmsgid \"After calling the initialization function of :class:`.VMobject`, the constructor of :class:`.Polygram` also does something somewhat odd: it sets the points (which, you might remember above, should actually be set in a corresponding ``generate_points`` method of :class:`.Polygram`).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:501\nmsgid \"In several instances, the implementation of mobjects does not really stick to all aspects of Manim's interface. This is unfortunate, and increasing consistency is something that we actively work on. Help is welcome!\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:506\nmsgid \"Without going too much into detail, :class:`.Polygram` sets its ``points`` attribute via :meth:`.VMobject.start_new_path`, :meth:`.VMobject.add_points_as_corners`, which take care of setting the quadruples of anchors and handles appropriately. After the points are set, Python continues to process the call stack until it reaches the method that was first called; the initialization method of :class:`.Square`. After this, the square is initialized and assigned to the ``orange_square`` variable.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:516\nmsgid \"The initialization of ``blue_circle`` is similar to the one of ``orange_square``, with the main difference being that the inheritance chain of :class:`.Circle` is different. Let us briefly follow the trace of the debugger:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:521\nmsgid \"The implementation of :meth:`.Circle.__init__` immediately calls the initialization method of :class:`.Arc`, as a circle in Manim is simply an arc with an angle of :math:`\\\\tau = 2\\\\pi`. When initializing the arc, some basic attributes are set (like ``Arc.radius``, ``Arc.arc_center``, ``Arc.start_angle``, and ``Arc.angle``), and then the initialization method of its parent class, :class:`.TipableVMobject`, is called (which is a rather abstract base class for mobjects which a arrow tip can be attached to). Note that in contrast to :class:`.Polygram`, this class does **not** preemptively generate the points of the circle.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:532\nmsgid \"After that, things are less exciting: :class:`.TipableVMobject` again sets some attributes relevant for adding arrow tips, and afterwards passes to the initialization method of :class:`.VMobject`. From there, :class:`.Mobject` is initialized and :meth:`.Mobject.generate_points` is called, which actually runs the method implemented in :meth:`.Arc.generate_points`.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:539\nmsgid \"After both our ``orange_square`` and the ``blue_circle`` are initialized, the square is actually added to the scene. The :meth:`.Scene.add` method is actually doing a few interesting things, so it is worth to dig a bit deeper in the next section.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:546\nmsgid \"Adding Mobjects to the Scene\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:548\nmsgid \"The code in our ``construct`` method that is run next is\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:554\nmsgid \"From a high-level point of view, :meth:`.Scene.add` adds the ``orange_square`` to the list of mobjects that should be rendered, which is stored in the ``mobjects`` attribute of the scene. However, it does so in a very careful way to avoid the situation that a mobject is being added to the scene more than once. At a first glance, this sounds like a simple task -- the problem is that ``Scene.mobjects`` is not a \\\"flat\\\" list of mobjects, but a list of mobjects which might contain mobjects themselves, and so on.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:563\nmsgid \"Stepping through the code in :meth:`.Scene.add`, we see that first it is checked whether we are currently using the OpenGL renderer (which we are not) -- adding mobjects to the scene works slightly different (and actually easier!) for the OpenGL renderer. Then, the code branch for the Cairo renderer is entered and the list of so-called foreground mobjects (which are rendered on top of all other mobjects) is added to the list of passed mobjects. This is to ensure that the foreground mobjects will stay above of the other mobjects, even after adding the new ones. In our case, the list of foreground mobjects is actually empty, and nothing changes.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:574\nmsgid \"Next, :meth:`.Scene.restructure_mobjects` is called with the list of mobjects to be added as the ``to_remove`` argument, which might sound odd at first. Practically, this ensures that mobjects are not added twice, as mentioned above: if they were present in the scene ``Scene.mobjects`` list before (even if they were contained as a child of some other mobject), they are first removed from the list. The way :meth:`.Scene.restrucutre_mobjects` works is rather aggressive: It always operates on a given list of mobjects; in the ``add`` method two different lists occur: the default one, ``Scene.mobjects`` (no extra keyword argument is passed), and ``Scene.moving_mobjects`` (which we will discuss later in more detail). It iterates through all of the members of the list, and checks whether any of the mobjects passed in ``to_remove`` are contained as children (in any nesting level). If so, **their parent mobject is deconstructed** and their siblings are inserted directly one level higher. Consider the following example::\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:604\nmsgid \"Note that the group is disbanded and the circle moves into the root layer of mobjects in ``test_scene.mobjects``.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:607\nmsgid \"After the mobject list is \\\"restructured\\\", the mobject to be added are simply appended to ``Scene.mobjects``. In our toy example, the ``Scene.mobjects`` list is actually empty, so the ``restructure_mobjects`` method does not actually do anything. The ``orange_square`` is simply added to ``Scene.mobjects``, and as the aforementioned ``Scene.moving_mobjects`` list is, at this point, also still empty, nothing happens and :meth:`.Scene.add` returns.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:615\nmsgid \"We will hear more about the ``moving_mobject`` list when we discuss the render loop. Before we do that, let us look at the next line of code in our toy example, which includes the initialization of an animation class, ::\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:623\nmsgid \"Hence it is time to talk about :class:`.Animation`.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:627\nmsgid \"Animations and the Render Loop\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:630\nmsgid \"Initializing animations\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:632\nmsgid \"Before we follow the trace of the debugger, let us briefly discuss the general structure of the (abstract) base class :class:`.Animation`. An animation object holds all the information necessary for the renderer to generate the corresponding frames. Animations (in the sense of animation objects) in Manim are *always* tied to a specific mobject; even in the case of :class:`.AnimationGroup` (which you should actually think of as an animation on a group of mobjects rather than a group of animations). Moreover, except for in a particular special case, the run time of animations is also fixed and known beforehand.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:642\nmsgid \"The initialization of animations actually is not very exciting, :meth:`.Animation.__init__` merely sets some attributes derived from the passed keyword arguments and additionally ensures that the ``Animation.starting_mobject`` and ``Animation.mobject`` attributes are populated. Once the animation is played, the ``starting_mobject`` attribute holds an unmodified copy of the mobject the animation is attached to; during the initialization it is set to a placeholder mobject. The ``mobject`` attribute is set to the mobject the animation is attached to.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:652\nmsgid \"Animations have a few special methods which are called during the render loop:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:655\nmsgid \":meth:`.Animation.begin`, which is called (as hinted by its name) at the beginning of every animation, so before the first frame is rendered. In it, all the required setup for the animation happens.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:658\nmsgid \":meth:`.Animation.finish` is the counterpart to the ``begin`` method which is called at the end of the life cycle of the animation (after the last frame has been rendered).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:661\nmsgid \":meth:`.Animation.interpolate` is the method that updates the mobject attached to the animation to the corresponding animation completion percentage. For example, if in the render loop, ``some_animation.interpolate(0.5)`` is called, the attached mobject will be updated to the state where 50% of the animation are completed.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:667\nmsgid \"We will discuss details about these and some further animation methods once we walk through the actual render loop. For now, we continue with our toy example and the code that is run when initializing the :class:`.ReplacementTransform` animation.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:672\nmsgid \"The initialization method of :class:`.ReplacementTransform` only consists of a call to the constructor of its parent class, :class:`.Transform`, with the additional keyword argument ``replace_mobject_with_target_in_scene`` set to ``True``. :class:`.Transform` then sets attributes that control how the points of the starting mobject are deformed into the points of the target mobject, and then passes on to the initialization method of :class:`.Animation`. Other basic properties of the animation (like its ``run_time``, the ``rate_func``, etc.) are processed there -- and then the animation object is fully initialized and ready to be played.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:685\nmsgid \"The ``play`` call: preparing to enter Manim's render loop\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:687\nmsgid \"We are finally there, the render loop is in our reach. Let us walk through the code that is run when :meth:`.Scene.play` is called.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:692\nmsgid \"Recall that this article is specifically about the Cairo renderer. Up to here, things were more or less the same for the OpenGL renderer as well; while some base mobjects might be different, the control flow and lifecycle of mobjects is still more or less the same. There are more substantial differences when it comes to the rendering loop.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:698\nmsgid \"As you will see when inspecting the method, :meth:`.Scene.play` almost immediately passes over to the ``play`` method of the renderer, in our case :class:`.CairoRenderer.play`. The one thing :meth:`.Scene.play` takes care of is the management of subcaptions that you might have passed to it (see the the documentation of :meth:`.Scene.play` and :meth:`.Scene.add_subcaption` for more information).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:707\nmsgid \"As has been said before, the communication between scene and renderer is not in a very clean state at this point, so the following paragraphs might be confusing if you don't run a debugger and step through the code yourself a bit.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:712\nmsgid \"Inside :meth:`.CairoRenderer.play`, the renderer first checks whether it may skip rendering of the current play call. This might happen, for example, when ``-s`` is passed to the CLI (i.e., only the last frame should be rendered), or when the ``-n`` flag is passed and the current play call is outside of the specified render bounds. The \\\"skipping status\\\" is updated in form of the call to :meth:`.CairoRenderer.update_skipping_status`.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:719\nmsgid \"Next, the renderer asks the scene to process the animations in the play call so that renderer obtains all of the information it needs. To be more concrete, :meth:`.Scene.compile_animation_data` is called, which then takes care of several things:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:724\nmsgid \"The method processes all animations and the keyword arguments passed to the initial :meth:`.Scene.play` call. In particular, this means that it makes sure all arguments passed to the play call are actually animations (or ``.animate`` syntax calls, which are also assembled to be actual :class:`.Animation`-objects at that point). It also propagates any animation-related keyword arguments (like ``run_time``, or ``rate_func``) passed to :class:`.Scene.play` to each individual animation. The processed animations are then stored in the ``animations`` attribute of the scene (which the renderer later reads...).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:733\nmsgid \"It adds all mobjects to which the animations that are played are bound to to the scene (provided the animation is not an mobject-introducing animation -- for these, the addition to the scene happens later).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:736\nmsgid \"In case the played animation is a :class:`.Wait` animation (this is the case in a :meth:`.Scene.wait` call), the method checks whether a static image should be rendered, or whether the render loop should be processed as usual (see :meth:`.Scene.should_update_mobjects` for the exact conditions, basically it checks whether there are any time-dependent updater functions and so on).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:742\nmsgid \"Finally, the method determines the total run time of the play call (which at this point is computed as the maximum of the run times of the passed animations). This is stored in the ``duration`` attribute of the scene.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:747\nmsgid \"After the animation data has been compiled by the scene, the renderer continues to prepare for entering the render loop. It now checks the skipping status which has been determined before. If the renderer can skip this play call, it does so: it sets the current play call hash (which we will get back to in a moment) to ``None`` and increases the time of the renderer by the determined animation run time.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:754\nmsgid \"Otherwise, the renderer checks whether or not Manim's caching system should be used. The idea of the caching system is simple: for every play call, a hash value is computed, which is then stored and upon re-rendering the scene, the hash is generated again and checked against the stored value. If it is the same, the cached output is reused, otherwise it is fully rerendered again. We will not go into details of the caching system here; if you would like to learn more, the :func:`.get_hash_from_play_call` function in the :mod:`.utils.hashing` module is essentially the entry point to the caching mechanism.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:764\nmsgid \"In the event that the animation has to be rendered, the renderer asks its :class:`.SceneFileWriter` to start a writing process. The process is started by a call to ``ffmpeg`` and opens a pipe to which rendered raw frames can be written. As long as the pipe is open, the process can be accessed via the ``writing_process`` attribute of the file writer. With the writing process in place, the renderer then asks the scene to \\\"begin\\\" the animations.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:772\nmsgid \"First, it literally *begins* all of the animations by calling their setup methods (:meth:`.Animation._setup_scene`, :meth:`.Animation.begin`). In doing so, the mobjects that are newly introduced by an animation (like via :class:`.Create` etc.) are added to the scene. Furthermore, the animation suspends updater functions being called on its mobject, and it sets its mobject to the state that corresponds to the first frame of the animation.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:780\nmsgid \"After this has happened for all animations in the current ``play`` call, the Cairo renderer determines which of the scene's mobjects can be painted statically to the background, and which ones have to be redrawn every frame. It does so by calling :meth:`.Scene.get_moving_and_static_mobjects`, and the resulting partition of mobjects is stored in the corresponding ``moving_mobjects`` and ``static_mobjects`` attributes.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:790\nmsgid \"The mechanism that determines static and moving mobjects is specific for the Cairo renderer, the OpenGL renderer works differently. Basically, moving mobjects are determined by checking whether they, any of their children, or any of the mobjects \\\"below\\\" them (in the sense of the order in which mobjects are processed in the scene) either have an update function attached, or whether they appear in one of the current animations. See the implementation of :meth:`.Scene.get_moving_mobjects` for more details.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:799\nmsgid \"Up to this very point, we did not actually render any (partial) image or movie files from the scene yet. This is, however, about to change. Before we enter the render loop, let us briefly revisit our toy example and discuss how the generic :meth:`.Scene.play` call setup looks like there.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:805\nmsgid \"For the call that plays the :class:`.ReplacementTransform`, there is no subcaption to be taken care of. The renderer then asks the scene to compile the animation data: the passed argument already is an animation (no additional preparations needed), there is no need for processing any keyword arguments (as we did not specify any additional ones to ``play``). The mobject bound to the animation, ``orange_square``, is already part of the scene (so again, no action taken). Finally, the run time is extracted (3 seconds long) and stored in ``Scene.duration``. The renderer then checks whether it should skip (it should not), then whether the animation is already cached (it is not). The corresponding animation hash value is determined and passed to the file writer, which then also calls ``ffmpeg`` to start the writing process which waits for rendered frames from the library.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:821\nmsgid \"The scene then ``begin``\\\\ s the animation: for the :class:`.ReplacementTransform` this means that the animation populates all of its relevant animation attributes (i.e., compatible copies of the starting and the target mobject so that it can safely interpolate between the two).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:827\nmsgid \"The mechanism determining static and moving mobjects considers all of the scenes mobjects (at this point only the ``orange_square``), and determines that the ``orange_square`` is bound to an animation that is currently played. As a result, the square is classified as a \\\"moving mobject\\\".\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:833\nmsgid \"Time to render some frames.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:837\nmsgid \"The render loop (for real this time)\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:839\nmsgid \"As mentioned above, due to the mechanism that determines static and moving mobjects in the scene, the renderer knows which mobjects it can paint statically to the background of the scene. Practically, this means that it partially renders a scene (to produce a background image), and then when iterating through the time progression of the animation only the \\\"moving mobjects\\\" are re-painted on top of the static background.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:846\nmsgid \"The renderer calls :meth:`.CairoRenderer.save_static_frame_data`, which first checks whether there are currently any static mobjects, and if there are, it updates the frame (only with the static mobjects; more about how exactly this works in a moment) and then saves a NumPy array representing the rendered frame in the ``static_image`` attribute. In our toy example, there are no static mobjects, and so the ``static_image`` attribute is simply set to ``None``.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:854\nmsgid \"Next, the renderer asks the scene whether the current animation is a \\\"frozen frame\\\" animation, which would mean that the renderer actually does not have to repaint the moving mobjects in every frame of the time progression. It can then just take the latest static frame, and display it throughout the animation.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:862\nmsgid \"An animation is considered a \\\"frozen frame\\\" animation if only a static :class:`.Wait` animation is played. See the description of :meth:`.Scene.compile_animation_data` above, or the implementation of :meth:`.Scene.should_update_mobjects` for more details.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:868\nmsgid \"If this is not the case (just as in our toy example), the renderer then calls the :meth:`.Scene.play_internal` method, which is the integral part of the render loop (in which the library steps through the time progression of the animation and renders the corresponding frames).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:874\nmsgid \"Within :meth:`.Scene.play_internal`, the following steps are performed:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:876\nmsgid \"The scene determines the run time of the animations by calling :meth:`.Scene.get_run_time`. This method basically takes the maximum ``run_time`` attribute of all of the animations passed to the :meth:`.Scene.play` call.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:880\nmsgid \"Then the *time progression* is constructed via the (internal) :meth:`.Scene._get_animation_time_progression` method, which wraps the actual :meth:`.Scene.get_time_progression` method. The time progression is a ``tqdm`` `progress bar object <https://tqdm.github.io>`__ for an iterator over ``np.arange(0, run_time, 1 / config.frame_rate)``. In other words, the time progression holds the time stamps (relative to the current animations, so starting at 0 and ending at the total animation run time, with the step size determined by the render frame rate) of the timeline where a new animation frame should be rendered.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:889\nmsgid \"Then the scene iterates over the time progression: for each time stamp ``t``, :meth:`.Scene.update_to_time` is called, which ...\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:892\nmsgid \"... first computes the time passed since the last update (which might be 0, especially for the initial call) and references it as ``dt``,\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:894\nmsgid \"then (in the order in which the animations are passed to :meth:`.Scene.play`) calls :meth:`.Animation.update_mobjects` to trigger all updater functions that are attached to the respective animation except for the \\\"main mobject\\\" of the animation (that is, for example, for :class:`.Transform` the unmodified copies of start and target mobject -- see :meth:`.Animation.get_all_mobjects_to_update` for more details),\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:900\nmsgid \"then the relative time progression with respect to the current animation is computed (``alpha = t / animation.run_time``), which is then used to update the state of the animation with a call to :meth:`.Animation.interpolate`.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:903\nmsgid \"After all of the passed animations have been processed, the updater functions of all mobjects in the scene, all meshes, and finally those attached to the scene itself are run.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:907\nmsgid \"At this point, the internal (Python) state of all mobjects has been updated to match the currently processed timestamp. If rendering should not be skipped, then it is now time to *take a picture*!\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:913\nmsgid \"The update of the internal state (iteration over the time progression) happens *always* once :meth:`.Scene.play_internal` is entered. This ensures that even if frames do not need to be rendered (because, e.g., the ``-n`` CLI flag has been passed, something has been cached, or because we might be in a *Section* with skipped rendering), updater functions still run correctly, and the state of the first frame that *is* rendered is kept consistent.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:920\nmsgid \"To render an image, the scene calls the corresponding method of its renderer, :meth:`.CairoRenderer.render` and passes just the list of *moving mobjects* (remember, the *static mobjects* are assumed to have already been painted statically to the background of the scene). All of the hard work then happens when the renderer updates its current frame via a call to :meth:`.CairoRenderer.update_frame`:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:926\nmsgid \"First, the renderer prepares its :class:`.Camera` by checking whether the renderer has a ``static_image`` different from ``None`` stored already. If so, it sets the image as the *background image* of the camera via :meth:`.Camera.set_frame_to_background`, and otherwise it just resets the camera via :meth:`.Camera.reset`. The camera is then asked to capture the scene with a call to :meth:`.Camera.camture_mobjects`.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:932\nmsgid \"Things get a bit technical here, and at some point it is more efficient to delve into the implementation -- but here is a summary of what happens once the camera is asked to capture the scene:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:936\nmsgid \"First, a flat list of mobjects is created (so submobjects get extracted from their parents). This list is then processed in groups of the same type of mobjects (e.g., a batch of vectorized mobjects, followed by a batch of image mobjects, followed by more vectorized mobjects, etc. -- in many cases there will just be one batch of vectorized mobjects).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:941\nmsgid \"Depending on the type of the currently processed batch, the camera uses dedicated *display functions* to convert the :class:`.Mobject` Python object to a NumPy array stored in the camera's ``pixel_array`` attribute. The most important example in that context is the display function for vectorized mobjects, :meth:`.Camera.display_multiple_vectorized_mobjects`, or the more particular (in case you did not add a background image to your :class:`.VMobject`), :meth:`.Camera.display_multiple_non_background_colored_vmobjects`. This method first gets the current Cairo context, and then, for every (vectorized) mobject in the batch, calls :meth:`.Camera.display_vectorized`. There, the actual background stroke, fill, and then stroke of the mobject is drawn onto the context. See :meth:`.Camera.apply_stroke` and :meth:`.Camera.set_cairo_context_color` for more details -- but it does not get much deeper than that, in the latter method the actual Bézier curves determined by the points of the mobject are drawn; this is where the low-level interaction with Cairo happens.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:957\nmsgid \"After all batches have been processed, the camera has an image representation of the Scene at the current time stamp in form of a NumPy array stored in its ``pixel_array`` attribute. The renderer then takes this array and passes it to its :class:`.SceneFileWriter`. This concludes one iteration of the render loop, and once the time progression has been processed completely, a final bit of cleanup is performed before the :meth:`.Scene.play_internal` call is completed.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:964\nmsgid \"A TL;DR for the render loop, in the context of our toy example, reads as follows:\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:966\nmsgid \"The scene finds that a 3 second long animation (the :class:`.ReplacementTransform` changing the orange square to the blue circle) should be played. Given the requested medium render quality, the frame rate is 30 frames per second, and so the time progression with steps ``[0, 1/30, 2/30, ..., 89/30]`` is created.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:970\nmsgid \"In the internal render loop, each of these time stamps is processed: there are no updater functions, so effectively the scene updates the state of the transformation animation to the desired time stamp (for example, at time stamp ``t = 45/30``, the animation is completed to a rate of ``alpha = 0.5``).\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:975\nmsgid \"Then the scene asks the renderer to do its job. The renderer asks its camera to capture the scene, the only mobject that needs to be processed at this point is the main mobject attached to the transformation; the camera converts the current state of the mobject to entries in a NumPy array. The renderer passes this array to the file writer.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:980\nmsgid \"At the end of the loop, 90 frames have been passed to the file writer.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:983\nmsgid \"Completing the render loop\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:985\nmsgid \"The last few steps in the :meth:`.Scene.play_internal` call are not too exciting: for every animation, the corresponding :meth:`.Animation.finish` and :meth:`.Animation.clean_up_from_scene` methods are called.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:991\nmsgid \"Note that as part of :meth:`.Animation.finish`, the :meth:`.Animation.interpolate` method is called with an argument of 1.0 -- you might have noticed already that the last frame of an animation can sometimes be a bit off or incomplete. This is by current design! The last frame rendered in the render loop (and displayed for a duration of ``1 / frame_rate`` seconds in the rendered video) corresponds to the state of the animation ``1 / frame_rate`` seconds before it ends. To display the final frame as well in the video, we would need to append another ``1 / frame_rate`` seconds to the video -- which would then mean that a 1 second rendered Manim video would be slightly longer than 1 second. We decided against this at some point.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:1001\nmsgid \"In the end, the time progression is closed (which completes the displayed progress bar) in the terminal. With the closing of the time progression, the :meth:`.Scene.play_internal` call is completed, and we return to the renderer, which now orders the :class:`.SceneFileWriter` to close the movie pipe that has been opened for this animation: a partial movie file is written.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:1007\nmsgid \"This pretty much concludes the walkthrough of a :class:`.Scene.play` call, and actually there is not too much more to say for our toy example either: at this point, a partial movie file that represents playing the :class:`.ReplacementTransform` has been written. The initialization of the :class:`.Dot` happens analogous to the initialization of ``blue_circle``, which has been discussed above. The :meth:`.Mobject.add_updater` call literally just attaches a function to the ``updaters`` attribute of the ``small_dot``. And the remaining :meth:`.Scene.play` and :meth:`.Scene.wait` calls follow the exact same procedure as discussed in the render loop section above; each such call produces a corresponding partial movie file.\"\nmsgstr \"\"\n\n#: ../../source/guides/deep_dive.rst:1018\nmsgid \"Once the :meth:`.Scene.construct` method has been fully processed (and thus all of the corresponding partial movie files have been written), the scene calls its cleanup method :meth:`.Scene.tear_down`, and then asks its renderer to finish the scene. The renderer, in turn, asks its scene file writer to wrap things up by calling :meth:`.SceneFileWriter.finish`, which triggers the combination of the partial movie files into the final product.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/guides/index.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/guides/index.rst:4\n#: ../../source/guides/index.rst:4\nmsgid \"Table of Contents\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/guides/using_text.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/guides/using_text.rst:3\nmsgid \"Rendering Text and Formulas\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:5\nmsgid \"There are two different ways by which you can render **Text** in videos:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:7\nmsgid \"Using Pango (:mod:`~.text_mobject`)\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:8\nmsgid \"Using LaTeX (:mod:`~.tex_mobject`)\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:10\nmsgid \"If you want to render simple text, you should use either :class:`~.Text` or :class:`~.MarkupText`, or one of its derivatives like :class:`~.Paragraph`. See :ref:`using-text-objects` for more information.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:14\nmsgid \"LaTeX should be used when you need mathematical typesetting. See :ref:`rendering-with-latex` for more information.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:20\nmsgid \"Text Without LaTeX\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:22\nmsgid \"The simplest way to add text to your animations is to use the :class:`~.Text` class. It uses the `Pango library`_ to render text. With Pango, you can also render non-English alphabets like 你好 or  こんにちは or 안녕하세요 or مرحبا بالعالم.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:27\nmsgid \"Here is a simple *Hello World* animation.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:38\nmsgid \"You can also use :class:`~.MarkupText` which allows the use of PangoMarkup (see the documentation of :class:`~.MarkupText` for details) to render text. For example:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:56\nmsgid \"Working with :class:`~.Text`\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:58\nmsgid \"This section explains the properties of :class:`~.Text` and how can it be used in your animations.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:62\nmsgid \"Using Fonts\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:64\nmsgid \"You can set a different font using :attr:`~.Text.font`.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:68\nmsgid \"The font used must be installed in your system, and Pango should know about it. You can get a list of fonts using :func:`manimpango.list_fonts`.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:85\nmsgid \"Setting Slant and Weight\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:86\nmsgid \"Slant is the style of the Text, and it can be ``NORMAL`` (the default), ``ITALIC`` or ``OBLIQUE``. Usually, for many fonts both ``ITALIC`` and ``OBLIQUE`` look similar, but ``ITALIC`` uses **Roman Style**, whereas ``OBLIQUE`` uses **Italic Style**.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:91\nmsgid \"Weight specifies the boldness of a font. You can see a list of weights in :class:`manimpango.Weight`.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:126\nmsgid \"Using Colors\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:128\nmsgid \"You can set the color of the text using :attr:`~.Text.color`:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:138\nmsgid \"You can use utilities like :attr:`~.Text.t2c` for coloring specific characters. This may be problematic if your text contains ligatures as explained in :ref:`iterating-text`.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:142\nmsgid \":attr:`~Text.t2c` accepts two types of dictionaries,\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:144\nmsgid \"The keys can contain indices like ``[2:-1]`` or ``[4:8]``, this works similar to how `slicing <https://realpython.com/python-strings/#string-slicing>`_ works in Python. The values should be the color of the Text from :class:`~.Color`.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:149\nmsgid \"The keys contain words or characters which should be colored separately and the values should be the color from :class:`~.Color`:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:161\nmsgid \"If you want to avoid problems when using colors (due to ligatures), consider using :class:`MarkupText`.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:166\nmsgid \"Using Gradients\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:168\nmsgid \"You can add a gradient using :attr:`~.Text.gradient`. The value must be an iterable of any length:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:179\nmsgid \"You can also use :attr:`~.Text.t2g` for gradients with specific characters of the text. It shares a similar syntax to :ref:`the interface for colors <using-colors>`:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:203\nmsgid \"Setting Line Spacing\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:205\nmsgid \"You can set the line spacing using :attr:`~.Text.line_spacing`:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:220\nmsgid \"Disabling Ligatures\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:222\nmsgid \"By disabling ligatures you would get a one-to-one mapping between characters and submobjects. This fixes the issues with coloring text.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:228\nmsgid \"Be aware that using this method with text that heavily depends on ligatures (Arabic text) may yield unexpected results.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:231\nmsgid \"You can disable ligatures by passing ``disable_ligatures`` to :class:`Text`. For example:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:246\nmsgid \"Iterating :class:`~.Text`\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:248\nmsgid \"Text objects behave like :class:`VGroups <.VGroup>`. Therefore, you can slice and index the text.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:251\nmsgid \"For example, you can set each letter to different color by iterating it.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:265\nmsgid \"Please note that `Ligature`_ can cause problems here. If you need a one-to-one mapping of characters to submobjects you should pass the ``disable_ligatures`` parameter to :class:`~.Text`. See :ref:`disable-ligatures`.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:273\nmsgid \"Working with :class:`~.MarkupText`\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:275\nmsgid \"MarkupText is similar to :class:`~.Text`, the only difference between them is that this accepts and processes PangoMarkup (which is similar to html), instead of just rendering plain text.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:279\nmsgid \"Consult the documentation of :class:`~.MarkupText` for more details and further references about PangoMarkup.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:297\nmsgid \"Text With LaTeX\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:299\nmsgid \"Just as you can use :class:`~.Text` to add text to your videos, you can use :class:`~.Tex` to insert LaTeX.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:302\nmsgid \"For example,\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:314\nmsgid \"Note that we are using a raw string (``r'...'``) instead of a regular string (``'...'``). This is because TeX code uses a lot of special characters - like ``\\\\`` for example - that have special meaning within a regular python string. An alternative would have been to write ``\\\\\\\\`` to escape the backslash: ``Tex('\\\\\\\\LaTeX')``.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:320\nmsgid \"Working with :class:`~.MathTex`\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:322\nmsgid \"Everything passed to :class:`~.MathTex` is in math mode by default. To be more precise, :class:`~.MathTex` is processed within an ``align*`` environment. You can achieve a similar effect with :class:`~.Tex` by enclosing your formula with ``$`` symbols: ``$\\\\xrightarrow{x^6y^8}$``:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:339\nmsgid \"LaTeX commands and keyword arguments\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:341\nmsgid \"We can use any standard LaTeX commands in the AMS maths packages. Such as the ``mathtt`` math-text type or the ``looparrowright`` arrow.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:352\nmsgid \"On the Manim side, the :class:`~.Tex` class also accepts attributes to change the appearance of the output. This is very similar to the :class:`~.Text` class. For example, the ``color`` keyword changes the color of the TeX mobject.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:366\nmsgid \"Extra LaTeX Packages\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:368\nmsgid \"Some commands require special packages to be loaded into the TeX template. For example, to use the ``mathscr`` script, we need to add the ``mathrsfs`` package. Since this package isn't loaded into Manim's tex template by default, we have to add it manually.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:388\nmsgid \"Substrings and parts\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:390\nmsgid \"The TeX mobject can accept multiple strings as arguments. Afterwards you can refer to the individual parts either by their index (like ``tex[1]``), or by selecting parts of the tex code. In this example, we set the color of the ``\\\\bigstar`` using :func:`~.set_color_by_tex`:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:404\nmsgid \"Note that :func:`~.set_color_by_tex` colors the entire substring containing the Tex, not just the specific symbol or Tex expression. Consider the following example:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:418\nmsgid \"As you can see, this colors the entire equation yellow, contrary to what may be expected. To color only ``x`` yellow, we have to do the following:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:433\nmsgid \"By setting ``substrings_to_isolate`` to ``x``, we split up the :class:`~.MathTex` into substrings automatically and isolate the ``x`` components into individual substrings. Only then can :meth:`~.set_color_by_tex` be used to achieve the desired result.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:438\nmsgid \"Note that Manim also supports a custom syntax that allows splitting a TeX string into substrings easily: simply enclose parts of your formula that you want to isolate with double braces. In the string ``MathTex(r\\\"{{ a^2 }} + {{ b^2 }} = {{ c^2 }}\\\")``, the rendered mobject will consist of the substrings ``a^2``, ``+``, ``b^2``, ``=``, and ``c^2``. This makes transformations between similar text fragments easy to write using :class:`~.TransformMatchingTex`.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:447\nmsgid \"Using ``index_labels`` to work with complicated strings\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:449\nmsgid \"You might sometimes be working with a very complicated :class:`~.MathTex` mobject that makes it difficult to work with its individual components. This is where the debugging function :func:`.index_labels` is very useful.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:453\nmsgid \"The method shows the index of a mobject's submobjects, allowing you to easily find the components of the mobject you would like to change.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:472\nmsgid \"LaTeX Maths Fonts - The Template Library\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:474\nmsgid \"Changing fonts in LaTeX when typesetting mathematical formulae is trickier than regular text. It requires changing the template that is used to compile the TeX. Manim comes with a collection of :class:`~.TexFontTemplates` ready for you to use. These templates will all work in math mode:\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:491\nmsgid \"Manim also has a :class:`~.TexTemplateLibrary` containing the TeX templates used by 3Blue1Brown. One example is the ctex template, used for typesetting Chinese script. For this to work, the ctex LaTeX package must be installed on your system. Furthermore, if you are only typesetting Text, you probably do not need :class:`~.Tex` at all, and should use :class:`~.Text` instead.\"\nmsgstr \"\"\n\n#: ../../source/guides/using_text.rst:508\nmsgid \"Aligning formulae\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/index.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/index.rst:7\nmsgid \"Manim Community Edition\"\nmsgstr \"\"\n\n#: ../../source/index.rst:9\nmsgid \"Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. Manim relies on Python's simplicity to generate animations programmatically, making it convenient to specify exactly how each one should run. Take a look at the :doc:`Example Gallery <../examples>` for some inspiration on how to create beautiful images and videos with Manim.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:17\nmsgid \"First Steps\"\nmsgstr \"\"\n\n#: ../../source/index.rst:19\nmsgid \"Are you new to Manim and are looking for where to get started? Then you are in the right place!\"\nmsgstr \"\"\n\n#: ../../source/index.rst:24\nmsgid \"Please be aware that there are different, incompatible versions of Manim available. Check our :ref:`installation FAQ <different-versions>` to learn more!\"\nmsgstr \"\"\n\n#: ../../source/index.rst:28\nmsgid \"The :doc:`Installation <installation>` section has the latest and up-to-date installation instructions for Windows, MacOS, and Linux. You can also find information on Manim's docker images and (online) notebook environments there.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:32\nmsgid \"Want to try the library before installing it? Take a look at our interactive online playground at https://try.manim.community in form of a Jupyter notebook.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:35\nmsgid \"In our :doc:`Tutorials <tutorials/index>` section you will find a collection of resources that will teach you how to use Manim. In particular, the :doc:`tutorials/quickstart` tutorial teaches you Manim's basics, and in :doc:`tutorials/building_blocks` the classes used to compose your animations are described in more detail.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:43\nmsgid \"Finding Help\"\nmsgstr \"\"\n\n#: ../../source/index.rst:45\nmsgid \"Are you struggling with installing or using Manim? Don't worry, we've all been there. Here are some good resources to help you out:\"\nmsgstr \"\"\n\n#: ../../source/index.rst:48\nmsgid \"Perhaps your problem is one that occurs frequently, then chances are it is addressed in our :doc:`collection of FAQs <faq/index>`.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:50\nmsgid \"If you are looking for information on some specific class, look for it in the :doc:`reference manual <reference>` and/or use the search feature of the documentation.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:53\nmsgid \"Still no luck? Then you are welcome to ask the community for help, together we usually manage to find a solution for your problem! Consult the :doc:`FAQ page on getting help <faq/help>` for instructions.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:59\nmsgid \"Navigating the Documentation\"\nmsgstr \"\"\n\n#: ../../source/index.rst:61\nmsgid \"Here are some short summaries for all of the sections in this documentation:\"\nmsgstr \"\"\n\n#: ../../source/index.rst:63\nmsgid \"The :doc:`Example Gallery </examples>` is a collection of examples (rendered videos and images together with the code they were generated from) that show a few different, simple things that you can do with Manim.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:66\nmsgid \"The :doc:`Installation </installation>` section has information on installing Manim.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:67\nmsgid \"In :doc:`Tutorials & Guides </tutorials_guides>` you can find learning resources: proper tutorials that guide you through the process of creating a video are in the :doc:`Tutorial </tutorials/index>` section; guides on specific topics are in the :doc:`Guides </guides/index>` section, and the answers to frequently asked questions can be found in the :doc:`FAQ </faq/index>` section.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:72\nmsgid \"The :doc:`Reference Manual </reference>` contains a comprehensive list of all of Manim's (documented) modules, classes, and functions. If you are somewhat familiar with Manim's module structure feel free to browse the manual directly. If you are searching for something specific, feel free to use the documentation's search feature in the sidebar. Many classes and methods come with their own illustrated examples too!\"\nmsgstr \"\"\n\n#: ../../source/index.rst:77\nmsgid \"The :doc:`Plugins </plugins>` page documents how to install, write, and distribute plugins (that is, separate Python packages that extend the feature set of the core library).\"\nmsgstr \"\"\n\n#: ../../source/index.rst:79\nmsgid \"Changes between versions are documented in our :doc:`Changelog </changelog>`.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:80\nmsgid \"If you are looking into contributing to the development of Manim, you can find information on how to get involved in our :doc:`Contributing </contributing>` section.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:82\nmsgid \"And finally, the :doc:`Code of Conduct </conduct>` page has a formal description of the rules you should abide by when interacting within our community.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:86\nmsgid \"Sharing Your Work\"\nmsgstr \"\"\n\n#: ../../source/index.rst:88\nmsgid \"We'd love to hear from you and see your manimations `on Twitter <https://twitter.com/manim_community>`_, `Reddit <https://www.reddit.com/r/manim/>`_, or `Discord <https://www.manim.community/discord/>`_. If you're using Manim in a scientific context, instructions on how to cite a particular release can be found `in our README <https://github.com/ManimCommunity/manim/blob/main/README.md>`_.\"\nmsgstr \"\"\n\n#: ../../source/index.rst:95\nmsgid \"Index\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/installation/docker.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/installation/docker.rst:2\nmsgid \"Docker\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:4\nmsgid \"The community maintains a docker image, which can be found `on DockerHub <https://hub.docker.com/r/manimcommunity/manim>`__. For our image ``manimcommunity/manim``, there are the following tags:\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:8\nmsgid \"``latest``: the most recent version corresponding to `the main branch <https://github.com/ManimCommunity/manim>`__,\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:10\nmsgid \"``stable``: the latest released version (according to `the releases page <https://github.com/ManimCommunity/manim/releases>`__),\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:12\nmsgid \"``vX.Y.Z``: any particular released version (according to `the releases page <https://github.com/ManimCommunity/manim/releases>`__).\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:17\nmsgid \"When using Manim's CLI within a Docker container, some flags like ``-p`` (preview file) and ``-f`` (show output file in the file browser) are not supported.\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:23\nmsgid \"Basic usage of the Docker container\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:25\nmsgid \"Assuming that you can access the docker installation on your system from a terminal (bash / PowerShell) via ``docker``, you can render a scene ``CircleToSquare`` in a file `test_scenes.py` with the following command.\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:36\nmsgid \"For Linux users there might be permission problems when letting the user in the container write to the mounted volume. Add ``--user=\\\"$(id -u):$(id -g)\\\"`` to the ``docker`` CLI arguments to prevent the creation of output files not belonging to your user.\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:42\nmsgid \"Instead of using the \\\"throwaway container\\\" approach outlined above, you can also create a named container that you can modify to your liking. First, run\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:51\nmsgid \"to obtain an interactive shell inside your container allowing you to, e.g., install further dependencies (like texlive packages using ``tlmgr``). Exit the container as soon as you are satisfied. Then, before using it, start the container by running\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:60\nmsgid \"which starts the container in the background. Then, to render a scene ``CircleToSquare`` in a file ``test_scenes.py``, run\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:69\nmsgid \"Running JupyterLab via Docker\"\nmsgstr \"\"\n\n#: ../../source/installation/docker.rst:71\nmsgid \"Another alternative to using the Docker image is to spin up a local JupyterLab instance. To do that, simply run\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/installation/jupyter.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/installation/jupyter.rst:2\nmsgid \"Jupyter Notebooks\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:6\nmsgid \"Binder\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:8\nmsgid \"`Binder <https://mybinder.readthedocs.io/en/latest/>`__ is an online platform that hosts shareable and customizable computing environments in the form of Jupyter notebooks. Manim ships with a built-in ``%%manim`` Jupyter magic command which makes it easy to use in these notebooks.\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:13\nmsgid \"To see an example for such an environment, visit our interactive tutorial over at https://try.manim.community/.\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:16\nmsgid \"It is relatively straightforward to prepare your own notebooks in a way that allows them to be shared interactively via Binder as well:\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:19\nmsgid \"First, prepare a directory containing one or multiple notebooks which you would like to share in an interactive environment. You can create these notebooks by using Jupyter notebooks with a local installation of Manim, or also by working in our pre-existing `interactive tutorial environment <https://try.manim.community/>`__.\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:24\nmsgid \"In the same directory containing your notebooks, add a file named ``Dockerfile`` with the following content:\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:33\nmsgid \"Don't forget to change the version tag ``v0.9.0`` to the version you were working with locally when creating your notebooks.\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:35\nmsgid \"Make the directory with your worksheets and the ``Dockerfile`` available to the public (and in particular: to Binder!). There are `several different options to do so <https://mybinder.readthedocs.io/en/latest/introduction.html#how-can-i-prepare-a-repository-for-binder>`__, within the community we usually work with GitHub repositories or gists.\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:41\nmsgid \"Once your material is publicly available, visit https://mybinder.org and follow the instructions there to generate an interactive environment for your worksheets.\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:47\nmsgid \"The repository containing our `interactive tutorial <https://try.manim.community>`__ can be found at https://github.com/ManimCommunity/jupyter_examples.\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:53\nmsgid \"Google Colaboratory\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:55\nmsgid \"It is also possible to install Manim in a `Google Colaboratory <https://colab.research.google.com/>`__ environment. In contrast to Binder, where you can customize and prepare the environment beforehand (such that Manim is already installed and ready to be used), you will have to take care of that every time you start a new notebook in Google Colab. Fortunately, this is not particularly difficult.\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:63\nmsgid \"After creating a new notebook, paste the following code block in a cell, then execute it.\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:76\nmsgid \"You should start to see Colab installing all the dependencies specified in these commands. After the execution has completed, you will be prompted to restart the runtime. Click the \\\"restart runtime\\\" button at the bottom of the cell output. You are now ready to use Manim in Colab!\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:81\nmsgid \"To check that everything works as expected, first import Manim by running\"\nmsgstr \"\"\n\n#: ../../source/installation/jupyter.rst:87\nmsgid \"in a new code cell. Then create another cell containing the following code::\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/installation/linux.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/installation/linux.rst:2\nmsgid \"Linux\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:4\nmsgid \"The installation instructions depend on your particular operating system and package manager. If you happen to know exactly what you are doing, you can also simply ensure that your system has:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:8\nmsgid \"a reasonably recent version of Python 3 (3.7–3.10),\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:9\nmsgid \"with working Cairo bindings in the form of `pycairo <https://cairographics.org/pycairo/>`__,\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:11\nmsgid \"FFmpeg accessible from the command line as ``ffmpeg``,\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:12\nmsgid \"and `Pango <https://pango.gnome.org>`__ headers.\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:14\nmsgid \"Then, installing Manim is just a matter of running:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:22\nmsgid \"In light of the current efforts of migrating to rendering via OpenGL, this list might be incomplete. Please `let us know <https://github.com/ManimCommunity/manim/issues/new/choose>` if you ran into missing dependencies while installing.\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:27\nmsgid \"In any case, we have also compiled instructions for several common combinations of operating systems and package managers below.\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:31\nmsgid \"Required Dependencies\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:34\nmsgid \"apt – Ubuntu / Mint / Debian\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:36\nmsgid \"To first update your sources, and then install Cairo, Pango, and FFmpeg simply run:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:44\nmsgid \"If you don't have python3-pip installed, install it via:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:50\nmsgid \"Then, to install Manim, run:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:56\n#: ../../source/installation/linux.rst:90\n#: ../../source/installation/linux.rst:123\nmsgid \"Continue by reading the :ref:`optional dependencies <linux-optional-dependencies>` section.\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:60\nmsgid \"dnf – Fedora / CentOS / RHEL\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:62\nmsgid \"To install Cairo and Pango:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:68\nmsgid \"In order to successfully build the ``pycairo`` wheel, you will also need the Python development headers:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:75\nmsgid \"FFmpeg is only available via the RPMfusion repository which you have to configure first – please consult https://rpmfusion.org/Configuration/ for instructions. Then, install FFmpeg:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:83\nmsgid \"At this point you have all required dependencies and can install Manim by running:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:94\nmsgid \"pacman – Arch / Manjaro\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:98\nmsgid \"Thanks to *groctel*, there is a `dedicated Manim package on the AUR! <https://aur.archlinux.org/packages/manim/>`\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:101\nmsgid \"If you don't want to use the packaged version from AUR, here is what you need to do manually: Update your package sources, then install Cairo, Pango, and FFmpeg:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:110\nmsgid \"If you don't have ``python-pip`` installed, get it by running:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:116\nmsgid \"then simply install Manim via:\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:130\nmsgid \"Optional Dependencies\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:132\nmsgid \"In order to make use of Manim's interface to LaTeX for, e.g., rendering equations, LaTeX has to be installed as well. Note that this is an optional dependency: if you don't intend to use LaTeX, you don't have to install it.\"\nmsgstr \"\"\n\n#: ../../source/installation/linux.rst:136\nmsgid \"You can use whichever LaTeX distribution you like or whichever is easiest to install with your package manager. Usually, `TeX Live <https://www.tug.org/texlive/>`__ is a good candidate if you don't care too much about disk space.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/installation/macos.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/installation/macos.rst:2\nmsgid \"MacOS\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:4\nmsgid \"For the sake of simplicity, the following instructions assume that you have the popular `package manager Homebrew <https://brew.sh>`__ installed. While you can certainly also install all dependencies without it, using Homebrew makes the process much easier.\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:9\nmsgid \"If you want to use Homebrew but do not have it installed yet, please follow `Homebrew's installation instructions <https://docs.brew.sh/Installation>`__.\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:14\nmsgid \"For a while after Apple released its new ARM-based processors (the *\\\"M1 chip\\\"*), the recommended way of installing Manim relied on *Rosetta*, Apple's compatibility layer between Intel and ARM architectures. This is no longer necessary, Manim can (and is recommended to) be installed natively.\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:21\nmsgid \"Required Dependencies\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:23\nmsgid \"To install all required dependencies for installing Manim (namely: ffmpeg, Python, and some required Python packages), run:\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:30\nmsgid \"On *Apple Silicon* based machines (i.e., devices with the M1 chip or similar; if you are unsure which processor you have check by opening the Apple menu, select *About This Mac* and check the entry next to *Chip*), some additional dependencies are required, namely:\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:39\nmsgid \"After all required dependencies are installed, simply run:\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:45\nmsgid \"to install Manim.\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:49\nmsgid \"A frequent source for installation problems is if ``pip3`` does not point to the correct Python installation on your system. To check this, run ``pip3 -V``: for MacOS Intel, the path should start with ``/usr/local``, and for Apple Silicon with ``/opt/homebrew``. If this is not the case, you either forgot to modify your shell profile (``.zprofile``) during the installation of Homebrew, or did not reload your shell (e.g., by opening a new terminal) after doing so. It is also possible that some other software (like Pycharm) changed the ``PATH`` variable – to fix this, make sure that the Homebrew-related lines in your ``.zprofile`` are at the very end of the file.\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:63\nmsgid \"Optional Dependencies\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:65\nmsgid \"In order to make use of Manim's interface to LaTeX for, e.g., rendering equations, LaTeX has to be installed as well. Note that this is an optional dependency: if you don't intend to use LaTeX, you don't have to install it.\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:69\nmsgid \"For MacOS, the recommended LaTeX distribution is `MacTeX <http://www.tug.org/mactex/>`__. You can install it by following the instructions from the link, or alternatively also via Homebrew by running:\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:80\nmsgid \"MacTeX is a *full* LaTeX distribution and will require more than 4GB of disk space. If this is an issue for you, consider installing a smaller distribution like `BasicTeX <http://www.tug.org/mactex/morepackages.html>`__.\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:85\nmsgid \"Should you choose to work with some partial TeX distribution, the full list of LaTeX packages which Manim interacts with in some way (a subset might be sufficient for your particular application) is::\"\nmsgstr \"\"\n\n#: ../../source/installation/macos.rst:96\nmsgid \"Working with Manim\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/installation/troubleshooting.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/installation/versions.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/installation/windows.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/installation/windows.rst:2\nmsgid \"Windows\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:4\nmsgid \"The easiest way of installing Manim and its dependencies is by using a package manager like `Chocolatey <https://chocolatey.org/>`__ or `Scoop <https://scoop.sh>`__. If you are not afraid of editing your System's ``PATH``, a manual installation is also possible. In fact, if you already have an existing Python installation (3.7-3.10), it might be the easiest way to get everything up and running.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:12\nmsgid \"If you choose to use one of the package managers, please follow their installation instructions (`for Chocolatey <https://chocolatey.org/install#install-step2>`__, `for Scoop <https://scoop-docs.now.sh/docs/getting-started/Quick-Start.html>`__) to make one of them available on your system.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:20\nmsgid \"Required Dependencies\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:22\nmsgid \"Manim requires a recent version of Python (3.7–3.10) and ``ffmpeg`` in order to work.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:26\nmsgid \"Chocolatey\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:28\nmsgid \"Manim can be installed via Chocolatey simply by running:\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:34\nmsgid \"That's it, no further steps required. You can continue with installing the :ref:`optional dependencies <win-optional-dependencies>` below.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:38\nmsgid \"Scoop\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:40\nmsgid \"While there is no recipe for installing Manim with Scoop directly, you can install all requirements by running:\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:47\nmsgid \"and then Manim can be installed by running:\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:53\nmsgid \"Manim should now be installed on your system. Continue reading the :ref:`optional dependencies <win-optional-dependencies>` section below.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:58\nmsgid \"Manual Installation\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:60\nmsgid \"As mentioned above, Manim needs a reasonably recent version of Python 3 (3.7–3.10) and FFmpeg.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:63\nmsgid \"**Python:** Head over to https://www.python.org, download an installer for Python (3.7–3.10), and follow its instructions to get Python installed on your system.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:69\nmsgid \"We have received reports of problems caused by using the version of Python that can be installed from the Windows Store. At this point, we recommend staying away from the Windows Store version. Instead, install Python directly from the `official website <https://www.python.org>`__.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:75\nmsgid \"**FFmpeg:** In order to install FFmpeg, you can get a pre-compiled and ready-to-use version from one of the resources linked at https://ffmpeg.org/download.html#build-windows, such as `the version available here <https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.7z>`__ (recommended), or if you know exactly what you are doing you can alternatively get the source code from https://ffmpeg.org/download.html and compile it yourself.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:85\nmsgid \"After downloading the pre-compiled archive, `unzip it <https://www.7-zip.org>`__ and, if you like, move the extracted directory to some more permanent place (e.g., ``C:\\\\Program Files\\\\``). Next, edit the ``PATH`` environment variable: first, visit ``Control Panel`` > ``System`` > ``System settings`` > ``Environment Variables``, then add the full path to the ``bin`` directory inside of the (moved) ffmpeg directory to the ``PATH`` variable. Finally, save your changes and exit.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:94\nmsgid \"If you now open a new command line prompt (or PowerShell) and run ``ffmpeg``, the command should be recognized.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:97\nmsgid \"At this point, you have all the required dependencies and can now install Manim via\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:108\nmsgid \"Optional Dependencies\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:110\nmsgid \"In order to make use of Manim's interface to LaTeX to, for example, render equations, LaTeX has to be installed as well. Note that this is an optional dependency: if you don't intend to use LaTeX, you don't have to install it.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:114\nmsgid \"For Windows, the recommended LaTeX distribution is `MiKTeX <https://miktex.org/download>`__. You can install it by using the installer from the linked MiKTeX site, or by using the package manager of your choice (Chocolatey: ``choco install miktex.install``, Scoop: ``scoop install latex``).\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:120\nmsgid \"If you are concerned about disk space, there are some alternative, smaller distributions of LaTeX.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:123\nmsgid \"**Using Chocolatey:** If you used Chocolatey to install manim or are already a chocolatey user, then you can simply run ``choco install manim-latex``. It is a dedicated package for Manim based on TinyTeX which contains all the required packages that Manim interacts with.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:128\nmsgid \"**Manual Installation:** You can also use `TinyTeX <https://yihui.org/tinytex/>`__ (Chocolatey: ``choco install tinytex``, Scoop: first ``scoop bucket add r-bucket https://github.com/cderv/r-bucket.git``, then ``scoop install tinytex``) alternative installation instructions can be found at their website. Keep in mind that you will have to manage the LaTeX packages installed on your system yourself via ``tlmgr``. Therefore we only recommend this option if you know what you are doing.\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:135\nmsgid \"The full list of LaTeX packages which Manim interacts with in some way (a subset might be sufficient for your particular application) are::\"\nmsgstr \"\"\n\n#: ../../source/installation/windows.rst:146\nmsgid \"Working with Manim\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/installation.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/installation.rst:2\nmsgid \"Installation\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:4\nmsgid \"Depending on your use case, different installation options are recommended: if you just want to play around with Manim for a bit, interactive in-browser notebooks are a really simple way of exploring the library as they require no local installation. Head over to https://try.manim.community to give our interactive tutorial a try.\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:10\nmsgid \"Otherwise, if you intend to use Manim to work on an animation project, we recommend installing the library locally (either to your system's Python, or via Docker).\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:16\nmsgid \"Note that there are several different versions of Manim. The instructions on this website are **only** for the *community edition*. Find out more about the :ref:`differences between Manim versions <different-versions>` if you are unsure which version you should install.\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:22\nmsgid \":ref:`Installing Manim to your system's Python <local-installation>`\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:23\nmsgid \":ref:`Using Manim via Docker <docker-installation>`\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:24\nmsgid \":ref:`Interactive Jupyter notebooks via Binder / Google Colab <interactive-online>`\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:31\nmsgid \"Installing Manim locally\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:33\nmsgid \"Manim is a Python library, and it can be `installed via pip <https://pypi.org/project/manim/>`__. However, in order for Manim to work properly, some additional system dependencies need to be installed first. The following pages have operating system specific instructions for you to follow.\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:39\nmsgid \"Manim requires Python version ``3.7`` or above to run.\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:43\nmsgid \"Depending on your particular setup, the installation process might be slightly different. Make sure that you have tried to follow the steps on the following pages carefully, but in case you hit a wall we are happy to help: either `join our Discord <https://www.manim.community/discord/>`__, or start a new Discussion `directly on GitHub <https://github.com/ManimCommunity/manim/discussions>`__.\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:58\nmsgid \"Once Manim is installed locally, you can proceed to our :doc:`quickstart guide <tutorials/quickstart>` which walks you through rendering a first simple scene.\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:62\nmsgid \"As mentioned above, do not worry if there are errors or other problems: consult our :doc:`FAQ section </faq/index>` for help (including instructions for how to ask Manim's community for help).\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:71\nmsgid \"Using Manim via Docker\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:73\nmsgid \"`Docker <https://www.docker.com>`__ is a virtualization tool that allows the distribution of encapsulated software environments (containers).\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:76\nmsgid \"The following pages contain more information about the docker image maintained by the community, ``manimcommunity/manim``:\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:87\nmsgid \"Interactive Jupyter notebooks for your browser\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:89\nmsgid \"Manim ships with a built-in ``%%manim`` IPython magic command designed for the use within `Jupyter notebooks <https://jupyter.org>`__. Our interactive tutorial over at https://try.manim.community illustrates how Manim can be used from within a Jupyter notebook.\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:94\nmsgid \"The following pages explain how you can setup interactive environments like that yourself:\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:104\nmsgid \"Editors\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:106\nmsgid \"If you're using Visual Studio Code you can install an extension called *Manim Sideview* which provides automated rendering and an integrated preview of the animation inside the editor. The extension can be installed through the `marketplace of VS Code <https://marketplace.visualstudio.com/items?itemName=Rickaym.manim-sideview>`__.\"\nmsgstr \"\"\n\n#: ../../source/installation.rst:113\nmsgid \"Installation for developers\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/internals.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/plugins.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/plugins.rst:5\nmsgid \"Plugins\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:7\nmsgid \"Plugins are features that extend Manim's core functionality. Since Manim is extensible and not everything belongs in its core, we'll go over how to install, use, and create your own plugins.\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:13\nmsgid \"The standard naming convention for plugins is to prefix the plugin with ``manim-``. This makes them easy for users to find on package repositories such as PyPI.\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:19\nmsgid \"The plugin feature is new and under active development. Expect updates for the best practices on installing, using, and creating plugins; as well as new subcommands/flags for ``manim plugins``\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:25\nmsgid \"See https://plugins.manim.community/ for the list of plugins available.\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:28\nmsgid \"Installing Plugins\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:29\nmsgid \"Plugins can be easily installed via the ``pip`` command:\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:36\nmsgid \"After installing a plugin, you may use the ``manim plugins`` command to list your available plugins, see the following help output:\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:52\nmsgid \"You can list plugins as such:\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:61\nmsgid \"Using Plugins in Projects\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:62\nmsgid \"For enabling a plugin ``manim.cfg`` or command line parameters should be used.\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:66\nmsgid \"The plugins should be module name of the plugin and not PyPi name.\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:68\nmsgid \"Enabling plugins through ``manim.cfg``\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:75\nmsgid \"For specifying multiple plugins, comma-separated values must be used.\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:83\nmsgid \"Creating Plugins\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:84\nmsgid \"Plugins are intended to extend Manim's core functionality. If you aren't sure whether a feature should be included in Manim's core, feel free to ask over on the `Discord server <https://www.manim.community/discord/>`_. Visit `manim-plugintemplate <https://pypi.org/project/manim-plugintemplate/>`_ on PyPI.org which serves as an in-depth tutorial for creating plugins.\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:94\nmsgid \"The only requirement of manim plugins is that they specify an entry point with the group, ``\\\"manim.plugins\\\"``. This allows Manim to discover plugins available in the user's environment. Everything regarding the plugin's directory structure, build system, and naming are completely up to your discretion as an author. The aforementioned template plugin is only a model using Poetry since this is the build system Manim uses. The plugin's `entry point <https://packaging.python.org/specifications/entry-points/>`_ can be specified in poetry as:\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:108\nmsgid \"Here ``name`` is the name of the module of the plugin.\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:110\nmsgid \"Here ``object_reference`` can point to either a function in a module or a module itself. For example,\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:118\nmsgid \"Here a module is used as ``object_reference``, and when this plugin is enabled, Manim will look for ``__all__`` keyword defined in ``manim_plugintemplate`` and everything as a global variable one by one.\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:122\nmsgid \"If ``object_reference`` is a function, Manim calls the function and expects the function to return a list of modules or functions that need to be defined globally.\"\nmsgstr \"\"\n\n#: ../../source/plugins.rst:125\nmsgid \"For example,\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim._config.logger_utils.JSONFormatter.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim._config.logger_utils.JSONFormatter.rst:2\nmsgid \"JSONFormatter\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.logger_utils.JSONFormatter.rst:4\nmsgid \"Qualified name: ``manim.\\\\_config.logger\\\\_utils.JSONFormatter``\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:1\nmsgid \"Bases: :py:class:`logging.Formatter`\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:1\nmsgid \"A formatter that outputs logs in a custom JSON format.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:3\nmsgid \"This class is used internally for testing purposes.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:6\nmsgid \"Initialize the formatter with specified format strings.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:8\nmsgid \"Initialize the formatter either with the specified format string, or a default as described above. Allow for specialized date formatting with the optional datefmt argument. If datefmt is omitted, you get an ISO8601-like (or RFC 3339-like) format.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:13\nmsgid \"Use a style parameter of '%', '{' or '$' to specify that you want to use one of %-formatting, :meth:`str.format` (``{}``) formatting or :class:`string.Template` formatting in your format string.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter:17\nmsgid \"Added the ``style`` parameter.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.logger_utils.JSONFormatter.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.logger_utils.JSONFormatter.rst:20:<autosummary>:1\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter.format:1\nmsgid \"Format the record in a custom JSON format.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.logger_utils.JSONFormatter.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.JSONFormatter.format:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim._config.logger_utils.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim._config.logger_utils.rst:2\nmsgid \"logger\\\\_utils\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils:1\nmsgid \"Utilities to create and set the logger.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils:3\nmsgid \"Manim's logger can be accessed as ``manim.logger``, or as ``logging.getLogger(\\\"manim\\\")``, once the library has been imported.  Manim also exports a second object, ``console``, which should be used to print on screen messages that need not be logged.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils:8\nmsgid \"Both ``logger`` and ``console`` use the ``rich`` library to produce rich text format.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.logger_utils.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.logger_utils.rst:26:<autosummary>:1\nmsgid \"A formatter that outputs logs in a custom JSON format.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.logger_utils.rst:29\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:1\nmsgid \"Make the manim logger and console.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:0\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:0\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.set_file_logger:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:3\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:3\nmsgid \"A parser containing any .cfg files in use.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:5\nmsgid \"The verbosity level of the logger.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:0\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:8\nmsgid \"The manim logger and consoles. The first console outputs to stdout, the second to stderr. All use the theme returned by :func:`parse_theme`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:0\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:0\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.set_file_logger:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:16\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.make_logger:17\nmsgid \"The ``parser`` is assumed to contain only the options related to configuring the logger at the top level.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:1\nmsgid \"Configure the rich style of logger and console output.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.parse_theme:6\nmsgid \"The rich theme to be used by the manim logger.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.set_file_logger:1\nmsgid \"Add a file handler to manim logger.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/logger_utils.py:docstring of manim._config.logger_utils.set_file_logger:3\nmsgid \"The path to the file is built using ``config.log_dir``.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim._config.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim._config.rst:2\nmsgid \"\\\\_config\"\nmsgstr \"\"\n\n#: ../../../manim/_config/__init__.py:docstring of manim._config:1\nmsgid \"Set the global config and logger.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:1\nmsgid \"Context manager that temporarily modifies the global ``config`` object.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:3\nmsgid \"Inside the ``with`` statement, the modified config will be used.  After context manager exits, the config will be restored to its original state.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:6\nmsgid \"Object whose keys will be used to temporarily update the global ``config``.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/_config/__init__.py:docstring of manim._config.tempconfig:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim._config.utils.ManimConfig.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim._config.utils.ManimConfig.rst:2\nmsgid \"ManimConfig\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimConfig.rst:4\nmsgid \"Qualified name: ``manim.\\\\_config.utils.ManimConfig``\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:1\nmsgid \"Bases: :py:class:`collections.abc.MutableMapping`\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:1\nmsgid \"Dict-like class storing all config options.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:3\nmsgid \"The global ``config`` object is an instance of this class, and acts as a single source of truth for all of the library's customizable behavior.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:6\nmsgid \"The global ``config`` object is capable of digesting different types of sources and converting them into a uniform interface.  These sources are (in ascending order of precedence): configuration files, command line arguments, and programmatic changes.  Regardless of how the user chooses to set a config option, she can access its current value using :class:`ManimConfig`'s attributes and properties.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:14\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:9\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:15\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:16\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:18\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:19\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:15\nmsgid \"Each config option is implemented as a property of this class.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:17\nmsgid \"Each config option can be set via a config file, using the full name of the property.  If a config option has an associated CLI flag, then the flag is equal to the full name of the property.  Those that admit an alternative flag or no flag at all are documented in the individual property's docstring.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:24\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:25\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:25\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:25\nmsgid \"We use a copy of the global configuration object in the following examples for the sake of demonstration; you can skip these lines and just import ``config`` directly if you actually want to modify the configuration:\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:35\nmsgid \"Each config option allows for dict syntax and attribute syntax.  For example, the following two lines are equivalent,\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:44\nmsgid \"The former is preferred; the latter is provided mostly for backwards compatibility.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:47\nmsgid \"The config options are designed to keep internal consistency.  For example, setting ``frame_y_radius`` will affect ``frame_height``:\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:58\nmsgid \"There are many ways of interacting with config options.  Take for example the config option ``background_color``.  There are three ways to change it: via a config file, via CLI flags, or programmatically.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:62\nmsgid \"To set the background color via a config file, save the following ``manim.cfg`` file with the following contents.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:70\nmsgid \"In order to have this ``.cfg`` file apply to a manim scene, it needs to be placed in the same directory as the script,\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:79\nmsgid \"Now, when the user executes\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:85\nmsgid \"the background of the scene will be set to ``WHITE``.  This applies regardless of where the manim command is invoked from.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:88\nmsgid \"Command line arguments override ``.cfg`` files.  In the previous example, executing\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:95\nmsgid \"will set the background color to BLUE, regardless of the contents of ``manim.cfg``.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:98\nmsgid \"Finally, any programmatic changes made within the scene script itself will override the command line arguments.  For example, if ``scene.py`` contains the following\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:111\nmsgid \"the background color will be set to RED, regardless of the contents of ``manim.cfg`` or the CLI arguments used when invoking manim.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimConfig.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimConfig.rst:26:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:1\nmsgid \"Deepcopy the contents of this ManimConfig.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimConfig.rst:26:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:1\nmsgid \"Process the config options present in CLI arguments.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimConfig.rst:26:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:1\nmsgid \"Process the config options present in a ``.cfg`` file.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimConfig.rst:26:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:1\nmsgid \"Process the config options present in a :class:`ConfigParser` object.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimConfig.rst:26:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:1\nmsgid \"Resolve a config option that stores a directory.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimConfig.rst:26:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:1\nmsgid \"Digest the options found in another :class:`ManimConfig` or in a dict.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimConfig.rst:28\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1\nmsgid \"Aspect ratio (width / height) in pixels (--resolution, -r).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.assets_dir:1\nmsgid \"Directory to locate video assets (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.background_color:1\nmsgid \"Background color of the scene (-c).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.background_opacity:1\nmsgid \"A number between 0.0 (fully transparent) and 1.0 (fully opaque).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.bottom:1\nmsgid \"Coordinate at the center bottom of the frame.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.custom_folders:1\nmsgid \"Whether to use custom folder output.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.disable_caching:1\nmsgid \"Whether to use scene caching.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.disable_caching_warning:1\nmsgid \"Whether a warning is raised if there are too much submobjects to hash.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.dry_run:1\nmsgid \"Whether dry run is enabled.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.enable_gui:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.gui_location:1\nmsgid \"Enable GUI interaction.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.enable_wireframe:1\nmsgid \"Enable wireframe debugging mode in opengl.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.ffmpeg_executable:1\nmsgid \"Manually specify the path to the ffmpeg executable\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.ffmpeg_loglevel:1\nmsgid \"Verbosity level of ffmpeg (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.flush_cache:1\nmsgid \"Whether to delete all the cached partial movie files.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.force_window:1\nmsgid \"Set to force window when using the opengl renderer\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.format:1\nmsgid \"File format; \\\"png\\\", \\\"gif\\\", \\\"mp4\\\", \\\"webm\\\" or \\\"mov\\\".\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_height:1\nmsgid \"Frame height in logical units (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_rate:1\nmsgid \"Frame rate in frames per second.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_size:1\nmsgid \"Tuple with (pixel width, pixel height) (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_width:1\nmsgid \"Frame width in logical units (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_x_radius:1\nmsgid \"Half the frame width (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.frame_y_radius:1\nmsgid \"Half the frame height (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.from_animation_number:1\nmsgid \"Start rendering animations at this number (-n).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.fullscreen:1\nmsgid \"Expand the window to its maximum possible size.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Directory to place images (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.input_file:1\nmsgid \"Input file name.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.left_side:1\nmsgid \"Coordinate at the middle left of the frame.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Directory to place logs.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.log_to_file:1\nmsgid \"Whether to save logs to a file.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Maximum number of files cached.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Main output directory.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.media_embed:1\nmsgid \"Embed videos in Jupyter notebook\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.media_width:1\nmsgid \"Media width in Jupyter notebook\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.movie_file_extension:1\nmsgid \"Either .mp4, .webm or .mov.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.notify_outdated_version:1\nmsgid \"Whether to notify if there is a version update available.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.output_file:1\nmsgid \"Output file name (-o).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Directory to place partial movie files (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.pixel_height:1\nmsgid \"Frame height in pixels (--resolution, -r).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.pixel_width:1\nmsgid \"Frame width in pixels (--resolution, -r).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.plugins:1\nmsgid \"List of plugins to enable.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.preview:1\nmsgid \"Whether to play the rendered movie (-p).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.progress_bar:1\nmsgid \"Whether to show progress bars while rendering animations.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.quality:1\nmsgid \"Video quality (-q).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.renderer:1\nmsgid \"\\\"cairo\\\", \\\"opengl\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.right_side:1\nmsgid \"Coordinate at the middle right of the frame.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.save_as_gif:1\nmsgid \"Whether to save the rendered scene in .gif format (-i).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.save_last_frame:1\nmsgid \"Whether to save the last frame of the scene as an image file (-s).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.save_pngs:1\nmsgid \"Whether to save all frames in the scene as images files (-g).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.save_sections:1\nmsgid \"Whether to save single videos for each section in addition to the movie file.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.scene_names:1\nmsgid \"Scenes to play from file.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Directory to place section videos (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.show_in_file_browser:1\nmsgid \"Whether to show the output file in the file browser (-f).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Directory to place tex (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Template used when rendering Tex.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"File to read Tex template from (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Directory to place text (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.top:1\nmsgid \"Coordinate at the center top of the frame.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.transparent:1\nmsgid \"Whether the background opacity is 0.0 (-t).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Stop rendering animations at this nmber.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.use_opengl_renderer:1\nmsgid \"Whether or not to use the OpenGL renderer.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.use_projection_fill_shaders:1\nmsgid \"Use shaders for OpenGLVMobject fill which are compatible with transformation matrices.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.use_projection_stroke_shaders:1\nmsgid \"Use shaders for OpenGLVMobject stroke which are compatible with transformation matrices.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.verbosity:1\nmsgid \"Logger verbosity; \\\"DEBUG\\\", \\\"INFO\\\", \\\"WARNING\\\", \\\"ERROR\\\", or \\\"CRITICAL\\\" (-v).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Directory to place videos (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.window_monitor:1\nmsgid \"The monitor on which the scene will be rendered\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"Set the position of preview window.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"The size of the opengl window.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.write_all:1\nmsgid \"Whether to render all scenes in the input file (-a).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.write_to_movie:1\nmsgid \"Whether to render the scene to a movie file (-w).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.aspect_ratio:1:<autosummary>:1\nmsgid \"PNG zero padding.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:3\nmsgid \"A copy of this object containing no shared references.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.copy:10\nmsgid \"This is the main mechanism behind :func:`tempconfig`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:3\nmsgid \"An object returned by :func:`.main_utils.parse_args()`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:6\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:12\nmsgid \"**self** -- This object, after processing the contents of ``parser``.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_args:16\nmsgid \"If ``args.config_file`` is a non-empty string, ``ManimConfig`` tries to digest the contents of said file with :meth:`~ManimConfig.digest_file` before digesting any other CLI arguments.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:3\nmsgid \"This method processes a single ``.cfg`` file, whereas :meth:`~ManimConfig.digest_parser` can process arbitrary parsers, built perhaps from multiple ``.cfg`` files.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:7\nmsgid \"Path to the ``.cfg`` file.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:10\nmsgid \"**self** -- This object, after processing the contents of ``filename``.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_file:17\nmsgid \"If there are multiple ``.cfg`` files to process, it is always more efficient to parse them into a single :class:`ConfigParser` object first and digesting them with one call to :meth:`~ManimConfig.digest_parser`, instead of calling this method multiple times.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:3\nmsgid \"This method processes arbitrary parsers, not only those read from a single file, whereas :meth:`~ManimConfig.digest_file` can only process one file at a time.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:7\nmsgid \"An object reflecting the contents of one or many ``.cfg`` files.  In particular, it may reflect the contents of multiple files that have been parsed in a cascading fashion.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:19\nmsgid \"If there are multiple ``.cfg`` files to process, it is always more efficient to parse them into a single :class:`ConfigParser` object first, and then call this function once (instead of calling :meth:`~.ManimConfig.digest_file` multiple times).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:26\nmsgid \"To digest the config options set in two files, first create a ConfigParser and parse both files and then digest the parser:\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.digest_parser:35\nmsgid \"In fact, the global ``config`` object is initialized like so:\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:3\nmsgid \"Config options that store directories may depend on one another.  This method is used to provide the actual directory to the end user.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:6\nmsgid \"The config option to be resolved.  Must be an option ending in ``'_dir'``, for example ``'media_dir'`` or ``'video_dir'``.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:9\nmsgid \"Any strings to be used when resolving the directory.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:12\nmsgid \"Path to the requested directory.  If the path resolves to the empty string, return ``None`` instead.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:16\nmsgid \"When ``key`` is not a config option that stores a directory and     thus :meth:`~ManimConfig.get_dir` is not appropriate; or when     ``key`` is appropriate but there is not enough information to     resolve the directory.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:20\nmsgid \"Standard :meth:`str.format` syntax is used to resolve the paths so the paths may contain arbitrary placeholders using f-string notation. However, these will require ``kwargs`` to contain the required values.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:26\nmsgid \"The value of ``config.tex_dir`` is ``'{media_dir}/Tex'`` by default, i.e. it is a subfolder of wherever ``config.media_dir`` is located.  In order to get the *actual* directory, use :meth:`~ManimConfig.get_dir`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:41\nmsgid \"Resolving directories is done in a lazy way, at the last possible moment, to reflect any changes in other config options:\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:50\nmsgid \"Some directories depend on information that is not available to :class:`ManimConfig`. For example, the default value of `video_dir` includes the name of the input file and the video quality (e.g. 480p15). This informamtion has to be supplied via ``kwargs``:\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:65\nmsgid \"Note the quality does not need to be passed as keyword argument since :class:`ManimConfig` does store information about quality.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:68\nmsgid \"Directories may be recursively defined.  For example, the config option ``partial_movie_dir`` depends on ``video_dir``, which in turn depends on ``media_dir``:\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.get_dir:84\nmsgid \"Standard f-string syntax is used.  Arbitrary names can be used when defining directories, as long as the corresponding values are passed to :meth:`ManimConfig.get_dir` via ``kwargs``.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.images_dir:1\nmsgid \"Directory to place images (no flag).  See :meth:`ManimConfig.get_dir`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.log_dir:1\nmsgid \"Directory to place logs.  See :meth:`ManimConfig.get_dir`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.max_files_cached:1\nmsgid \"Maximum number of files cached.  Use -1 for infinity (no flag).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.media_dir:1\nmsgid \"Main output directory.  See :meth:`ManimConfig.get_dir`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.partial_movie_dir:1\nmsgid \"Directory to place partial movie files (no flag).  See :meth:`ManimConfig.get_dir`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.renderer:0\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.renderer:3\nmsgid \"Renderer\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.sections_dir:1\nmsgid \"Directory to place section videos (no flag).  See :meth:`ManimConfig.get_dir`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.tex_dir:1\nmsgid \"Directory to place tex (no flag).  See :meth:`ManimConfig.get_dir`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.tex_template:1\nmsgid \"Template used when rendering Tex.  See :class:`.TexTemplate`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.tex_template_file:1\nmsgid \"File to read Tex template from (no flag).  See :class:`.TexTemplateFromFile`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.text_dir:1\nmsgid \"Directory to place text (no flag).  See :meth:`ManimConfig.get_dir`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:3\nmsgid \"Similar to :meth:`dict.update`, replaces the values of this object with those of ``obj``.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:6\nmsgid \"The object to copy values from.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.update:11\nmsgid \"If ``obj`` is a dict but contains keys that do not belong to any     config options.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.upto_animation_number:1\nmsgid \"Stop rendering animations at this nmber.  Use -1 to avoid skipping (-n).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.video_dir:1\nmsgid \"Directory to place videos (no flag).  See :meth:`ManimConfig.get_dir`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.window_position:1\nmsgid \"Set the position of preview window. You can use directions, e.g. UL/DR/ORIGIN/LEFT...or the position(pixel) of the upper left corner of the window, e.g. '960,540'\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimConfig.window_size:1\nmsgid \"The size of the opengl window. 'default' to automatically scale the window based on the display monitor.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim._config.utils.ManimFrame.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim._config.utils.ManimFrame.rst:2\nmsgid \"ManimFrame\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimFrame.rst:4\nmsgid \"Qualified name: ``manim.\\\\_config.utils.ManimFrame``\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimFrame:1\nmsgid \"Bases: :py:class:`collections.abc.Mapping`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimFrame.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.ManimFrame.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.ManimFrame:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim._config.utils.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim._config.utils.rst:2\nmsgid \"utils\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils:1\nmsgid \"Utilities to create and set the config.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils:3\nmsgid \"The main class exported by this module is :class:`ManimConfig`.  This class contains all configuration options, including frame geometry (e.g. frame height/width, frame rate), output (e.g. directories, logging), styling (e.g. background color, transparency), and general behavior (e.g. writing a movie vs writing a single frame).\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils:9\nmsgid \"See :doc:`/guides/configuration` for an introduction to Manim's configuration system.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.rst:28:<autosummary>:1\nmsgid \"Dict-like class storing all config options.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim._config.utils.rst:31\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:1\nmsgid \"The paths where ``.cfg`` files will be searched for.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:3\nmsgid \"When manim is first imported, it processes any ``.cfg`` files it finds.  This function returns the locations in which these files are searched for.  In ascending order of precedence, these are: the library-wide config file, the user-wide config file, and the folder-wide config file.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:8\nmsgid \"The library-wide config file determines manim's default behavior.  The user-wide config file is stored in the user's home folder, and determines the behavior of manim whenever the user invokes it from anywhere in the system.  The folder-wide config file only affects scenes that are in the same folder.  The latter two files are optional.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:14\nmsgid \"These files, if they exist, are meant to loaded into a single :class:`configparser.ConfigParser` object, and then processed by :class:`ManimConfig`.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:18\nmsgid \"List of paths which may contain ``.cfg`` files, in ascending order of precedence.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:0\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:20\nmsgid \"List[:class:`Path`]\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:25\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.config_file_paths:26\nmsgid \"The location of the user-wide config file is OS-specific.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:1\nmsgid \"Make a :class:`ConfigParser` object and load any ``.cfg`` files.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:3\nmsgid \"The user-wide file, if it exists, overrides the library-wide file.  The folder-wide file, if it exists, overrides the other two.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:6\nmsgid \"The folder-wide file can be ignored by passing ``custom_file``.  However, the user-wide and library-wide config files cannot be ignored.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:9\nmsgid \"Path to a custom config file.  If used, the folder-wide file in the relevant directory will be ignored, if it exists.  If None, the folder-wide file will be used, if it exists.\"\nmsgstr \"\"\n\n#: ../../../manim/_config/utils.py:docstring of manim._config.utils.make_config_parser:14\nmsgid \"A parser containing the config options found in the .cfg files that were found.  It is guaranteed to contain at least the config options found in the library-wide file.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.animation.Animation.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.animation.Animation.rst:2\nmsgid \"Animation\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.animation.Animation.rst:4\nmsgid \"Qualified name: ``manim.animation.animation.Animation``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:1\nmsgid \"An animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:3\nmsgid \"Animations have a fixed time span.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.clean_up_from_scene:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate_mobject:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.update_mobjects:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:5\nmsgid \"The mobject to be animated. This is not required for all types of animations.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:6\nmsgid \"Defines the delay after which the animation is applied to submobjects. This lag is relative to the duration of the animation.  This does not influence the total runtime of the animation. Instead the runtime of individual animations is adjusted so that the complete animation has the defined run time.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:6\nmsgid \"Defines the delay after which the animation is applied to submobjects. This lag is relative to the duration of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:9\nmsgid \"This does not influence the total runtime of the animation. Instead the runtime of individual animations is adjusted so that the complete animation has the defined run time.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:12\nmsgid \"The duration of the animation in seconds.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:13\nmsgid \"The function defining the animation progress based on the relative runtime (see  :mod:`~.rate_functions`) .  For example ``rate_func(0.5)`` is the proportion of the animation that is done after half of the animations run time.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:13\nmsgid \"The function defining the animation progress based on the relative runtime (see  :mod:`~.rate_functions`) .\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:15\nmsgid \"For example ``rate_func(0.5)`` is the proportion of the animation that is done after half of the animations run time.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:21\nmsgid \"reverse_rate_function\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:19\nmsgid \"Reverses the rate function of the animation. Setting ``reverse_rate_function`` does not have any effect on ``remover`` or ``introducer``. These need to be set explicitly if an introducer-animation should be turned into a remover one and vice versa.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:24\nmsgid \"name\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:24\nmsgid \"The name of the animation. This gets displayed while rendering the animation. Defaults to <class-name>(<Mobject-name>).\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:26\nmsgid \"remover\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:27\nmsgid \"Whether the given mobject should be removed from the scene after this animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:30\nmsgid \"suspend_mobject_updating\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:29\nmsgid \"Whether updaters of the mobject should be suspended during the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:34\nmsgid \"In the current implementation of this class, the specified rate function is applied within :meth:`.Animation.interpolate_mobject` call as part of the call to :meth:`.Animation.interpolate_submobject`. For subclasses of :class:`.Animation` that are implemented by overriding :meth:`interpolate_mobject`, the rate function has to be applied manually (e.g., by passing ``self.rate_func(alpha)`` instead of just ``alpha``).\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation:43\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.animation.Animation.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1\nmsgid \"Begin the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.clean_up_from_scene:1\nmsgid \"Clean up the :class:`~.Scene` after finishing the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.copy:1\nmsgid \"Create a copy of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.finish:1\nmsgid \"Finish the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects:1\nmsgid \"Get all mobjects involved in the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects_to_update:1\nmsgid \"Get all mobjects to be updated during the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_rate_func:1\nmsgid \"Get the rate function of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_run_time:1\nmsgid \"Get the run time of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:1\nmsgid \"Get the animation progress of any submobjects subanimation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate:1\nmsgid \"Set the animation progress.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate_mobject:1\nmsgid \"Interpolates the mobject of the :class:`Animation` based on alpha value.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_introducer:1\nmsgid \"Test if the animation is an introducer.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_remover:1\nmsgid \"Test if the animation is a remover.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:1\nmsgid \"Set the name of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:1\nmsgid \"Set the rate function of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:1\nmsgid \"Set the run time of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:1:<autosummary>:1\nmsgid \"Updates things like starting_mobject, and (for Transforms) target_mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:3\nmsgid \"This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.begin:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.clean_up_from_scene:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.copy:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.finish:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects_to_update:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_rate_func:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_run_time:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate_mobject:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_introducer:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_remover:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.update_mobjects:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.clean_up_from_scene:3\nmsgid \"This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.clean_up_from_scene:6\nmsgid \"The scene the animation should be cleaned up from.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.copy:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects_to_update:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_rate_func:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_run_time:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_introducer:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_remover:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.copy:3\nmsgid \"A copy of ``self``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.finish:3\nmsgid \"This method gets called when the animation is over.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects:3\nmsgid \"Ordering must match the ordering of arguments to interpolate_submobject\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects:5\nmsgid \"The sequence of mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_all_mobjects_to_update:3\nmsgid \"The list of mobjects to be updated during the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_rate_func:3\nmsgid \"The rate function of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_run_time:3\nmsgid \"The time the animation takes in seconds.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:3\nmsgid \"The overall animation progress\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:4\nmsgid \"The index of the subanimation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:5\nmsgid \"The total count of subanimations.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.get_sub_alpha:7\nmsgid \"The progress of the subanimation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate:3\nmsgid \"This method gets called for every frame during an animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate:5\nmsgid \"The relative time to set the animation to, 0 meaning the start, 1 meaning the end.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.interpolate_mobject:3\nmsgid \"A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_introducer:3\nmsgid \"``True`` if the animation is an introducer, ``False`` otherwise.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.is_remover:3\nmsgid \"``True`` if the animation is a remover, ``False`` otherwise.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:3\nmsgid \"The new name of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_name:5\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:5\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:7\nmsgid \"``self``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_rate_func:3\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:3\nmsgid \"The new time the animation should take in seconds.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Animation.set_run_time:4\nmsgid \"The run_time of an animation should not be changed while it is already running.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.animation.Wait.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.animation.Wait.rst:2\nmsgid \"Wait\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.animation.Wait.rst:4\nmsgid \"Qualified name: ``manim.animation.animation.Wait``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:1\nmsgid \"A \\\"no operation\\\" animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.clean_up_from_scene:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.interpolate:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.update_mobjects:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:3\nmsgid \"The amount of time that should pass.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:4\nmsgid \"A function without positional arguments that evaluates to a boolean. The function is evaluated after every new frame has been rendered. Playing the animation only stops after the return value is truthy. Overrides the specified ``run_time``.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:8\nmsgid \"Controls whether or not the wait animation is static, i.e., corresponds to a frozen frame. If ``False`` is passed, the render loop still progresses through the animation as usual and (among other things) continues to call updater functions. If ``None`` (the default value), the :meth:`.Scene.play` call tries to determine whether the Wait call can be static or not itself via :meth:`.Scene.should_mobjects_update`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait:14\nmsgid \"Keyword arguments to be passed to the parent class, :class:`.Animation`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.animation.Wait.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1\nmsgid \"Begin the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.clean_up_from_scene:1\nmsgid \"Clean up the :class:`~.Scene` after finishing the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.finish:1\nmsgid \"Finish the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1:<autosummary>:1\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.interpolate:1\nmsgid \"Set the animation progress.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:1:<autosummary>:1\nmsgid \"Updates things like starting_mobject, and (for Transforms) target_mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:3\nmsgid \"This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.begin:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.clean_up_from_scene:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.finish:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.interpolate:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.update_mobjects:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.clean_up_from_scene:3\nmsgid \"This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.clean_up_from_scene:6\nmsgid \"The scene the animation should be cleaned up from.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.finish:3\nmsgid \"This method gets called when the animation is over.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.interpolate:3\nmsgid \"This method gets called for every frame during an animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.Wait.interpolate:5\nmsgid \"The relative time to set the animation to, 0 meaning the start, 1 meaning the end.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.animation.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.animation.rst:2\nmsgid \"animation\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation:1\nmsgid \"Animate mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.animation.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.animation.rst:28:<autosummary>:1\nmsgid \"An animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.animation.rst:28:<autosummary>:1\nmsgid \"A \\\"no operation\\\" animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.animation.rst:31\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:1\nmsgid \"Decorator used to mark methods as overrides for specific :class:`~.Animation` types.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:3\nmsgid \"Should only be used to decorate methods of classes derived from :class:`~.Mobject`. ``Animation`` overrides get inherited to subclasses of the ``Mobject`` who defined them. They don't override subclasses of the ``Animation`` they override.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.prepare_animation:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:9\nmsgid \"The animation to be overridden.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:11\nmsgid \"The actual decorator. This marks the method as overriding an animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:0\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.prepare_animation:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.override_animation:15\n#: ../../../manim/animation/animation.py:docstring of manim.animation.animation.prepare_animation:5\nmsgid \"Examples\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.changing.AnimatedBoundary.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:2\nmsgid \"AnimatedBoundary\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:4\nmsgid \"Qualified name: ``manim.animation.changing.AnimatedBoundary``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.AnimatedBoundary:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.AnimatedBoundary:1\nmsgid \"Boundary of a :class:`.VMobject` with animated color change.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.AnimatedBoundary:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:34:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:34:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:34:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.AnimatedBoundary.rst:34:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.changing.TracedPath.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.changing.TracedPath.rst:2\nmsgid \"TracedPath\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.TracedPath.rst:4\nmsgid \"Qualified name: ``manim.animation.changing.TracedPath``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:1\nmsgid \"Traces the path of a point returned by a function call.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:3\nmsgid \"The function to be traced.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:4\nmsgid \"The width of the trace.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:5\nmsgid \"The color of the trace.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:6\nmsgid \"The time taken for the path to dissipate. Default set to ``None`` which disables dissipation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing.TracedPath:10\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.TracedPath.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.TracedPath.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.TracedPath.rst:33:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.TracedPath.rst:33:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.TracedPath.rst:33:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.TracedPath.rst:33:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.changing.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.changing.rst:2\nmsgid \"changing\"\nmsgstr \"\"\n\n#: ../../../manim/animation/changing.py:docstring of manim.animation.changing:1\nmsgid \"Animation of a mobject boundary and tracing of points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.changing.rst:22:<autosummary>:1\nmsgid \"Boundary of a :class:`.VMobject` with animated color change.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.composition.AnimationGroup.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.composition.AnimationGroup.rst:2\nmsgid \"AnimationGroup\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.composition.AnimationGroup.rst:4\nmsgid \"Qualified name: ``manim.animation.composition.AnimationGroup``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.composition.AnimationGroup.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1:<autosummary>:1\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1\nmsgid \"Begin the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1:<autosummary>:1\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.build_animations_with_timings:1\nmsgid \"Creates a list of triplets of the form (anim, start_time, end_time)\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1:<autosummary>:1\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.clean_up_from_scene:1\nmsgid \"Clean up the :class:`~.Scene` after finishing the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1:<autosummary>:1\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.finish:1\nmsgid \"Finish the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1:<autosummary>:1\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.get_all_mobjects:1\nmsgid \"Get all mobjects involved in the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1:<autosummary>:1\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.interpolate:1\nmsgid \"Set the animation progress.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:1:<autosummary>:1\nmsgid \"Updates things like starting_mobject, and (for Transforms) target_mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:3\nmsgid \"This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.begin:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.build_animations_with_timings:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.clean_up_from_scene:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.finish:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.get_all_mobjects:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.interpolate:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.update_mobjects:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.clean_up_from_scene:3\nmsgid \"This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.clean_up_from_scene:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.interpolate:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.update_mobjects:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.clean_up_from_scene:6\nmsgid \"The scene the animation should be cleaned up from.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.finish:3\nmsgid \"This method gets called when the animation is over.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.get_all_mobjects:3\nmsgid \"Ordering must match the ordering of arguments to interpolate_submobject\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.get_all_mobjects:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.get_all_mobjects:5\nmsgid \"The sequence of mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.interpolate:3\nmsgid \"This method gets called for every frame during an animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.AnimationGroup.interpolate:5\nmsgid \"The relative time to set the animation to, 0 meaning the start, 1 meaning the end.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.composition.LaggedStart.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.composition.LaggedStart.rst:2\nmsgid \"LaggedStart\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.composition.LaggedStart.rst:4\nmsgid \"Qualified name: ``manim.animation.composition.LaggedStart``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.LaggedStart:1\nmsgid \"Bases: :py:class:`manim.animation.composition.AnimationGroup`\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.composition.LaggedStartMap.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.composition.LaggedStartMap.rst:2\nmsgid \"LaggedStartMap\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.composition.LaggedStartMap.rst:4\nmsgid \"Qualified name: ``manim.animation.composition.LaggedStartMap``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.LaggedStartMap:1\nmsgid \"Bases: :py:class:`manim.animation.composition.LaggedStart`\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.composition.Succession.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.composition.Succession.rst:2\nmsgid \"Succession\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.composition.Succession.rst:4\nmsgid \"Qualified name: ``manim.animation.composition.Succession``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession:1\nmsgid \"Bases: :py:class:`manim.animation.composition.AnimationGroup`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.composition.Succession.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:1:<autosummary>:1\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:1\nmsgid \"Begin the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:1:<autosummary>:1\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.finish:1\nmsgid \"Finish the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:1:<autosummary>:1\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.interpolate:1\nmsgid \"Set the animation progress.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:1:<autosummary>:1\nmsgid \"Updates things like starting_mobject, and (for Transforms) target_mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:3\nmsgid \"This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.begin:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.finish:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.interpolate:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.update_mobjects:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.finish:3\nmsgid \"This method gets called when the animation is over.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.interpolate:3\nmsgid \"This method gets called for every frame during an animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.interpolate:0\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.update_mobjects:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition.Succession.interpolate:5\nmsgid \"The relative time to set the animation to, 0 meaning the start, 1 meaning the end.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.composition.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.composition.rst:2\nmsgid \"composition\"\nmsgstr \"\"\n\n#: ../../../manim/animation/composition.py:docstring of manim.animation.composition:1\nmsgid \"Tools for displaying multiple animations at once.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.composition.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.AddTextLetterByLetter.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.AddTextLetterByLetter.rst:2\nmsgid \"AddTextLetterByLetter\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.AddTextLetterByLetter.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.AddTextLetterByLetter``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextLetterByLetter:1\nmsgid \"Bases: :py:class:`manim.animation.creation.ShowIncreasingSubsets`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextLetterByLetter:1\nmsgid \"Show a :class:`~.Text` letter by letter on the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextLetterByLetter:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextLetterByLetter:3\nmsgid \"Frequency of appearance of the letters.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextLetterByLetter:5\nmsgid \"This is currently only possible for class:`~.Text` and not for class:`~.MathTex`\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.AddTextWordByWord.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.AddTextWordByWord.rst:2\nmsgid \"AddTextWordByWord\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.AddTextWordByWord.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.AddTextWordByWord``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextWordByWord:1\nmsgid \"Bases: :py:class:`manim.animation.composition.Succession`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.AddTextWordByWord:1\nmsgid \"Show a :class:`~.Text` word by word on the scene. Note: currently broken.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.Create.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.Create.rst:2\nmsgid \"Create\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.Create.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.Create``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:1\nmsgid \"Bases: :py:class:`manim.animation.creation.ShowPartial`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:1\nmsgid \"Incrementally show a VMobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:3\nmsgid \"The VMobject to animate.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:6\nmsgid \"If ``mobject`` is not an instance of :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Create:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.DrawBorderThenFill.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.DrawBorderThenFill.rst:2\nmsgid \"DrawBorderThenFill\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.DrawBorderThenFill.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.DrawBorderThenFill``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill:1\nmsgid \"Draw the border first and then show the fill.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.DrawBorderThenFill.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.begin:1:<autosummary>:1\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.begin:1\nmsgid \"Begin the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.begin:1:<autosummary>:1\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.get_all_mobjects:1\nmsgid \"Get all mobjects involved in the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.begin:3\nmsgid \"This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.begin:0\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.get_all_mobjects:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.get_all_mobjects:3\nmsgid \"Ordering must match the ordering of arguments to interpolate_submobject\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.DrawBorderThenFill.get_all_mobjects:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.ShowIncreasingSubsets.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.ShowIncreasingSubsets.rst:2\nmsgid \"ShowIncreasingSubsets\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.ShowIncreasingSubsets.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.ShowIncreasingSubsets``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets:1\nmsgid \"Show one submobject at a time, leaving all previous ones displayed on screen.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.ShowIncreasingSubsets.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets.interpolate_mobject:1:<autosummary>:1\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets.interpolate_mobject:1\nmsgid \"Interpolates the mobject of the :class:`Animation` based on alpha value.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets.interpolate_mobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowIncreasingSubsets.interpolate_mobject:3\nmsgid \"A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.ShowPartial.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.ShowPartial.rst:2\nmsgid \"ShowPartial\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.ShowPartial.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.ShowPartial``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowPartial:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowPartial:1\nmsgid \"Abstract class for Animations that show the VMobject partially.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowPartial:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowPartial:3\nmsgid \"If ``mobject`` is not an instance of :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.ShowPartial.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.ShowSubmobjectsOneByOne.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.ShowSubmobjectsOneByOne.rst:2\nmsgid \"ShowSubmobjectsOneByOne\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.ShowSubmobjectsOneByOne.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.ShowSubmobjectsOneByOne``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowSubmobjectsOneByOne:1\nmsgid \"Bases: :py:class:`manim.animation.creation.ShowIncreasingSubsets`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.ShowSubmobjectsOneByOne:1\nmsgid \"Show one submobject at a time, removing all previously displayed ones from screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.ShowSubmobjectsOneByOne.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.SpiralIn.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.SpiralIn.rst:2\nmsgid \"SpiralIn\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.SpiralIn.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.SpiralIn``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:1\nmsgid \"Create the Mobject with sub-Mobjects flying in on spiral trajectories.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:0\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn.interpolate_mobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:3\nmsgid \"The Mobject on which to be operated.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:4\nmsgid \"The factor used for scaling the effect.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:5\nmsgid \"Fractional duration of initial fade-in of sub-Mobjects as they fly inward.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn:8\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.SpiralIn.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn.interpolate_mobject:1:<autosummary>:1\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn.interpolate_mobject:1\nmsgid \"Interpolates the mobject of the :class:`Animation` based on alpha value.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.SpiralIn.interpolate_mobject:3\nmsgid \"A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.Uncreate.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.Uncreate.rst:2\nmsgid \"Uncreate\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.Uncreate.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.Uncreate``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Uncreate:1\nmsgid \"Bases: :py:class:`manim.animation.creation.Create`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Uncreate:1\nmsgid \"Like :class:`Create` but in reverse.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Uncreate:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.Unwrite.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.Unwrite.rst:2\nmsgid \"Unwrite\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.Unwrite.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.Unwrite``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Unwrite:1\nmsgid \"Bases: :py:class:`manim.animation.creation.Write`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Unwrite:1\nmsgid \"Simulate erasing by hand a :class:`~.Text` or a :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Unwrite:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Unwrite:3\nmsgid \"Set True to have the animation start erasing from the last submobject first.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Unwrite:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.Write.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.Write.rst:2\nmsgid \"Write\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.Write.rst:4\nmsgid \"Qualified name: ``manim.animation.creation.Write``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write:1\nmsgid \"Bases: :py:class:`manim.animation.creation.DrawBorderThenFill`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write:1\nmsgid \"Simulate hand-writing a :class:`~.Text` or hand-drawing a :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.Write.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.begin:1:<autosummary>:1\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.begin:1\nmsgid \"Begin the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.begin:1:<autosummary>:1\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.finish:1\nmsgid \"Finish the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.begin:3\nmsgid \"This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.begin:0\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation.Write.finish:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.creation.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.creation.rst:2\nmsgid \"creation\"\nmsgstr \"\"\n\n#: ../../../manim/animation/creation.py:docstring of manim.animation.creation:1\nmsgid \"Animate the display or removal of a mobject from a scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:40:<autosummary>:1\nmsgid \"Show a :class:`~.Text` letter by letter on the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:40:<autosummary>:1\nmsgid \"Show a :class:`~.Text` word by word on the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:40:<autosummary>:1\nmsgid \"Incrementally show a VMobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:40:<autosummary>:1\nmsgid \"Draw the border first and then show the fill.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:40:<autosummary>:1\nmsgid \"Show one submobject at a time, leaving all previous ones displayed on screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:40:<autosummary>:1\nmsgid \"Abstract class for Animations that show the VMobject partially.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:40:<autosummary>:1\nmsgid \"Show one submobject at a time, removing all previously displayed ones from screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:40:<autosummary>:1\nmsgid \"Create the Mobject with sub-Mobjects flying in on spiral trajectories.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:40:<autosummary>:1\nmsgid \"Like :class:`Create` but in reverse.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.creation.rst:40:<autosummary>:1\nmsgid \"Simulate erasing by hand a :class:`~.Text` or a :class:`~.VMobject`.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.fading.FadeIn.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.fading.FadeIn.rst:2\nmsgid \"FadeIn\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.fading.FadeIn.rst:4\nmsgid \"Qualified name: ``manim.animation.fading.FadeIn``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:1\nmsgid \"Bases: :py:class:`manim.animation.fading._Fade`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:1\nmsgid \"Fade in :class:`~.Mobject` s.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:3\nmsgid \"The mobjects to be faded in.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:4\nmsgid \"The vector by which the mobject shifts while being faded in.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:5\nmsgid \"The position from which the mobject starts while being faded in. In case another mobject is given as target position, its center is used.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:7\nmsgid \"The factor by which the mobject is scaled initially before being rescaling to its original size while being faded in.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeIn:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.fading.FadeIn.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.fading.FadeIn.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.fading.FadeOut.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.fading.FadeOut.rst:2\nmsgid \"FadeOut\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.fading.FadeOut.rst:4\nmsgid \"Qualified name: ``manim.animation.fading.FadeOut``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:1\nmsgid \"Bases: :py:class:`manim.animation.fading._Fade`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:1\nmsgid \"Fade out :class:`~.Mobject` s.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:0\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut.clean_up_from_scene:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:3\nmsgid \"The mobjects to be faded out.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:4\nmsgid \"The vector by which the mobject shifts while being faded out.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:5\nmsgid \"The position to which the mobject moves while being faded out. In case another mobject is given as target position, its center is used.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:7\nmsgid \"The factor by which the mobject is scaled while being faded out.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut:10\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.fading.FadeOut.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.fading.FadeOut.rst:21:<autosummary>:1\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut.clean_up_from_scene:1\nmsgid \"Clean up the :class:`~.Scene` after finishing the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.fading.FadeOut.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut.clean_up_from_scene:3\nmsgid \"This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading.FadeOut.clean_up_from_scene:6\nmsgid \"The scene the animation should be cleaned up from.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.fading.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.fading.rst:2\nmsgid \"fading\"\nmsgstr \"\"\n\n#: ../../../manim/animation/fading.py:docstring of manim.animation.fading:1\nmsgid \"Fading in and out of view.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.fading.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.fading.rst:22:<autosummary>:1\nmsgid \"Fade in :class:`~.Mobject` s.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.growing.GrowArrow.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.growing.GrowArrow.rst:2\nmsgid \"GrowArrow\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowArrow.rst:4\nmsgid \"Qualified name: ``manim.animation.growing.GrowArrow``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:1\nmsgid \"Bases: :py:class:`manim.animation.growing.GrowFromPoint`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:1\nmsgid \"Introduce an :class:`~.Arrow` by growing it from its start toward its tip.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:3\nmsgid \"The arrow to be introduced.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:4\nmsgid \"Initial color of the arrow before growing to its full size. Leave empty to match arrow's color.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowArrow:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowArrow.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowArrow.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.growing.GrowFromCenter.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromCenter.rst:2\nmsgid \"GrowFromCenter\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromCenter.rst:4\nmsgid \"Qualified name: ``manim.animation.growing.GrowFromCenter``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:1\nmsgid \"Bases: :py:class:`manim.animation.growing.GrowFromPoint`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:1\nmsgid \"Introduce an :class:`~.Mobject` by growing it from its center.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:3\nmsgid \"The mobjects to be introduced.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:4\nmsgid \"Initial color of the mobject before growing to its full size. Leave empty to match mobject's color.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromCenter:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromCenter.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromCenter.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.growing.GrowFromEdge.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromEdge.rst:2\nmsgid \"GrowFromEdge\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromEdge.rst:4\nmsgid \"Qualified name: ``manim.animation.growing.GrowFromEdge``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:1\nmsgid \"Bases: :py:class:`manim.animation.growing.GrowFromPoint`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:1\nmsgid \"Introduce an :class:`~.Mobject` by growing it from one of its bounding box edges.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:3\nmsgid \"The mobjects to be introduced.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:4\nmsgid \"The direction to seek bounding box edge of mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:5\nmsgid \"Initial color of the mobject before growing to its full size. Leave empty to match mobject's color.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromEdge:8\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromEdge.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromEdge.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.growing.GrowFromPoint.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromPoint.rst:2\nmsgid \"GrowFromPoint\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromPoint.rst:4\nmsgid \"Qualified name: ``manim.animation.growing.GrowFromPoint``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:1\nmsgid \"Introduce an :class:`~.Mobject` by growing it from a point.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:3\nmsgid \"The mobjects to be introduced.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:4\nmsgid \"The point from which the mobject grows.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:5\nmsgid \"Initial color of the mobject before growing to its full size. Leave empty to match mobject's color.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.GrowFromPoint:8\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromPoint.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.GrowFromPoint.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.growing.SpinInFromNothing.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.growing.SpinInFromNothing.rst:2\nmsgid \"SpinInFromNothing\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.SpinInFromNothing.rst:4\nmsgid \"Qualified name: ``manim.animation.growing.SpinInFromNothing``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:1\nmsgid \"Bases: :py:class:`manim.animation.growing.GrowFromCenter`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:1\nmsgid \"Introduce an :class:`~.Mobject` spinning and growing it from its center.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:3\nmsgid \"The mobjects to be introduced.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:4\nmsgid \"The amount of spinning before mobject reaches its full size. E.g. 2*PI means that the object will do one full spin before being fully introduced.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:6\nmsgid \"Initial color of the mobject before growing to its full size. Leave empty to match mobject's color.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing.SpinInFromNothing:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.SpinInFromNothing.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.SpinInFromNothing.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.growing.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.growing.rst:2\nmsgid \"growing\"\nmsgstr \"\"\n\n#: ../../../manim/animation/growing.py:docstring of manim.animation.growing:1\nmsgid \"Animations that introduce mobjects to scene by growing them from points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.rst:28:<autosummary>:1\nmsgid \"Introduce an :class:`~.Arrow` by growing it from its start toward its tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.rst:28:<autosummary>:1\nmsgid \"Introduce an :class:`~.Mobject` by growing it from its center.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.rst:28:<autosummary>:1\nmsgid \"Introduce an :class:`~.Mobject` by growing it from one of its bounding box edges.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.growing.rst:28:<autosummary>:1\nmsgid \"Introduce an :class:`~.Mobject` by growing it from a point.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.indication.ApplyWave.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.indication.ApplyWave.rst:2\nmsgid \"ApplyWave\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.ApplyWave.rst:4\nmsgid \"Qualified name: ``manim.animation.indication.ApplyWave``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:1\nmsgid \"Bases: :py:class:`manim.animation.movement.Homotopy`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:1\nmsgid \"Send a wave through the Mobject distorting it temporarily.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:3\nmsgid \"The mobject to be distorted.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:4\nmsgid \"The direction in which the wave nudges points of the shape\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:5\nmsgid \"The distance points of the shape get shifted\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:6\nmsgid \"The function defining the shape of one wave flank.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:7\nmsgid \"The length of the wave relative to the width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:8\nmsgid \"The number of ripples of the wave\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:9\nmsgid \"The duration of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ApplyWave:12\nmsgid \"Examples\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.indication.Circumscribe.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.indication.Circumscribe.rst:2\nmsgid \"Circumscribe\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.Circumscribe.rst:4\nmsgid \"Qualified name: ``manim.animation.indication.Circumscribe``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:1\nmsgid \"Bases: :py:class:`manim.animation.composition.Succession`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:1\nmsgid \"Draw a temporary line surrounding the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:3\nmsgid \"The mobject to be circumscribed.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:4\nmsgid \"The shape with which to surrond the given mobject. Should be either :class:`~.Rectangle` or :class:`~.Circle`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:6\nmsgid \"Whether to make the surrounding shape to fade in. It will be drawn otherwise.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:7\nmsgid \"Whether to make the surrounding shape to fade out. It will be undrawn otherwise.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:8\nmsgid \"The time_width of the drawing and undrawing. Gets ignored if either `fade_in` or `fade_out` is `True`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:9\nmsgid \"The distance between the surrounding shape and the given mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:10\nmsgid \"The color of the surrounding shape.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:11\nmsgid \"The duration of the entire animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:12\nmsgid \"Additional arguments to be passed to the :class:`~.Succession` constructor\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Circumscribe:16\nmsgid \"Examples\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.indication.Flash.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.indication.Flash.rst:2\nmsgid \"Flash\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.Flash.rst:4\nmsgid \"Qualified name: ``manim.animation.indication.Flash``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:1\nmsgid \"Bases: :py:class:`manim.animation.composition.AnimationGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:1\nmsgid \"Send out lines in all directions.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:3\nmsgid \"The center of the flash lines. If it is a :class:`.~Mobject` its center will be used.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:4\nmsgid \"The length of the flash lines.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:5\nmsgid \"The number of flash lines.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:6\nmsgid \"The distance from `point` at which the flash lines start.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:7\nmsgid \"The stroke width of the flash lines.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:8\nmsgid \"The color of the flash lines.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:9\nmsgid \"The time width used for the flash lines. See :class:`.~ShowPassingFlash` for more details.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:10\nmsgid \"The duration of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:11\nmsgid \"Additional arguments to be passed to the :class:`~.Succession` constructor\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Flash:15\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.Flash.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.indication.FocusOn.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.indication.FocusOn.rst:2\nmsgid \"FocusOn\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.FocusOn.rst:4\nmsgid \"Qualified name: ``manim.animation.indication.FocusOn``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:1\nmsgid \"Shrink a spotlight to a position.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:3\nmsgid \"The point at which to shrink the spotlight. If it is a :class:`.~Mobject` its center will be used.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:4\nmsgid \"The opacity of the spotlight.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:5\nmsgid \"The color of the spotlight.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:6\nmsgid \"The duration of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:7\nmsgid \"Additional arguments to be passed to the :class:`~.Succession` constructor\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.FocusOn:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.FocusOn.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.FocusOn.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.indication.Indicate.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.indication.Indicate.rst:2\nmsgid \"Indicate\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.Indicate.rst:4\nmsgid \"Qualified name: ``manim.animation.indication.Indicate``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:1\nmsgid \"Indicate a Mobject by temporarily resizing and recoloring it.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:3\nmsgid \"The mobject to indicate.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:4\nmsgid \"The factor by which the mobject will be temporally scaled\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:5\nmsgid \"The color the mobject temporally takes.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:6\nmsgid \"The function definig the animation progress at every point in time.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:7\nmsgid \"Additional arguments to be passed to the :class:`~.Succession` constructor\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Indicate:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.Indicate.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.Indicate.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.indication.ShowCreationThenFadeOut.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.indication.ShowCreationThenFadeOut.rst:2\nmsgid \"ShowCreationThenFadeOut\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.ShowCreationThenFadeOut.rst:4\nmsgid \"Qualified name: ``manim.animation.indication.ShowCreationThenFadeOut``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowCreationThenFadeOut:1\nmsgid \"Bases: :py:class:`manim.animation.composition.Succession`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowCreationThenFadeOut:1\nmsgid \"Deprecated The class ShowCreationThenFadeOut has been deprecated since v0.15.0 and is expected to be removed after v0.16.0. Use Create then FadeOut to achieve this effect.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.indication.ShowPassingFlash.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.indication.ShowPassingFlash.rst:2\nmsgid \"ShowPassingFlash\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.ShowPassingFlash.rst:4\nmsgid \"Qualified name: ``manim.animation.indication.ShowPassingFlash``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:1\nmsgid \"Bases: :py:class:`manim.animation.creation.ShowPartial`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:1\nmsgid \"Show only a sliver of the VMobject each frame.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:0\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash.clean_up_from_scene:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:3\nmsgid \"The mobject whose stroke is animated.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:4\nmsgid \"The length of the sliver relative to the length of the stroke.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.ShowPassingFlash.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash.clean_up_from_scene:1:<autosummary>:1\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash.clean_up_from_scene:1\nmsgid \"Clean up the :class:`~.Scene` after finishing the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash.clean_up_from_scene:3\nmsgid \"This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlash.clean_up_from_scene:6\nmsgid \"The scene the animation should be cleaned up from.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth.rst:2\nmsgid \"ShowPassingFlashWithThinningStrokeWidth\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth.rst:4\nmsgid \"Qualified name: ``manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.ShowPassingFlashWithThinningStrokeWidth:1\nmsgid \"Bases: :py:class:`manim.animation.composition.AnimationGroup`\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.indication.Wiggle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.indication.Wiggle.rst:2\nmsgid \"Wiggle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.Wiggle.rst:4\nmsgid \"Qualified name: ``manim.animation.indication.Wiggle``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:1\nmsgid \"Wiggle a Mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:3\nmsgid \"The mobject to wiggle.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:5\nmsgid \"The factor by which the mobject will be temporarily scaled.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:6\nmsgid \"The wiggle angle.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:7\nmsgid \"The number of wiggles.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:8\nmsgid \"The point about which the mobject gets scaled.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:9\nmsgid \"The point around which the mobject gets rotated.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:10\nmsgid \"The duration of the animation\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication.Wiggle:13\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.Wiggle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.indication.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.indication.rst:2\nmsgid \"indication\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication:1\nmsgid \"Animations drawing attention to particular mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/indication.py:docstring of manim.animation.indication:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.rst:36:<autosummary>:1\nmsgid \"Send a wave through the Mobject distorting it temporarily.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.rst:36:<autosummary>:1\nmsgid \"Draw a temporary line surrounding the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.rst:36:<autosummary>:1\nmsgid \"Send out lines in all directions.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.rst:36:<autosummary>:1\nmsgid \"Shrink a spotlight to a position.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.rst:36:<autosummary>:1\nmsgid \"Indicate a Mobject by temporarily resizing and recoloring it.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.rst:36:<autosummary>:1\nmsgid \"Deprecated\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.indication.rst:36:<autosummary>:1\nmsgid \"Show only a sliver of the VMobject each frame.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.movement.ComplexHomotopy.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.movement.ComplexHomotopy.rst:2\nmsgid \"ComplexHomotopy\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.ComplexHomotopy.rst:4\nmsgid \"Qualified name: ``manim.animation.movement.ComplexHomotopy``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.ComplexHomotopy:1\nmsgid \"Bases: :py:class:`manim.animation.movement.Homotopy`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.ComplexHomotopy:1\nmsgid \"Complex Homotopy a function Cx[0, 1] to C\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.movement.Homotopy.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.movement.Homotopy.rst:2\nmsgid \"Homotopy\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.Homotopy.rst:4\nmsgid \"Qualified name: ``manim.animation.movement.Homotopy``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:1\nmsgid \"A Homotopy.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:3\nmsgid \"This is an animation transforming the points of a mobject according to the specified transformation function. With the parameter :math:`t` moving from 0 to 1 throughout the animation and :math:`(x, y, z)` describing the coordinates of the point of a mobject, the function passed to the ``homotopy`` keyword argument should transform the tuple :math:`(x, y, z, t)` to :math:`(x', y', z')`, the coordinates the original point is transformed to at time :math:`t`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:11\nmsgid \"A function mapping :math:`(x, y, z, t)` to :math:`(x', y', z')`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:12\nmsgid \"The mobject transformed under the given homotopy.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:13\nmsgid \"The run time of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:14\nmsgid \"Keyword arguments propagated to :meth:`.Mobject.apply_function`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.Homotopy:15\nmsgid \"Further keyword arguments passed to the parent class.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.Homotopy.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.movement.MoveAlongPath.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.movement.MoveAlongPath.rst:2\nmsgid \"MoveAlongPath\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.MoveAlongPath.rst:4\nmsgid \"Qualified name: ``manim.animation.movement.MoveAlongPath``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath:1\nmsgid \"Make one mobject move along the path of another mobject. .. rubric:: Example\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.MoveAlongPath.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath.interpolate_mobject:1:<autosummary>:1\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath.interpolate_mobject:1\nmsgid \"Interpolates the mobject of the :class:`Animation` based on alpha value.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath.interpolate_mobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.MoveAlongPath.interpolate_mobject:3\nmsgid \"A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.movement.PhaseFlow.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.movement.PhaseFlow.rst:2\nmsgid \"PhaseFlow\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.PhaseFlow.rst:4\nmsgid \"Qualified name: ``manim.animation.movement.PhaseFlow``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.PhaseFlow:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.PhaseFlow.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.PhaseFlow.interpolate_mobject:1:<autosummary>:1\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.PhaseFlow.interpolate_mobject:1\nmsgid \"Interpolates the mobject of the :class:`Animation` based on alpha value.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.PhaseFlow.interpolate_mobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.PhaseFlow.interpolate_mobject:3\nmsgid \"A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.movement.SmoothedVectorizedHomotopy.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.movement.SmoothedVectorizedHomotopy.rst:2\nmsgid \"SmoothedVectorizedHomotopy\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.SmoothedVectorizedHomotopy.rst:4\nmsgid \"Qualified name: ``manim.animation.movement.SmoothedVectorizedHomotopy``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement.SmoothedVectorizedHomotopy:1\nmsgid \"Bases: :py:class:`manim.animation.movement.Homotopy`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.SmoothedVectorizedHomotopy.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.movement.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.movement.rst:2\nmsgid \"movement\"\nmsgstr \"\"\n\n#: ../../../manim/animation/movement.py:docstring of manim.animation.movement:1\nmsgid \"Animations related to movement.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.rst:28:<autosummary>:1\nmsgid \"Complex Homotopy a function Cx[0, 1] to C\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.rst:28:<autosummary>:1\nmsgid \"A Homotopy.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.movement.rst:28:<autosummary>:1\nmsgid \"Make one mobject move along the path of another mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.numbers.ChangeDecimalToValue.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.numbers.ChangeDecimalToValue.rst:2\nmsgid \"ChangeDecimalToValue\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.numbers.ChangeDecimalToValue.rst:4\nmsgid \"Qualified name: ``manim.animation.numbers.ChangeDecimalToValue``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangeDecimalToValue:1\nmsgid \"Bases: :py:class:`manim.animation.numbers.ChangingDecimal`\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.numbers.ChangingDecimal.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.numbers.ChangingDecimal.rst:2\nmsgid \"ChangingDecimal\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.numbers.ChangingDecimal.rst:4\nmsgid \"Qualified name: ``manim.animation.numbers.ChangingDecimal``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangingDecimal:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.numbers.ChangingDecimal.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangingDecimal.interpolate_mobject:1:<autosummary>:1\n#: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangingDecimal.interpolate_mobject:1\nmsgid \"Interpolates the mobject of the :class:`Animation` based on alpha value.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangingDecimal.interpolate_mobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers.ChangingDecimal.interpolate_mobject:3\nmsgid \"A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.numbers.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.numbers.rst:2\nmsgid \"numbers\"\nmsgstr \"\"\n\n#: ../../../manim/animation/numbers.py:docstring of manim.animation.numbers:1\nmsgid \"Animations for changing numbers.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.numbers.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.rotation.Rotate.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.rotation.Rotate.rst:2\nmsgid \"Rotate\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.rotation.Rotate.rst:4\nmsgid \"Qualified name: ``manim.animation.rotation.Rotate``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:1\nmsgid \"Animation that rotates a Mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:3\nmsgid \"The mobject to be rotated.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:4\nmsgid \"The rotation angle.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:5\nmsgid \"The rotation axis as a numpy vector.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:6\nmsgid \"The rotation center.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:7\nmsgid \"If ``about_point``is ``None``, this argument specifies the direction of the bounding box point to be taken as the rotation center.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotate:12\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.rotation.Rotate.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.rotation.Rotate.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.rotation.Rotating.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.rotation.Rotating.rst:2\nmsgid \"Rotating\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.rotation.Rotating.rst:4\nmsgid \"Qualified name: ``manim.animation.rotation.Rotating``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotating:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.rotation.Rotating.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotating.interpolate_mobject:1:<autosummary>:1\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotating.interpolate_mobject:1\nmsgid \"Interpolates the mobject of the :class:`Animation` based on alpha value.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotating.interpolate_mobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation.Rotating.interpolate_mobject:3\nmsgid \"A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.rotation.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.rotation.rst:2\nmsgid \"rotation\"\nmsgstr \"\"\n\n#: ../../../manim/animation/rotation.py:docstring of manim.animation.rotation:1\nmsgid \"Animations related to rotation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.rotation.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.rotation.rst:22:<autosummary>:1\nmsgid \"Animation that rotates a Mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.specialized.Broadcast.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.specialized.Broadcast.rst:2\nmsgid \"Broadcast\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.specialized.Broadcast.rst:4\nmsgid \"Qualified name: ``manim.animation.specialized.Broadcast``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:1\nmsgid \"Bases: :py:class:`manim.animation.composition.LaggedStart`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:1\nmsgid \"Broadcast a mobject starting from an ``initial_width``, up to the actual size of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:3\nmsgid \"The mobject to be broadcast.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:4\nmsgid \"The center of the broadcast, by default ORIGIN.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:5\nmsgid \"The number of mobjects that emerge from the focal point, by default 5.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:6\nmsgid \"The starting stroke opacity of the mobjects emitted from the broadcast, by default 1.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:7\nmsgid \"The final stroke opacity of the mobjects emitted from the broadcast, by default 0.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:8\nmsgid \"The initial width of the mobjects, by default 0.0.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:9\nmsgid \"Whether the mobjects should be removed from the scene after the animation, by default True.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:10\nmsgid \"The time between each iteration of the mobject, by default 0.2.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:11\nmsgid \"The total duration of the animation, by default 3.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:12\nmsgid \"Additional arguments to be passed to :class:`~.LaggedStart`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/specialized.py:docstring of manim.animation.specialized.Broadcast:15\nmsgid \"Examples\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.specialized.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.specialized.rst:2\nmsgid \"specialized\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.specialized.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.speedmodifier.ChangeSpeed.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:2\nmsgid \"ChangeSpeed\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:4\nmsgid \"Qualified name: ``manim.animation.speedmodifier.ChangeSpeed``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:1\nmsgid \"Modifies the speed of passed animation. :class:`AnimationGroup` with different ``lag_ratio`` can also be used which combines multiple animations into one. The ``run_time`` of the passed animation is changed to modify the speed.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:0\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:0\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.clean_up_from_scene:0\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.interpolate:0\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.update_mobjects:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:6\nmsgid \"Animation of which the speed is to be modified.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:7\nmsgid \"Contains nodes (percentage of ``run_time``) and its corresponding speed factor.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:8\nmsgid \"Overrides ``rate_func`` of passed animation, applied before changing speed.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27:<autosummary>:1\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:1\nmsgid \"This static method can be used to apply speed change to updaters.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27:<autosummary>:1\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.begin:1\nmsgid \"Begin the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27:<autosummary>:1\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.clean_up_from_scene:1\nmsgid \"Clean up the :class:`~.Scene` after finishing the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27:<autosummary>:1\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.finish:1\nmsgid \"Finish the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27:<autosummary>:1\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.get_scaled_total_time:1\nmsgid \"The time taken by the animation under the assumption that the ``run_time`` is 1.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27:<autosummary>:1\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.interpolate:1\nmsgid \"Set the animation progress.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:27:<autosummary>:1\nmsgid \"Updates things like starting_mobject, and (for Transforms) target_mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.ChangeSpeed.rst:29\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:3\nmsgid \"This updater will follow speed and rate function of any :class:`.ChangeSpeed` animation that is playing with ``affects_speed_updaters=True``. By default, updater functions added via the usual :meth:`.Mobject.add_updater` method do not respect the change of animation speed.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:8\nmsgid \"The mobject to which the updater should be attached.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:9\nmsgid \"The function that is called whenever a new frame is rendered.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:10\nmsgid \"The position in the list of the mobject's updaters at which the function should be inserted.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.add_updater:12\nmsgid \"If ``True``, calls the update function when attaching it to the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.begin:3\nmsgid \"This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.begin:0\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.clean_up_from_scene:0\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.finish:0\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.get_scaled_total_time:0\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.interpolate:0\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.update_mobjects:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.clean_up_from_scene:3\nmsgid \"This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.clean_up_from_scene:6\nmsgid \"The scene the animation should be cleaned up from.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.finish:3\nmsgid \"This method gets called when the animation is over.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.interpolate:3\nmsgid \"This method gets called for every frame during an animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier.ChangeSpeed.interpolate:5\nmsgid \"The relative time to set the animation to, 0 meaning the start, 1 meaning the end.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.speedmodifier.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.speedmodifier.rst:2\nmsgid \"speedmodifier\"\nmsgstr \"\"\n\n#: ../../../manim/animation/speedmodifier.py:docstring of manim.animation.speedmodifier:1\nmsgid \"Utilities for modifying the speed at which animations are played.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.speedmodifier.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.ApplyComplexFunction.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.ApplyComplexFunction.rst:2\nmsgid \"ApplyComplexFunction\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyComplexFunction.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.ApplyComplexFunction``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyComplexFunction:1\nmsgid \"Bases: :py:class:`manim.animation.transform.ApplyMethod`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyComplexFunction.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyComplexFunction.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.ApplyFunction.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.ApplyFunction.rst:2\nmsgid \"ApplyFunction\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyFunction.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.ApplyFunction``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyFunction:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyFunction.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyFunction.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.ApplyMatrix.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.ApplyMatrix.rst:2\nmsgid \"ApplyMatrix\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyMatrix.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.ApplyMatrix``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:1\nmsgid \"Bases: :py:class:`manim.animation.transform.ApplyPointwiseFunction`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:1\nmsgid \"Applies a matrix transform to an mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:3\nmsgid \"The transformation matrix.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:4\nmsgid \"The :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:5\nmsgid \"The origin point for the transform. Defaults to ``ORIGIN``.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:6\nmsgid \"Further keyword arguments that are passed to :class:`ApplyPointwiseFunction`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMatrix:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyMatrix.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyMatrix.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.ApplyMethod.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.ApplyMethod.rst:2\nmsgid \"ApplyMethod\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyMethod.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.ApplyMethod``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:1\nmsgid \"Animates a mobject by applying a method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:3\nmsgid \"Note that only the method needs to be passed to this animation, it is not required to pass the corresponding mobject. Furthermore, this animation class only works if the method returns the modified mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:8\nmsgid \"The method that will be applied in the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:9\nmsgid \"Any positional arguments to be passed when applying the method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyMethod:10\nmsgid \"Any keyword arguments passed to :class:`~.Transform`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyMethod.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyMethod.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.ApplyPointwiseFunction.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.ApplyPointwiseFunction.rst:2\nmsgid \"ApplyPointwiseFunction\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyPointwiseFunction.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.ApplyPointwiseFunction``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunction:1\nmsgid \"Bases: :py:class:`manim.animation.transform.ApplyMethod`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunction:1\nmsgid \"Animation that applies a pointwise function to a mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunction:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyPointwiseFunction.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyPointwiseFunction.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.rst:2\nmsgid \"ApplyPointwiseFunctionToCenter\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.ApplyPointwiseFunctionToCenter``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunctionToCenter:1\nmsgid \"Bases: :py:class:`manim.animation.transform.ApplyPointwiseFunction`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.rst:20:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunctionToCenter.begin:1\nmsgid \"Begin the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ApplyPointwiseFunctionToCenter.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ApplyPointwiseFunctionToCenter.begin:3\nmsgid \"This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.ClockwiseTransform.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.ClockwiseTransform.rst:2\nmsgid \"ClockwiseTransform\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ClockwiseTransform.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.ClockwiseTransform``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ClockwiseTransform:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ClockwiseTransform:1\nmsgid \"Transforms the points of a mobject along a clockwise oriented arc.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ClockwiseTransform:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ClockwiseTransform.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ClockwiseTransform.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.CounterclockwiseTransform.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.CounterclockwiseTransform.rst:2\nmsgid \"CounterclockwiseTransform\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.CounterclockwiseTransform.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.CounterclockwiseTransform``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.CounterclockwiseTransform:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.CounterclockwiseTransform:1\nmsgid \"Transforms the points of a mobject along a counterclockwise oriented arc.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.CounterclockwiseTransform:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.CounterclockwiseTransform.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.CounterclockwiseTransform.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.CyclicReplace.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.CyclicReplace.rst:2\nmsgid \"CyclicReplace\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.CyclicReplace.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.CyclicReplace``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.CyclicReplace:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.CyclicReplace.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.CyclicReplace.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.FadeToColor.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.FadeToColor.rst:2\nmsgid \"FadeToColor\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeToColor.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.FadeToColor``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeToColor:1\nmsgid \"Bases: :py:class:`manim.animation.transform.ApplyMethod`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeToColor:1\nmsgid \"Animation that changes color of a mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeToColor:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeToColor.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeToColor.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.FadeTransform.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransform.rst:2\nmsgid \"FadeTransform\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransform.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.FadeTransform``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:1\nmsgid \"Fades one mobject into another.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:0\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.clean_up_from_scene:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:3\nmsgid \"The starting :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:4\nmsgid \"The target :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:5\nmsgid \"Controls whether the target :class:`~.Mobject` is stretched during the animation. Default: ``True``.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:7\nmsgid \"If the target mobject is not stretched automatically, this allows to adjust the initial scale of the target :class:`~.Mobject` while it is shifted in. Setting this to 0, 1, and 2, respectively, matches the length of the target with the length of the starting :class:`~.Mobject` in x, y, and z direction, respectively.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:12\nmsgid \"Further keyword arguments are passed to the parent class.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform:15\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransform.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransform.rst:24:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.begin:1\nmsgid \"Initial setup for the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransform.rst:24:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.clean_up_from_scene:1\nmsgid \"Clean up the :class:`~.Scene` after finishing the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransform.rst:24:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.get_all_mobjects:1\nmsgid \"Get all mobjects involved in the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransform.rst:24:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.ghost_to:1\nmsgid \"Replaces the source by the target and sets the opacity to 0.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransform.rst:26\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.begin:3\nmsgid \"The mobject to which this animation is bound is a group consisting of both the starting and the ending mobject. At the start, the ending mobject replaces the starting mobject (and is completely faded). In the end, it is set to be the other way around.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.clean_up_from_scene:3\nmsgid \"This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.clean_up_from_scene:6\nmsgid \"The scene the animation should be cleaned up from.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.get_all_mobjects:3\nmsgid \"Ordering must match the ordering of arguments to interpolate_submobject\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.get_all_mobjects:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransform.get_all_mobjects:5\nmsgid \"The sequence of mobjects.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.FadeTransformPieces.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:2\nmsgid \"FadeTransformPieces\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.FadeTransformPieces``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransformPieces:1\nmsgid \"Bases: :py:class:`manim.animation.transform.FadeTransform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransformPieces:1\nmsgid \"Fades submobjects of one mobject into submobjects of another one.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransformPieces:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:21:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransformPieces.begin:1\nmsgid \"Initial setup for the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:21:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.FadeTransformPieces.ghost_to:1\nmsgid \"Replaces the source submobjects by the target submobjects and sets the opacity to 0.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.FadeTransformPieces.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.MoveToTarget.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.MoveToTarget.rst:2\nmsgid \"MoveToTarget\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.MoveToTarget.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.MoveToTarget``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.MoveToTarget:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.MoveToTarget:1\nmsgid \"Transforms a mobject to the mobject stored in its ``target`` attribute.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.MoveToTarget:3\nmsgid \"After calling the :meth:`~.Mobject.generate_target` method, the :attr:`target` attribute of the mobject is populated with a copy of it. After modifying the attribute, playing the :class:`.MoveToTarget` animation transforms the original mobject into the modified one stored in the :attr:`target` attribute.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.MoveToTarget:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.MoveToTarget.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.MoveToTarget.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.ReplacementTransform.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.ReplacementTransform.rst:2\nmsgid \"ReplacementTransform\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ReplacementTransform.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.ReplacementTransform``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:1\nmsgid \"Replaces and morphs a mobject into a target mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:3\nmsgid \"The starting :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:4\nmsgid \"The target :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:5\nmsgid \"Further keyword arguments that are passed to :class:`Transform`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ReplacementTransform:8\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ReplacementTransform.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ReplacementTransform.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.Restore.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.Restore.rst:2\nmsgid \"Restore\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Restore.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.Restore``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Restore:1\nmsgid \"Bases: :py:class:`manim.animation.transform.ApplyMethod`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Restore:1\nmsgid \"Transforms a mobject to its last saved state.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Restore:3\nmsgid \"To save the state of a mobject, use the :meth:`~.Mobject.save_state` method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Restore:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Restore.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Restore.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.ScaleInPlace.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.ScaleInPlace.rst:2\nmsgid \"ScaleInPlace\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ScaleInPlace.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.ScaleInPlace``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ScaleInPlace:1\nmsgid \"Bases: :py:class:`manim.animation.transform.ApplyMethod`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ScaleInPlace:1\nmsgid \"Animation that scales a mobject by a certain factor.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ScaleInPlace:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ScaleInPlace.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ScaleInPlace.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.ShrinkToCenter.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.ShrinkToCenter.rst:2\nmsgid \"ShrinkToCenter\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ShrinkToCenter.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.ShrinkToCenter``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ShrinkToCenter:1\nmsgid \"Bases: :py:class:`manim.animation.transform.ScaleInPlace`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ShrinkToCenter:1\nmsgid \"Animation that makes a mobject shrink to center.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.ShrinkToCenter:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ShrinkToCenter.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.ShrinkToCenter.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.Swap.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.Swap.rst:2\nmsgid \"Swap\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Swap.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.Swap``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Swap:1\nmsgid \"Bases: :py:class:`manim.animation.transform.CyclicReplace`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Swap.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Swap.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.Transform.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.Transform.rst:2\nmsgid \"Transform\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Transform.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.Transform``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:1\nmsgid \"A Transform transforms a Mobject into a target Mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:0\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.clean_up_from_scene:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:3\nmsgid \"The :class:`.Mobject` to be transformed. It will be mutated to become the ``target_mobject``.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:4\nmsgid \"The target of the transformation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:5\nmsgid \"A function defining the path that the points of the ``mobject`` are being moved along until they match the points of the ``target_mobject``, see :mod:`.utils.paths`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:7\nmsgid \"The arc angle (in radians) that the points of ``mobject`` will follow to reach the points of the target if using a circular path arc, see ``path_arc_centers``. See also :func:`manim.utils.paths.path_along_arc`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:10\nmsgid \"The axis to rotate along if using a circular path arc, see ``path_arc_centers``.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:11\nmsgid \"The center of the circular arcs along which the points of ``mobject`` are moved by the transformation.  If this is set and ``path_func`` is not set, then a ``path_along_circles`` path will be generated using the ``path_arc`` parameters and stored in ``path_func``. If ``path_func`` is set, this and the other ``path_arc`` fields are set as attributes, but a ``path_func`` is not generated from it.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:11\nmsgid \"The center of the circular arcs along which the points of ``mobject`` are moved by the transformation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:14\nmsgid \"If this is set and ``path_func`` is not set, then a ``path_along_circles`` path will be generated using the ``path_arc`` parameters and stored in ``path_func``. If ``path_func`` is set, this and the other ``path_arc`` fields are set as attributes, but a ``path_func`` is not generated from it.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:17\nmsgid \"Controls which mobject is replaced when the transformation is complete.  If set to True, ``mobject`` will be removed from the scene and ``target_mobject`` will replace it. Otherwise, ``target_mobject`` is never added and ``mobject`` just takes its shape.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:17\nmsgid \"Controls which mobject is replaced when the transformation is complete.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:19\nmsgid \"If set to True, ``mobject`` will be removed from the scene and ``target_mobject`` will replace it. Otherwise, ``target_mobject`` is never added and ``mobject`` just takes its shape.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform:23\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Transform.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Transform.rst:25:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.begin:1\nmsgid \"Begin the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Transform.rst:25:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.clean_up_from_scene:1\nmsgid \"Clean up the :class:`~.Scene` after finishing the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Transform.rst:25:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.get_all_mobjects:1\nmsgid \"Get all mobjects involved in the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.Transform.rst:27\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.begin:3\nmsgid \"This method is called right as an animation is being played. As much initialization as possible, especially any mobject copying, should live in this method.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.begin:0\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.clean_up_from_scene:0\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.get_all_mobjects:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.clean_up_from_scene:3\nmsgid \"This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.clean_up_from_scene:6\nmsgid \"The scene the animation should be cleaned up from.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.get_all_mobjects:3\nmsgid \"Ordering must match the ordering of arguments to interpolate_submobject\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.Transform.get_all_mobjects:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.TransformAnimations.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.TransformAnimations.rst:2\nmsgid \"TransformAnimations\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.TransformAnimations.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.TransformAnimations``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformAnimations:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.TransformAnimations.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.TransformAnimations.rst:20:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformAnimations.interpolate:1\nmsgid \"Set the animation progress.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.TransformAnimations.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformAnimations.interpolate:3\nmsgid \"This method gets called for every frame during an animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformAnimations.interpolate:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformAnimations.interpolate:5\nmsgid \"The relative time to set the animation to, 0 meaning the start, 1 meaning the end.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.TransformFromCopy.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.TransformFromCopy.rst:2\nmsgid \"TransformFromCopy\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.TransformFromCopy.rst:4\nmsgid \"Qualified name: ``manim.animation.transform.TransformFromCopy``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy:1\nmsgid \"Bases: :py:class:`manim.animation.transform.Transform`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy:1\nmsgid \"Performs a reversed Transform\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.TransformFromCopy.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.TransformFromCopy.rst:20:<autosummary>:1\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy.interpolate:1\nmsgid \"Set the animation progress.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.TransformFromCopy.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy.interpolate:3\nmsgid \"This method gets called for every frame during an animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy.interpolate:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform.TransformFromCopy.interpolate:5\nmsgid \"The relative time to set the animation to, 0 meaning the start, 1 meaning the end.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform.rst:2\nmsgid \"transform\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform.py:docstring of manim.animation.transform:1\nmsgid \"Animations transforming one mobject into another.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Applies a matrix transform to an mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Animates a mobject by applying a method.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Animation that applies a pointwise function to a mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Transforms the points of a mobject along a clockwise oriented arc.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Transforms the points of a mobject along a counterclockwise oriented arc.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Animation that changes color of a mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Fades one mobject into another.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Fades submobjects of one mobject into submobjects of another one.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Transforms a mobject to the mobject stored in its ``target`` attribute.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Replaces and morphs a mobject into a target mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Transforms a mobject to its last saved state.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Animation that scales a mobject by a certain factor.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"Animation that makes a mobject shrink to center.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform.rst:60:<autosummary>:1\nmsgid \"A Transform transforms a Mobject into a target Mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform_matching_parts.TransformMatchingAbstractBase.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingAbstractBase.rst:2\nmsgid \"TransformMatchingAbstractBase\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingAbstractBase.rst:4\nmsgid \"Qualified name: ``manim.animation.transform\\\\_matching\\\\_parts.TransformMatchingAbstractBase``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:1\nmsgid \"Bases: :py:class:`manim.animation.composition.AnimationGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:1\nmsgid \"Abstract base class for transformations that keep track of matching parts.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:3\nmsgid \"Subclasses have to implement the two static methods :meth:`~.TransformMatchingAbstractBase.get_mobject_parts` and :meth:`~.TransformMatchingAbstractBase.get_mobject_key`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:7\nmsgid \"Basically, this transformation first maps all submobjects returned by the ``get_mobject_parts`` method to certain keys by applying the ``get_mobject_key`` method. Then, submobjects with matching keys are transformed into each other.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:0\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase.clean_up_from_scene:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:12\nmsgid \"The starting :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:13\nmsgid \"The target :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:14\nmsgid \"Controls whether submobjects without a matching key are transformed into each other by using :class:`~.Transform`. Default: ``False``.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:16\nmsgid \"Controls whether submobjects without a matching key are transformed into each other by using :class:`~.FadeTransform`. Default: ``False``.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:18\nmsgid \"Optional. A dictionary mapping keys belonging to some of the starting mobject's submobjects (i.e., the return values of the ``get_mobject_key`` method) to some keys belonging to the target mobject's submobjects that should be transformed although the keys don't match.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:22\nmsgid \"All further keyword arguments are passed to the submobject transformations.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase:26\nmsgid \"If neither ``transform_mismatches`` nor ``fade_transform_mismatches`` are set to ``True``, submobjects without matching keys in the starting mobject are faded out in the direction of the unmatched submobjects in the target mobject, and unmatched submobjects in the target mobject are faded in from the direction of the unmatched submobjects in the start mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingAbstractBase.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase.clean_up_from_scene:1:<autosummary>:1\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase.clean_up_from_scene:1\nmsgid \"Clean up the :class:`~.Scene` after finishing the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase.clean_up_from_scene:3\nmsgid \"This includes to :meth:`~.Scene.remove` the Animation's :class:`~.Mobject` if the animation is a remover.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingAbstractBase.clean_up_from_scene:6\nmsgid \"The scene the animation should be cleaned up from.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform_matching_parts.TransformMatchingShapes.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingShapes.rst:2\nmsgid \"TransformMatchingShapes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingShapes.rst:4\nmsgid \"Qualified name: ``manim.animation.transform\\\\_matching\\\\_parts.TransformMatchingShapes``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingShapes:1\nmsgid \"Bases: :py:class:`manim.animation.transform_matching_parts.TransformMatchingAbstractBase`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingShapes:1\nmsgid \"An animation trying to transform groups by matching the shape of their submobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingShapes:4\nmsgid \"Two submobjects match if the hash of their point coordinates after normalization (i.e., after translation to the origin, fixing the submobject height at 1 unit, and rounding the coordinates to three decimal places) matches.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingShapes:12\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingShapes.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform_matching_parts.TransformMatchingTex.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingTex.rst:2\nmsgid \"TransformMatchingTex\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingTex.rst:4\nmsgid \"Qualified name: ``manim.animation.transform\\\\_matching\\\\_parts.TransformMatchingTex``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingTex:1\nmsgid \"Bases: :py:class:`manim.animation.transform_matching_parts.TransformMatchingAbstractBase`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingTex:1\nmsgid \"A transformation trying to transform rendered LaTeX strings.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingTex:3\nmsgid \"Two submobjects match if their ``tex_string`` matches.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts.TransformMatchingTex:8\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.TransformMatchingTex.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.transform_matching_parts.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.rst:2\nmsgid \"transform\\\\_matching\\\\_parts\"\nmsgstr \"\"\n\n#: ../../../manim/animation/transform_matching_parts.py:docstring of manim.animation.transform_matching_parts:1\nmsgid \"Animations that try to transform Mobjects while keeping track of identical parts.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.rst:24:<autosummary>:1\nmsgid \"Abstract base class for transformations that keep track of matching parts.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.transform_matching_parts.rst:24:<autosummary>:1\nmsgid \"An animation trying to transform groups by matching the shape of their submobjects.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.update.MaintainPositionRelativeTo.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.update.UpdateFromAlphaFunc.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.update.UpdateFromFunc.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.update.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.updaters.mobject_update_utils.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.updaters.mobject_update_utils.rst:2\nmsgid \"mobject\\\\_update\\\\_utils\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/mobject_update_utils.py:docstring of manim.animation.updaters.mobject_update_utils:1\nmsgid \"Utility functions for continuous animation of mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.updaters.mobject_update_utils.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/mobject_update_utils.py:docstring of manim.animation.updaters.mobject_update_utils.f_always:1\nmsgid \"More functional version of always, where instead of taking in args, it takes in functions which output the relevant arguments.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/mobject_update_utils.py:docstring of manim.animation.updaters.mobject_update_utils.turn_animation_into_updater:1\nmsgid \"Add an updater to the animation's mobject which applies the interpolation and update functions of the animation\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.updaters.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.updaters.rst:2\nmsgid \"updaters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/__init__.py:docstring of manim.animation.updaters:1\nmsgid \"Animations and utility mobjects related to update functions.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/__init__.py:docstring of manim.animation.updaters:4\nmsgid \"Modules\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/__init__.py:docstring of manim.animation.updaters:11:<autosummary>:1\nmsgid \"Utility functions for continuous animation of mobjects.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.updaters.update.MaintainPositionRelativeTo.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.updaters.update.MaintainPositionRelativeTo.rst:2\nmsgid \"MaintainPositionRelativeTo\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.updaters.update.MaintainPositionRelativeTo.rst:4\nmsgid \"Qualified name: ``manim.animation.updaters.update.MaintainPositionRelativeTo``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.MaintainPositionRelativeTo:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.updaters.update.MaintainPositionRelativeTo.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.MaintainPositionRelativeTo.interpolate_mobject:1:<autosummary>:1\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.MaintainPositionRelativeTo.interpolate_mobject:1\nmsgid \"Interpolates the mobject of the :class:`Animation` based on alpha value.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.MaintainPositionRelativeTo.interpolate_mobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.MaintainPositionRelativeTo.interpolate_mobject:3\nmsgid \"A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.updaters.update.UpdateFromAlphaFunc.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.updaters.update.UpdateFromAlphaFunc.rst:2\nmsgid \"UpdateFromAlphaFunc\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.updaters.update.UpdateFromAlphaFunc.rst:4\nmsgid \"Qualified name: ``manim.animation.updaters.update.UpdateFromAlphaFunc``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromAlphaFunc:1\nmsgid \"Bases: :py:class:`manim.animation.updaters.update.UpdateFromFunc`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.updaters.update.UpdateFromAlphaFunc.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromAlphaFunc.interpolate_mobject:1:<autosummary>:1\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromAlphaFunc.interpolate_mobject:1\nmsgid \"Interpolates the mobject of the :class:`Animation` based on alpha value.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromAlphaFunc.interpolate_mobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromAlphaFunc.interpolate_mobject:3\nmsgid \"A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.updaters.update.UpdateFromFunc.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.updaters.update.UpdateFromFunc.rst:2\nmsgid \"UpdateFromFunc\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.updaters.update.UpdateFromFunc.rst:4\nmsgid \"Qualified name: ``manim.animation.updaters.update.UpdateFromFunc``\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc:1\nmsgid \"Bases: :py:class:`manim.animation.animation.Animation`\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc:1\nmsgid \"update_function of the form func(mobject), presumably to be used when the state of one mobject is dependent on another simultaneously animated mobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.updaters.update.UpdateFromFunc.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc.interpolate_mobject:1:<autosummary>:1\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc.interpolate_mobject:1\nmsgid \"Interpolates the mobject of the :class:`Animation` based on alpha value.\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc.interpolate_mobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update.UpdateFromFunc.interpolate_mobject:3\nmsgid \"A float between 0 and 1 expressing the ratio to which the animation is completed. For example, alpha-values of 0, 0.5, and 1 correspond to the animation being completed 0%, 50%, and 100%, respectively.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.animation.updaters.update.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.animation.updaters.update.rst:2\nmsgid \"update\"\nmsgstr \"\"\n\n#: ../../../manim/animation/updaters/update.py:docstring of manim.animation.updaters.update:1\nmsgid \"Animations that update mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.animation.updaters.update.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.camera.BackgroundColoredVMobjectDisplayer.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.camera.BackgroundColoredVMobjectDisplayer.rst:2\nmsgid \"BackgroundColoredVMobjectDisplayer\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.BackgroundColoredVMobjectDisplayer.rst:4\nmsgid \"Qualified name: ``manim.camera.camera.BackgroundColoredVMobjectDisplayer``\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer:1\nmsgid \"Camera object to use.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.BackgroundColoredVMobjectDisplayer.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:1:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:1\nmsgid \"Displays the colored VMobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:1:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:1\nmsgid \"Gets the background array that has the passed file_name.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:1:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:1\nmsgid \"Resizes the pixel array representing the background.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:1:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:1\nmsgid \"Resizes the background array to match the passed pixel array.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:3\nmsgid \"The VMobjects\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:6\nmsgid \"The pixel array with the `cvmobjects` displayed.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.display:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:3\nmsgid \"The background image or its file name.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.get_background_array:5\nmsgid \"The pixel array of the image.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:3\nmsgid \"The pixel\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:5\nmsgid \"The new width of the background\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:7\nmsgid \"The new height of the background\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:9\nmsgid \"The PIL image mode, by default \\\"RGBA\\\"\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array:12\nmsgid \"The numpy pixel array of the resized background.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:3\nmsgid \"The prospective pixel array.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.BackgroundColoredVMobjectDisplayer.resize_background_array_to_match:5\nmsgid \"The pixel array whose width and height should be matched.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.camera.Camera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:2\nmsgid \"Camera\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:4\nmsgid \"Qualified name: ``manim.camera.camera.Camera``\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:1\nmsgid \"Base camera class.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:3\nmsgid \"This is the object which takes care of what exactly is displayed on screen at any given moment.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:6\nmsgid \"Some important configuration values and local variables to note are:\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:10\nmsgid \"background_image : :class:`str`, optional\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:9\nmsgid \"str, optional\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:9\nmsgid \"The path to an image that should be the background image. If not set, the background is filled with `self.background_color`\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:14\nmsgid \"pixel_height : :class:`int`, optional\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:13\nmsgid \"int, optional\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:13\nmsgid \"The height of the scene in pixels.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:16\nmsgid \"Initialises the Camera.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjusted_thickness:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.cache_cairo_context:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobject:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_image_mobject:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_image_mobjects:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_non_background_colored_vmobjects:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_point_cloud_mobjects:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_vectorized_mobjects:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_thickening_nudges:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_PIL_image:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_rgba_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset_pixel_shape:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.resize_frame_shape:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background_from_func:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_pixel_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:18\nmsgid \"What self.background should be, by default None as will be set later.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera:20\nmsgid \"Any local variables to be set.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:1\nmsgid \"If any of the points in the passed array are out of the viable range, they are adjusted suitably.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:0\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:0\nmsgid \"param thickness\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:1\nmsgid \"Fills the cairo context\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:1\nmsgid \"Applies a stroke to the VMobject in the cairo context.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.cache_cairo_context:1\nmsgid \"Caches the passed Pixel array into a Cairo Context\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobject:1\nmsgid \"Capture mobjects by storing it in :attr:`pixel_array`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:1\nmsgid \"Capture mobjects by printing them on :attr:`pixel_array`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:1\nmsgid \"Converts a pixel array from values that have floats in then to proper RGB values.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_image_mobject:1\nmsgid \"Displays an ImageMobject by changing the pixel_array suitably.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:1\nmsgid \"Displays multiple vmobjects that have the same color as the background.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_image_mobjects:1\nmsgid \"Displays multiple image mobjects by modifying the passed pixel_array.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_non_background_colored_vmobjects:1\nmsgid \"Displays multiple VMobjects in the cairo context, as long as they don't have background colors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_point_cloud_mobjects:1\nmsgid \"Displays multiple PMobjects by modifying the passed pixel array.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_vectorized_mobjects:1\nmsgid \"Displays multiple VMobjects in the pixel_array\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\nmsgid \"Displays a PMobject by modifying the Pixel array suitably.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:1\nmsgid \"Displays a VMobject in the cairo context\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_background_colored_vmobject_displayer:1\nmsgid \"Returns the background_colored_vmobject_displayer if it exists or makes one and returns it if not.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:1\nmsgid \"Returns the cached cairo context of the passed pixel array if it exists, and None if it doesn't.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:1\nmsgid \"Returns the cairo context for a pixel array after caching it to self.pixel_array_to_cairo_context If that array has already been cached, it returns the cached version instead.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_coords_of_all_pixels:1\nmsgid \"Returns the cartesian coordinates of each pixel.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:1\nmsgid \"Returns the RGBA array of the fill of the passed VMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:1\nmsgid \"Returns an image from the passed pixel array, or from the current frame if the passed pixel array is none.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:1\nmsgid \"Used to get the list of mobjects to display with the camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:1\nmsgid \"Gets the RGBA array for the stroke of the passed VMobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\nmsgid \"Initialize the background.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:1\nmsgid \"Checks whether the passed mobject is in frame or not.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\nmsgid \"Makes a pixel array for the background by using coords_to_colors_func to determine each pixel's color.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:1\nmsgid \"Returns array of pixels that are on the screen from a given array of pixel_coordinates\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_PIL_image:1\nmsgid \"Overlays a PIL image on the passed pixel array.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_rgba_array:1\nmsgid \"Overlays an RGBA array on top of the given Pixel array.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset:1\nmsgid \"Resets the camera's pixel array to that of the background\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset_pixel_shape:1\nmsgid \"This method resets the height and width of a single pixel to the passed new_height and new_width.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.resize_frame_shape:1\nmsgid \"Changes frame_shape to match the aspect ratio of the pixels, where fixed_dimension determines whether frame_height or frame_width remains fixed while the other changes accordingly.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background:1\nmsgid \"Sets the background to the passed pixel_array after converting to valid RGB values.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\nmsgid \"Sets the background to a pixel array using coords_to_colors_func to determine each pixel's color.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:1\nmsgid \"Sets the color of the cairo context\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:1\nmsgid \"Sets a path for the cairo context with the vmobject passed\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_pixel_array:1\nmsgid \"Sets the pixel array of the camera to the passed pixel array.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:1\nmsgid \"Returns thickened coordinates for a passed array of pixel coords and a thickness to thicken by.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:63:<autosummary>:1\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:1\nmsgid \"Return the type of mobject, if it is a type that can be rendered.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.Camera.rst:65\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:4\nmsgid \"The points to adjust\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_background_colored_vmobject_displayer:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_coords_of_all_pixels:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:7\nmsgid \"The adjusted points.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjust_out_of_range_points:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.adjusted_thickness:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_background_colored_vmobject_displayer:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_coords_of_all_pixels:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_thickening_nudges:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:0\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:3\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:3\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:3\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:3\nmsgid \"The cairo context\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:5\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:5\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:3\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:4\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:5\nmsgid \"The VMobject\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_fill:8\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:8\nmsgid \"The camera object.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:7\nmsgid \"Whether or not to consider the background when applying this stroke width, by default False\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.apply_stroke:11\nmsgid \"The camera object with the stroke applied.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.cache_cairo_context:3\nmsgid \"The pixel array to cache\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.cache_cairo_context:5\nmsgid \"The context to cache it into.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobject:3\nmsgid \"This is a single-mobject version of :meth:`capture_mobjects`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobject:5\nmsgid \"Mobject to capture.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobject:6\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:8\nmsgid \"Keyword arguments to be passed to :meth:`get_mobjects_to_display`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:3\nmsgid \"This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:6\nmsgid \"Mobjects to capture.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:12\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:12\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.capture_mobjects:13\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:13\nmsgid \"For a list of classes that can currently be rendered, see :meth:`display_funcs`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:4\nmsgid \"Pixel array to convert.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:6\nmsgid \"Whether or not to convert float values to ints, by default False\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.convert_pixel_array:9\nmsgid \"The new, converted pixel array.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_image_mobject:3\nmsgid \"The imageMobject to display\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_image_mobject:5\nmsgid \"The Pixel array to put the imagemobject in.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:3\nmsgid \"List of Colored VMobjects\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_background_colored_vmobjects:5\nmsgid \"The pixel array.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_image_mobjects:3\nmsgid \"list of ImageMobjects\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_image_mobjects:5\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_point_cloud_mobjects:5\nmsgid \"The pixel array to modify.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_non_background_colored_vmobjects:4\nmsgid \"list of the VMobjects\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_non_background_colored_vmobjects:6\nmsgid \"The Pixel array to add the VMobjects to.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_point_cloud_mobjects:3\nmsgid \"List of PMobjects\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_vectorized_mobjects:3\nmsgid \"list of VMobjects to display\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_multiple_vectorized_mobjects:5\nmsgid \"The pixel array\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_point_cloud:1\nmsgid \"Displays a PMobject by modifying the Pixel array suitably.. TODO: Write a description for the rgbas argument. :param pmobject: Point Cloud Mobject :type pmobject: PMobject :param points: The points to display in the point cloud mobject :type points: list :param rgbas: :type rgbas: np.array :param thickness: The thickness of each point of the PMobject :type thickness: int, float :param pixel_array: The pixel array to modify. :type pixel_array: np.array\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:3\nmsgid \"The Vectorized Mobject to display\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:5\nmsgid \"The cairo context to use.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.display_vectorized:8\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:10\nmsgid \"The camera object\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_background_colored_vmobject_displayer:4\nmsgid \"Object that displays VMobjects that have the same color as the background.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:4\nmsgid \"The pixel array to check.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cached_cairo_context:7\nmsgid \"The cached cairo context.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:6\nmsgid \"The Pixel array to get the cairo context of.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_cairo_context:9\nmsgid \"The cairo context of the pixel array.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_coords_of_all_pixels:3\nmsgid \"The array of cartesian coordinates.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_fill_rgbas:6\nmsgid \"The RGBA Array of the fill of the VMobject\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:5\nmsgid \"The pixel array from which to get an image, by default None\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_image:8\nmsgid \"The PIL image of the array.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:4\nmsgid \"The Mobjects\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:6\nmsgid \"Whether or not to include the submobjects of mobjects, by default True\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:8\nmsgid \"Any mobjects to exclude, by default None\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_mobjects_to_display:11\nmsgid \"list of mobjects\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:6\nmsgid \"Whether or not to consider the background when getting the stroke RGBAs, by default False\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.get_stroke_rgbas:10\nmsgid \"The RGBA array of the stroke.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.init_background:1\nmsgid \"Initialize the background. If self.background_image is the path of an image the image is set as background; else, the default background color fills the background.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:4\nmsgid \"The mobject for which the checking needs to be done.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.is_in_frame:7\nmsgid \"True if in frame, False otherwise.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:1\nmsgid \"Makes a pixel array for the background by using coords_to_colors_func to determine each pixel's color. Each input pixel's color. Each input to coords_to_colors_func is an (x, y) pair in space (in ordinary space coordinates; not pixel coordinates), and each output is expected to be an RGBA array of 4 floats.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:5\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background_from_func:5\nmsgid \"The function whose input is an (x,y) pair of coordinates and whose return values must be the colors for that point\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.make_background_from_func:9\nmsgid \"The pixel array which can then be passed to set_background.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:4\nmsgid \"The pixel coords to check.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.on_screen_pixels:7\nmsgid \"The pixel coords on screen.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_PIL_image:3\nmsgid \"The Pixel array\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_PIL_image:5\nmsgid \"The Image to overlay.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_rgba_array:3\nmsgid \"The original pixel array to modify.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.overlay_rgba_array:5\nmsgid \"The new pixel array to overlay.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset:4\nmsgid \"The camera object after setting the pixel array.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset_pixel_shape:4\nmsgid \"The new height of the entire scene in pixels\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.reset_pixel_shape:6\nmsgid \"The new width of the entire scene in pixels\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.resize_frame_shape:6\nmsgid \"If 0, height is scaled with respect to width else, width is scaled with respect to height.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background:4\nmsgid \"The pixel array to set the background to.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background:6\nmsgid \"Whether or not to convert floats values to proper RGB valid ones, by default False\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_background_from_func:1\nmsgid \"Sets the background to a pixel array using coords_to_colors_func to determine each pixel's color. Each input pixel's color. Each input to coords_to_colors_func is an (x, y) pair in space (in ordinary space coordinates; not pixel coordinates), and each output is expected to be an RGBA array of 4 floats.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:5\nmsgid \"The RGBA array with which to color the context.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_color:7\nmsgid \"The VMobject with which to set the color.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_cairo_context_path:8\nmsgid \"Camera object after setting cairo_context_path\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_pixel_array:3\nmsgid \"The pixel array to convert and then set as the camera's pixel array.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.set_pixel_array:5\nmsgid \"Whether or not to convert float values to proper RGB values, by default False\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:4\nmsgid \"Pixel coordinates\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:6\nmsgid \"Thickness\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.thickened_coordinates:9\nmsgid \"Array of thickened pixel coords.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:3\nmsgid \"If `mobject` is an instance of a class that inherits from a class that can be rendered, return the super class.  For example, an instance of a Square is also an instance of VMobject, and these can be rendered. Therefore, `type_or_raise(Square())` returns True.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:8\nmsgid \"The object to take the type of.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:15\nmsgid \"The type of mobjects, if it can be rendered.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:16\nmsgid \"Type[:class:`~.Mobject`]\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera.Camera.type_or_raise:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.camera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.camera.rst:2\nmsgid \"camera\"\nmsgstr \"\"\n\n#: ../../../manim/camera/camera.py:docstring of manim.camera.camera:1\nmsgid \"A camera converts the mobjects contained in a Scene into an array of pixels.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.rst:22:<autosummary>:0\nmsgid \"param camera\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.camera.rst:22:<autosummary>:1\nmsgid \"Camera object to use.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.mapping_camera.MappingCamera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.mapping_camera.MappingCamera.rst:2\nmsgid \"MappingCamera\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.MappingCamera.rst:4\nmsgid \"Qualified name: ``manim.camera.mapping\\\\_camera.MappingCamera``\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:1\nmsgid \"Bases: :py:class:`manim.camera.camera.Camera`\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:1\nmsgid \"Camera object that allows mapping between objects.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:4\nmsgid \"Initialises the Camera.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:0\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:6\nmsgid \"What self.background should be, by default None as will be set later.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera:8\nmsgid \"Any local variables to be set.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.MappingCamera.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.MappingCamera.rst:21:<autosummary>:1\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:1\nmsgid \"Capture mobjects by printing them on :attr:`pixel_array`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.MappingCamera.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:3\nmsgid \"This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:6\nmsgid \"Mobjects to capture.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:8\nmsgid \"Keyword arguments to be passed to :meth:`get_mobjects_to_display`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.MappingCamera.capture_mobjects:12\nmsgid \"Notes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.mapping_camera.OldMultiCamera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:2\nmsgid \"OldMultiCamera\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:4\nmsgid \"Qualified name: ``manim.camera.mapping\\\\_camera.OldMultiCamera``\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera:1\nmsgid \"Bases: :py:class:`manim.camera.camera.Camera`\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera:1\nmsgid \"Initialises the Camera.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera:0\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:0\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_background:0\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_pixel_array:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera:3\nmsgid \"What self.background should be, by default None as will be set later.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera:5\nmsgid \"Any local variables to be set.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:23:<autosummary>:1\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:1\nmsgid \"Capture mobjects by printing them on :attr:`pixel_array`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:23:<autosummary>:1\nmsgid \"Initialize the background.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:23:<autosummary>:1\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_background:1\nmsgid \"Sets the background to the passed pixel_array after converting to valid RGB values.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:23:<autosummary>:1\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_pixel_array:1\nmsgid \"Sets the pixel array of the camera to the passed pixel array.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.OldMultiCamera.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:3\nmsgid \"This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:6\nmsgid \"Mobjects to capture.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:8\nmsgid \"Keyword arguments to be passed to :meth:`get_mobjects_to_display`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:12\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.capture_mobjects:13\nmsgid \"For a list of classes that can currently be rendered, see :meth:`display_funcs`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.init_background:1\nmsgid \"Initialize the background. If self.background_image is the path of an image the image is set as background; else, the default background color fills the background.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_background:4\nmsgid \"The pixel array to set the background to.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_background:6\nmsgid \"Whether or not to convert floats values to proper RGB valid ones, by default False\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.OldMultiCamera.set_pixel_array:3\nmsgid \"The pixel array to convert and then set as the camera's pixel array.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.mapping_camera.SplitScreenCamera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.mapping_camera.SplitScreenCamera.rst:2\nmsgid \"SplitScreenCamera\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.SplitScreenCamera.rst:4\nmsgid \"Qualified name: ``manim.camera.mapping\\\\_camera.SplitScreenCamera``\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.SplitScreenCamera:1\nmsgid \"Bases: :py:class:`manim.camera.mapping_camera.OldMultiCamera`\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.SplitScreenCamera:1\nmsgid \"Initialises the Camera.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.SplitScreenCamera:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.SplitScreenCamera:3\nmsgid \"What self.background should be, by default None as will be set later.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera.SplitScreenCamera:5\nmsgid \"Any local variables to be set.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.SplitScreenCamera.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.SplitScreenCamera.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.mapping_camera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.mapping_camera.rst:2\nmsgid \"mapping\\\\_camera\"\nmsgstr \"\"\n\n#: ../../../manim/camera/mapping_camera.py:docstring of manim.camera.mapping_camera:1\nmsgid \"A camera that allows mapping between objects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.rst:24:<autosummary>:1\nmsgid \"Camera object that allows mapping between objects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.mapping_camera.rst:24:<autosummary>:1\n#: ../../source/reference/manim.camera.mapping_camera.rst:24:<autosummary>:1\nmsgid \"Initialises the Camera.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.moving_camera.CameraFrame.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.moving_camera.MovingCamera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:2\nmsgid \"MovingCamera\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:4\nmsgid \"Qualified name: ``manim.camera.moving\\\\_camera.MovingCamera``\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera:1\nmsgid \"Bases: :py:class:`manim.camera.camera.Camera`\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera:1\nmsgid \"Stays in line with the height, width and position of it's 'frame', which is a Rectangle\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera:8\nmsgid \"Frame is a Mobject, (should almost certainly be a rectangle) determining which region of space the camera displays\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:24:<autosummary>:1\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:1\nmsgid \"Zooms on to a given array of mobjects (or a singular mobject) and automatically resizes to frame all the mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:24:<autosummary>:1\n#: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:24:<autosummary>:1\nmsgid \"Since the frame can be moving around, the cairo context used for updating should be regenerated at each frame.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:24:<autosummary>:1\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:1\nmsgid \"Capture mobjects by printing them on :attr:`pixel_array`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:24:<autosummary>:1\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.get_mobjects_indicating_movement:1\nmsgid \"Returns all mobjects whose movement implies that the camera should think of all other mobjects on the screen as moving\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.moving_camera.MovingCamera.rst:26\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:1:<autosummary>:1\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_center:1\nmsgid \"Returns the centerpoint of the frame in cartesian coordinates.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:1:<autosummary>:1\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_height:1\nmsgid \"Returns the height of the frame.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:1:<autosummary>:1\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_width:1\nmsgid \"Returns the width of the frame\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:6\nmsgid \"This method only works when 2D-objects in the XY-plane are considered, it will not work correctly when the camera has been rotated.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:0\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:9\nmsgid \"The mobject or array of mobjects that the camera will focus on.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:10\nmsgid \"The width of the margin that is added to the frame (optional, 0 by default).\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:11\nmsgid \"If set to ``True``, only allows focusing on mobjects that are already in frame.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:12\nmsgid \"If set to ``False``, applies the changes instead of returning the corresponding animation\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:0\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_center:0\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_height:0\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_width:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:14\nmsgid \"_AnimationBuilder that zooms the camera view to a given list of mobjects or ScreenRectangle with position and size updated to zoomed position.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.auto_zoom:0\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_center:0\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_height:0\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_width:0\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.get_mobjects_indicating_movement:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.cache_cairo_context:1\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.get_cached_cairo_context:1\nmsgid \"Since the frame can be moving around, the cairo context used for updating should be regenerated at each frame.  So no caching.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:3\nmsgid \"This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:6\nmsgid \"Mobjects to capture.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:8\nmsgid \"Keyword arguments to be passed to :meth:`get_mobjects_to_display`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:12\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.capture_mobjects:13\nmsgid \"For a list of classes that can currently be rendered, see :meth:`display_funcs`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_center:3\nmsgid \"The cartesian coordinates of the center of the frame.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera.MovingCamera.frame_height:3\nmsgid \"The height of the frame.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.moving_camera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.moving_camera.rst:2\nmsgid \"moving\\\\_camera\"\nmsgstr \"\"\n\n#: ../../../manim/camera/moving_camera.py:docstring of manim.camera.moving_camera:1\nmsgid \"A camera able to move through a scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.moving_camera.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.multi_camera.MultiCamera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:2\nmsgid \"MultiCamera\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:4\nmsgid \"Qualified name: ``manim.camera.multi\\\\_camera.MultiCamera``\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera:1\nmsgid \"Bases: :py:class:`manim.camera.moving_camera.MovingCamera`\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera:1\nmsgid \"Camera Object that allows for multiple perspectives.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera:3\nmsgid \"Initialises the MultiCamera\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera:0\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:0\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera:7\nmsgid \"Any valid keyword arguments of MovingCamera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:24:<autosummary>:1\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:1\nmsgid \"Adds an ImageMobject that's been obtained from the camera into the list ``self.image_mobject_from_cameras``\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:24:<autosummary>:1\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:1\nmsgid \"Capture mobjects by printing them on :attr:`pixel_array`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:24:<autosummary>:1\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.get_mobjects_indicating_movement:1\nmsgid \"Returns all mobjects whose movement implies that the camera should think of all other mobjects on the screen as moving\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:24:<autosummary>:1\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.reset:1\nmsgid \"Resets the MultiCamera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:24:<autosummary>:1\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.update_sub_cameras:1\nmsgid \"Reshape sub_camera pixel_arrays\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.multi_camera.MultiCamera.rst:26\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:1:<autosummary>:1\nmsgid \"Returns the centerpoint of the frame in cartesian coordinates.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:1:<autosummary>:1\nmsgid \"Returns the height of the frame.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:1:<autosummary>:1\nmsgid \"Returns the width of the frame\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.add_image_mobject_from_camera:4\nmsgid \"The ImageMobject to add to self.image_mobject_from_cameras\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:3\nmsgid \"This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:6\nmsgid \"Mobjects to capture.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:8\nmsgid \"Keyword arguments to be passed to :meth:`get_mobjects_to_display`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:12\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.capture_mobjects:13\nmsgid \"For a list of classes that can currently be rendered, see :meth:`display_funcs`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.get_mobjects_indicating_movement:0\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.reset:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera.MultiCamera.reset:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.multi_camera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.multi_camera.rst:2\nmsgid \"multi\\\\_camera\"\nmsgstr \"\"\n\n#: ../../../manim/camera/multi_camera.py:docstring of manim.camera.multi_camera:1\nmsgid \"A camera supporting multiple perspectives.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.multi_camera.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.three_d_camera.ThreeDCamera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:2\nmsgid \"ThreeDCamera\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:4\nmsgid \"Qualified name: ``manim.camera.three\\\\_d\\\\_camera.ThreeDCamera``\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera:1\nmsgid \"Bases: :py:class:`manim.camera.camera.Camera`\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera:1\nmsgid \"Initializes the ThreeDCamera\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_in_frame_mobjects:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_orientation_mobjects:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_in_frame_mobjects:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_orientation_mobjects:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_focal_distance:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_gamma:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_phi:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_theta:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_zoom:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera:3\nmsgid \"Any argument of Camera\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera:4\nmsgid \"Any keyword argument of Camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\nmsgid \"This method allows the mobject to have a fixed position, even when the camera moves around.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\nmsgid \"This method allows the mobject to have a fixed orientation, even when the camera moves around.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:1\nmsgid \"Capture mobjects by printing them on :attr:`pixel_array`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.generate_rotation_matrix:1\nmsgid \"Generates a rotation matrix based off the current position of the camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:1\nmsgid \"Returns the RGBA array of the fill of the passed VMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_focal_distance:1\nmsgid \"Returns focal_distance of the Camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_gamma:1\nmsgid \"Returns the rotation of the camera about the vector from the ORIGIN to the Camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:1\nmsgid \"Used to get the list of mobjects to display with the camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_phi:1\nmsgid \"Returns the Polar angle (the angle off Z_AXIS) phi.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_rotation_matrix:1\nmsgid \"Returns the matrix corresponding to the current position of the camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:1\nmsgid \"Gets the RGBA array for the stroke of the passed VMobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_theta:1\nmsgid \"Returns the Azimuthal i.e the angle that spins the camera around the Z_AXIS.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_value_trackers:1\nmsgid \"Returns list of ValueTrackers of phi, theta, focal_distance and gamma\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_zoom:1\nmsgid \"Returns the zoom amount of the camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:1\nmsgid \"Applies the current rotation_matrix as a projection matrix to the passed point.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:1\nmsgid \"Applies the current rotation_matrix as a projection matrix to the passed array of points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\nmsgid \"If a mobject was fixed in frame by passing it through :meth:`.add_fixed_in_frame_mobjects`, then this undoes that fixing.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\nmsgid \"If a mobject was fixed in its orientation by passing it through :meth:`.add_fixed_orientation_mobjects`, then this undoes that fixing.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.reset_rotation_matrix:1\nmsgid \"Sets the value of self.rotation_matrix to the matrix corresponding to the current position of the camera\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_focal_distance:1\nmsgid \"Sets the focal_distance of the Camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_gamma:1\nmsgid \"Sets the angle of rotation of the camera about the vector from the ORIGIN to the Camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_phi:1\nmsgid \"Sets the polar angle i.e the angle between Z_AXIS and Camera through ORIGIN in radians.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_theta:1\nmsgid \"Sets the azimuthal angle i.e the angle that spins the camera around Z_AXIS in radians.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:45:<autosummary>:1\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_zoom:1\nmsgid \"Sets the zoom amount of the camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.ThreeDCamera.rst:47\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_in_frame_mobjects:1\nmsgid \"This method allows the mobject to have a fixed position, even when the camera moves around. E.G If it was passed through this method, at the top of the frame, it will continue to be displayed at the top of the frame.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_in_frame_mobjects:6\nmsgid \"Highly useful when displaying Titles or formulae or the like.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_in_frame_mobjects:8\nmsgid \"The mobject to fix in frame.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_orientation_mobjects:1\nmsgid \"This method allows the mobject to have a fixed orientation, even when the camera moves around. E.G If it was passed through this method, facing the camera, it will continue to face the camera even as the camera moves. Highly useful when adding labels to graphs and the like.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_orientation_mobjects:7\nmsgid \"The mobject whose orientation must be fixed.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_orientation_mobjects:9\nmsgid \"Whether or not to use the function that takes the mobject's center as centerpoint, by default False\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.add_fixed_orientation_mobjects:12\nmsgid \"The function which returns the centerpoint with respect to which the mobject will be oriented, by default None\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:3\nmsgid \"This is the essential function that converts the contents of a Scene into an array, which is then converted to an image or video.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:6\nmsgid \"Mobjects to capture.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:8\nmsgid \"Keyword arguments to be passed to :meth:`get_mobjects_to_display`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:12\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.capture_mobjects:13\nmsgid \"For a list of classes that can currently be rendered, see :meth:`display_funcs`.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.generate_rotation_matrix:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_focal_distance:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_gamma:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_phi:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_rotation_matrix:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_theta:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_value_trackers:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_zoom:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.generate_rotation_matrix:3\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_rotation_matrix:3\nmsgid \"The matrix corresponding to the current position of the camera.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.generate_rotation_matrix:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_focal_distance:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_gamma:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_phi:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_rotation_matrix:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_theta:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_value_trackers:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_zoom:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:0\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:3\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:4\nmsgid \"The VMobject\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_fill_rgbas:6\nmsgid \"The RGBA Array of the fill of the VMobject\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_focal_distance:3\nmsgid \"The focal_distance of the Camera in MUnits.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_gamma:3\nmsgid \"The angle of rotation of the camera about the vector from the ORIGIN to the Camera in radians\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:4\nmsgid \"The Mobjects\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:6\nmsgid \"Whether or not to include the submobjects of mobjects, by default True\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:8\nmsgid \"Any mobjects to exclude, by default None\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_mobjects_to_display:11\nmsgid \"list of mobjects\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_phi:3\nmsgid \"The Polar angle in radians.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:6\nmsgid \"Whether or not to consider the background when getting the stroke RGBAs, by default False\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_stroke_rgbas:10\nmsgid \"The RGBA array of the stroke.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_theta:3\nmsgid \"The Azimuthal angle in radians.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_value_trackers:3\nmsgid \"list of ValueTracker objects\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.get_zoom:3\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_zoom:3\nmsgid \"The zoom amount of the camera.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:4\nmsgid \"The point to project.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_point:7\nmsgid \"The point after projection.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:4\nmsgid \"The list of points to project.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.project_points:7\nmsgid \"The points after projecting.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_in_frame_mobjects:1\nmsgid \"If a mobject was fixed in frame by passing it through :meth:`.add_fixed_in_frame_mobjects`, then this undoes that fixing. The Mobject will no longer be fixed in frame.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_in_frame_mobjects:5\nmsgid \"The mobjects which need not be fixed in frame any longer.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_orientation_mobjects:1\nmsgid \"If a mobject was fixed in its orientation by passing it through :meth:`.add_fixed_orientation_mobjects`, then this undoes that fixing. The Mobject will no longer have a fixed orientation.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.remove_fixed_orientation_mobjects:5\nmsgid \"The mobjects whose orientation need not be fixed any longer.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_focal_distance:3\nmsgid \"The focal_distance of the Camera.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_gamma:3\nmsgid \"The new angle of rotation of the camera.\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera.ThreeDCamera.set_phi:3\nmsgid \"The new value of the polar angle in radians.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.camera.three_d_camera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.camera.three_d_camera.rst:2\nmsgid \"three\\\\_d\\\\_camera\"\nmsgstr \"\"\n\n#: ../../../manim/camera/three_d_camera.py:docstring of manim.camera.three_d_camera:1\nmsgid \"A camera that can be positioned and oriented in three-dimensional space.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.camera.three_d_camera.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.constants.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.constants.rst:2\nmsgid \"constants\"\nmsgstr \"\"\n\n#: ../../../manim/constants.py:docstring of manim.constants:1\nmsgid \"Constant definitions.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:11\nmsgid \"Module Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"The center of the coordinate system.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"One unit step in the positive Y direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"One unit step in the negative Y direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"One unit step in the positive X direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"One unit step in the negative X direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"One unit step in the negative Z direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"One unit step in the positive Z direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"One step up plus one step left.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"One step up plus one step right.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"One step down plus one step left.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"One step down plus one step right.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"The ratio of the circumference of a circle to its diameter.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.constants.rst:27:<autosummary>:1\nmsgid \"The ratio of the circumference of a circle to its radius.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.boolean_ops.Difference.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.boolean_ops.Exclusion.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.boolean_ops.Intersection.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.boolean_ops.Union.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.boolean_ops.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.changing.AnimatedBoundary.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.changing.TracedPath.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.changing.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.coordinate_systems.Axes.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.coordinate_systems.ComplexPlane.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.coordinate_systems.CoordinateSystem.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.coordinate_systems.NumberPlane.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.coordinate_systems.PolarPlane.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.coordinate_systems.ThreeDAxes.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.coordinate_systems.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.frame.FullScreenFadeRectangle.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.frame.FullScreenRectangle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:2\nmsgid \"FullScreenRectangle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:4\nmsgid \"Qualified name: ``manim.mobject.frame.FullScreenRectangle``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.FullScreenRectangle:1\nmsgid \"Bases: :py:class:`manim.mobject.frame.ScreenRectangle`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:33:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:33:<autosummary>:1\nmsgid \"The aspect ratio.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:33:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:33:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.FullScreenRectangle.rst:33:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.frame.PictureInPictureFrame.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.frame.ScreenRectangle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.frame.ScreenRectangle.rst:2\nmsgid \"ScreenRectangle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.ScreenRectangle.rst:4\nmsgid \"Qualified name: ``manim.mobject.frame.ScreenRectangle``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.Rectangle`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.ScreenRectangle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.ScreenRectangle.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1:<autosummary>:1\n#: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1\nmsgid \"The aspect ratio.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame.ScreenRectangle.aspect_ratio:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.frame.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.frame.rst:2\nmsgid \"frame\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/frame.py:docstring of manim.mobject.frame:1\nmsgid \"Special rectangles.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.frame.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.functions.FunctionGraph.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.functions.ImplicitFunction.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.functions.ParametricFunction.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.functions.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Angle.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.AnnotationDot.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.AnnularSector.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Annulus.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.ArcBetweenPoints.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.ArcPolygon.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.ArcPolygonFromArcs.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Arrow.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.ArrowCircleFilledTip.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.ArrowCircleTip.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.ArrowSquareFilledTip.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.ArrowSquareTip.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.ArrowTip.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.ArrowTriangleFilledTip.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.ArrowTriangleTip.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Circle.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.CubicBezier.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.CurvedArrow.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.CurvedDoubleArrow.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Cutout.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.DashedLine.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Dot.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.DoubleArrow.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Elbow.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Ellipse.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.LabeledDot.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Polygon.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Rectangle.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.RegularPolygon.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.RegularPolygram.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.RightAngle.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.RoundedRectangle.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Sector.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Square.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Star.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.TangentLine.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.TipableVMobject.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Triangle.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.Vector.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.AnnotationDot.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:2\nmsgid \"AnnotationDot\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.AnnotationDot``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnotationDot:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.Dot`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnotationDot:1\nmsgid \"A dot with bigger radius and bold stroke to annotate scenes.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnotationDot.rst:32:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.AnnularSector.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:2\nmsgid \"AnnularSector\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.AnnularSector``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.Arc`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:1\nmsgid \"The inside radius of the Annular Sector.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:2\nmsgid \"The outside radius of the Annular Sector.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:3\nmsgid \"The clockwise angle of the Annular Sector.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:4\nmsgid \"The starting clockwise angle of the Annular Sector.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:5\nmsgid \"The opacity of the color filled in the Annular Sector.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:6\nmsgid \"The stroke width of the Annular Sector.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:7\nmsgid \"The color filled into the Annular Sector.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector:10\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:21:<autosummary>:1\n#: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:21:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.AnnularSector.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.AnnularSector.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.Annulus.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:2\nmsgid \"Annulus\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.Annulus``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.Circle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:1\nmsgid \"Region between two concentric :class:`Circles <.Circle>`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:3\nmsgid \"The radius of the inner :class:`Circle`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:4\nmsgid \"The radius of the outer :class:`Circle`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:5\nmsgid \"Additional arguments to be passed to :class:`Annulus`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus:8\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:21:<autosummary>:1\n#: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:21:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Annulus.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Annulus.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.Arc.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:2\nmsgid \"Arc\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.Arc``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.TipableVMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc:1\nmsgid \"A circular arc.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc:5\nmsgid \"A simple arc of angle Pi.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:24:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:24:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.get_arc_center:1\nmsgid \"Looks at the normals to the first two anchors, and finds their intersection points\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Arc.rst:26\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Arc:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.ArcBetweenPoints.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:2\nmsgid \"ArcBetweenPoints\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.ArcBetweenPoints``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcBetweenPoints:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.Arc`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcBetweenPoints:1\nmsgid \"Inherits from Arc and additionally takes 2 points between which the arc is spanned.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcBetweenPoints:4\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcBetweenPoints.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.ArcPolygon.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:2\nmsgid \"ArcPolygon\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.ArcPolygon``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:1\nmsgid \"A generalized polygon allowing for points to be connected with arcs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:3\nmsgid \"This version tries to stick close to the way :class:`Polygon` is used. Points can be passed to it directly which are used to generate the according arcs (using :class:`ArcBetweenPoints`). An angle or radius can be passed to it to use across all arcs, but to configure arcs individually an ``arc_config`` list has to be passed with the syntax explained below.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:9\nmsgid \"A list of vertices, start and end points for the arc segments.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:10\nmsgid \"The angle used for constructing the arcs. If no other parameters are set, this angle is used to construct all arcs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:12\nmsgid \"The circle radius used to construct the arcs. If specified, overrides the specified ``angle``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:14\nmsgid \"When passing a ``dict``, its content will be passed as keyword arguments to :class:`~.ArcBetweenPoints`. Otherwise, a list of dictionaries containing values that are passed as keyword arguments for every individual arc can be passed.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:18\nmsgid \"Further keyword arguments that are passed to the constructor of :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:25\nmsgid \"The arcs created from the input parameters::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:0\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:36\nmsgid \"Two instances of :class:`ArcPolygon` can be transformed properly into one another as well. Be advised that any arc initialized with ``angle=0`` will actually be a straight line, so if a straight section should seamlessly transform into an arced section or vice versa, initialize the straight section with a negligible angle instead (such as ``angle=0.0001``).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:43\nmsgid \"There is an alternative version (:class:`ArcPolygonFromArcs`) that is instantiated with pre-defined arcs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:49\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygon:68\nmsgid \"For further examples see :class:`ArcPolygonFromArcs`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygon.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:2\nmsgid \"ArcPolygonFromArcs\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.ArcPolygonFromArcs``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:1\nmsgid \"A generalized polygon allowing for points to be connected with arcs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:3\nmsgid \"This version takes in pre-defined arcs to generate the arcpolygon and introduces little new syntax. However unlike :class:`Polygon` it can't be created with points directly.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:7\nmsgid \"For proper appearance the passed arcs should connect seamlessly: ``[a,b][b,c][c,a]``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:10\nmsgid \"If there are any gaps between the arcs, those will be filled in with straight lines, which can be used deliberately for any straight sections. Arcs can also be passed as straight lines such as an arc initialized with ``angle=0``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:15\nmsgid \"These are the arcs from which the arcpolygon is assembled.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:16\nmsgid \"Keyword arguments that are passed to the constructor of :class:`~.VMobject`. Affects how the ArcPolygon itself is drawn, but doesn't affect passed arcs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:24\nmsgid \"The arcs used to initialize the ArcPolygonFromArcs::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:33\nmsgid \"Two instances of :class:`ArcPolygon` can be transformed properly into one another as well. Be advised that any arc initialized with ``angle=0`` will actually be a straight line, so if a straight section should seamlessly transform into an arced section or vice versa, initialize the straight section with a negligible angle instead (such as ``angle=0.0001``).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:40\nmsgid \"There is an alternative version (:class:`ArcPolygon`) that can be instantiated with points.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:47\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:48\nmsgid \"One example of an arcpolygon is the Reuleaux triangle. Instead of 3 straight lines connecting the outer points, a Reuleaux triangle has 3 arcs connecting those points, making a shape with constant width.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:53\nmsgid \"Passed arcs are stored as submobjects in the arcpolygon. This means that the arcs are changed along with the arcpolygon, for example when it's shifted, and these arcs can be manipulated after the arcpolygon has been initialized.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:58\nmsgid \"Also both the arcs contained in an :class:`~.ArcPolygonFromArcs`, as well as the arcpolygon itself are drawn, which affects draw time in :class:`~.Create` for example. In most cases the arcs themselves don't need to be drawn, in which case they can be passed as invisible.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.ArcPolygonFromArcs:80\nmsgid \"The arcpolygon itself can also be hidden so that instead only the contained arcs are drawn. This can be used to easily debug arcs or to highlight them.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.ArcPolygonFromArcs.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.Circle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:2\nmsgid \"Circle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.Circle``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.Arc`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:1\nmsgid \"A circle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:0\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:0\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:0\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.surround:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:3\nmsgid \"The color of the shape.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:4\nmsgid \"Additional arguments to be passed to :class:`Arc`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle:7\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:9\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.surround:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:22:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1\nmsgid \"Returns a circle passing through the specified three points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:22:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:1\nmsgid \"Returns the position of a point on the circle.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:22:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.surround:1\nmsgid \"Modifies a circle so that it surrounds a given mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Circle.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.from_three_points:5\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:3\nmsgid \"The angle of the point along the circle in radians.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:5\nmsgid \"The location of the point along the circle's circumference.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.point_at_angle:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.surround:3\nmsgid \"The mobject that the circle will be surrounding.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Circle.surround:5\nmsgid \"Scales the circle with respect to the mobject. A `buffer_factor` < 1 makes the circle smaller than the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.CubicBezier.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:2\nmsgid \"CubicBezier\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.CubicBezier``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.CubicBezier:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.CubicBezier:2\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CubicBezier.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.CurvedArrow.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:2\nmsgid \"CurvedArrow\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.CurvedArrow``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.CurvedArrow:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.ArcBetweenPoints`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedArrow.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:2\nmsgid \"CurvedDoubleArrow\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.CurvedDoubleArrow``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.CurvedDoubleArrow:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.CurvedArrow`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.CurvedDoubleArrow.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.Dot.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:2\nmsgid \"Dot\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.Dot``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.Circle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:1\nmsgid \"A circle with a very small radius.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:3\nmsgid \"The location of the dot.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:4\nmsgid \"The radius of the dot.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:5\nmsgid \"The thickness of the outline of the dot.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:6\nmsgid \"The opacity of the dot's fill_colour\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:7\nmsgid \"The color of the dot.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:8\nmsgid \"Additional arguments to be passed to :class:`Circle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Dot:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Dot.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.Ellipse.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:2\nmsgid \"Ellipse\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.Ellipse``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.Circle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:1\nmsgid \"A circular shape; oval, circle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:3\nmsgid \"The horizontal width of the ellipse.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:4\nmsgid \"The vertical height of the ellipse.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:5\nmsgid \"Additional arguments to be passed to :class:`Circle`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Ellipse:8\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Ellipse.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.LabeledDot.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:2\nmsgid \"LabeledDot\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.LabeledDot``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.Dot`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:1\nmsgid \"A :class:`Dot` containing a label in its center.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:3\nmsgid \"The label of the :class:`Dot`. This is rendered as :class:`~.MathTex` by default (i.e., when passing a :class:`str`), but other classes representing rendered strings like :class:`~.Text` or :class:`~.Tex` can be passed as well.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:7\nmsgid \"The radius of the :class:`Dot`. If ``None`` (the default), the radius is calculated based on the size of the ``label``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.LabeledDot:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.LabeledDot.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.Sector.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:2\nmsgid \"Sector\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.Sector``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Sector:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.AnnularSector`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.Sector:2\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.Sector.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.TipableVMobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:2\nmsgid \"TipableVMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.arc.TipableVMobject``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:1\nmsgid \"Meant for shared functionality between Arc and Line. Functionality can be classified broadly into these groups:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:7\nmsgid \"Adding, Creating, Modifying tips\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:5\nmsgid \"add_tip calls create_tip, before pushing the new tip\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:6\nmsgid \"into the TipableVMobject's list of submobjects\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:7\nmsgid \"stylistic and positional configuration\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:11\nmsgid \"Checking for tips\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:11\nmsgid \"Boolean checks for whether the TipableVMobject has a tip\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:11\nmsgid \"and a starting tip\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:15\nmsgid \"Getters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:15\nmsgid \"Straightforward accessors, returning information pertaining\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject:15\nmsgid \"to the TipableVMobject instance's tip(s), its length etc\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.add_tip:1\nmsgid \"Adds a tip to the TipableVMobject instance, recognising that the endpoints might need to be switched if it's a 'starting tip' or not.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.create_tip:1\nmsgid \"Stylises the tip, positions it spatially, and returns the newly instantiated tip to the caller.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.get_end:1\nmsgid \"Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.get_start:1\nmsgid \"Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.get_tip:1\nmsgid \"Returns the TipableVMobject instance's (first) tip, otherwise throws an exception.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.get_tips:1\nmsgid \"Returns a VGroup (collection of VMobjects) containing the TipableVMObject instance's tips.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:36:<autosummary>:1\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.get_unpositioned_tip:1\nmsgid \"Returns a tip that has been stylistically configured, but has not yet been given a position in space.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.TipableVMobject.rst:38\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.add_tip:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.add_tip:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.add_tip:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc.TipableVMobject.add_tip:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.arc.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:2\nmsgid \"arc\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc:1\nmsgid \"Mobjects that are curved.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/arc.py:docstring of manim.mobject.geometry.arc:4\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:0\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\nmsgid \"A dot with bigger radius and bold stroke to annotate scenes.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:0\nmsgid \"param inner_radius\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\nmsgid \"The inside radius of the Annular Sector.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\nmsgid \"Region between two concentric :class:`Circles <.Circle>`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\nmsgid \"A circular arc.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\nmsgid \"Inherits from Arc and additionally takes 2 points between which the arc is spanned.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\nmsgid \"A generalized polygon allowing for points to be connected with arcs.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\nmsgid \"A circle.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:0\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\nmsgid \"A circle with a very small radius.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\nmsgid \"A circular shape; oval, circle.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.arc.rst:50:<autosummary>:1\nmsgid \"A :class:`Dot` containing a label in its center.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.boolean_ops.Difference.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:2\nmsgid \"Difference\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.boolean\\\\_ops.Difference``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.boolean_ops._BooleanOps`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:1\nmsgid \"Subtracts one :class:`~.VMobject` from another one.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:3\nmsgid \"The 1st :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:4\nmsgid \"The 2nd :class:`~.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Difference:7\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Difference.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.boolean_ops.Exclusion.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:2\nmsgid \"Exclusion\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.boolean\\\\_ops.Exclusion``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.boolean_ops._BooleanOps`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:1\nmsgid \"Find the XOR between two :class:`~.VMobject`. This creates a new :class:`~.VMobject` consisting of the region covered by exactly one of them.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:5\nmsgid \"The 1st :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:6\nmsgid \"The 2nd :class:`~.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Exclusion:9\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Exclusion.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.boolean_ops.Intersection.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:2\nmsgid \"Intersection\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.boolean\\\\_ops.Intersection``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.boolean_ops._BooleanOps`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:1\nmsgid \"Find the intersection of two :class:`~.VMobject` s. This keeps the parts covered by both :class:`~.VMobject` s.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:4\nmsgid \"The :class:`~.VMobject` to find the intersection.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:6\nmsgid \"If less the 2 :class:`~.VMobject` are passed.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Intersection:9\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Intersection.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.boolean_ops.Union.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:2\nmsgid \"Union\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.boolean\\\\_ops.Union``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.boolean_ops._BooleanOps`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:1\nmsgid \"Union of two or more :class:`~.VMobject` s. This returns the common region of the :class:`~VMobject` s.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:4\nmsgid \"The :class:`~.VMobject` s to find the union of.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:6\nmsgid \"If less than 2 :class:`~.VMobject` s are passed.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops.Union:9\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.Union.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.boolean_ops.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.rst:2\nmsgid \"boolean\\\\_ops\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/boolean_ops.py:docstring of manim.mobject.geometry.boolean_ops:1\nmsgid \"Boolean operations for two-dimensional mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.rst:26:<autosummary>:1\nmsgid \"Subtracts one :class:`~.VMobject` from another one.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.rst:26:<autosummary>:1\nmsgid \"Find the XOR between two :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.boolean_ops.rst:26:<autosummary>:1\nmsgid \"Find the intersection of two :class:`~.VMobject` s.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.line.Angle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Angle.rst:2\nmsgid \"Angle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Angle.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.line.Angle``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:1\nmsgid \"A circular arc or elbow-type mobject representing an angle of two lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:0\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:0\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:3\nmsgid \"The first line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:4\nmsgid \"The second line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:5\nmsgid \"The radius of the :class:`Arc`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:6\nmsgid \"A sequence of two :class:`int` numbers determining which of the 4 quadrants should be used. The first value indicates whether to anchor the arc on the first line closer to the end point (1) or start point (-1), and the second value functions similarly for the end (1) or start (-1) of the second line. Possibilities: (1,1), (-1,1), (1,-1), (-1,-1).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:12\nmsgid \"Toggles between the two possible angles defined by two points and an arc center. If set to False (default), the arc will always go counterclockwise from the point on line1 until the point on line2 is reached. If set to True, the angle will go clockwise from line1 to line2.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:15\nmsgid \"Allows for a :class:`Dot` in the arc. Mainly used as an convention to indicate a right angle. The dot can be customized in the next three parameters.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:18\nmsgid \"The radius of the :class:`Dot`. If not specified otherwise, this radius will be 1/10 of the arc radius.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:20\nmsgid \"Relative distance from the center to the arc: 0 puts the dot in the center and 1 on the arc itself.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:22\nmsgid \"The color of the :class:`Dot`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:24\nmsgid \"Produces an elbow-type mobject indicating a right angle, see :class:`RightAngle` for more information and a shorthand.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:27\nmsgid \"Further keyword arguments that are passed to the constructor of :class:`Arc` or :class:`Elbow`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:30\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:15\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_lines:7\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle:31\nmsgid \"The first example shows some right angles with a dot in the middle while the second example shows all 8 possible angles defined by two lines.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Angle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Angle.rst:22:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1\nmsgid \"The angle between the lines AB and BC.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Angle.rst:22:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_lines:1\nmsgid \"Get the lines forming an angle of the :class:`Angle` class.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Angle.rst:22:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:1\nmsgid \"Get the value of an angle of the :class:`Angle` class.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Angle.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:3\nmsgid \"This constructs the angle :math:`\\\\angle ABC`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:5\nmsgid \"The endpoint of the first angle leg\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:6\nmsgid \"The vertex of the angle\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:7\nmsgid \"The endpoint of the second angle leg\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:8\nmsgid \"Further keyword arguments are passed to :class:`.Angle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:0\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_lines:0\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:10\nmsgid \"Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8), Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED, other_angle=True),\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.from_three_points:0\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_lines:0\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_lines:3\nmsgid \"A :class:`~.VGroup` containing the lines that form the angle of the :class:`Angle` class.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:3\nmsgid \"A boolean to decide the unit (deg/rad) in which the value of the angle is returned.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Angle.get_value:5\nmsgid \"The value in degrees/radians of an angle of the :class:`Angle` class.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.line.Arrow.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:2\nmsgid \"Arrow\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.line.Arrow``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.line.Line`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:1\nmsgid \"An arrow.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:3\nmsgid \"Arguments to be passed to :class:`Line`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:5\nmsgid \"The thickness of the arrow. Influenced by :attr:`max_stroke_width_to_length_ratio`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:7\nmsgid \"The distance of the arrow from its start and end points.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:9\nmsgid \":attr:`tip_length` scales with the length of the arrow. Increasing this ratio raises the max value of :attr:`tip_length`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:11\nmsgid \":attr:`stroke_width` scales with the length of the arrow. Increasing this ratio ratios the max value of :attr:`stroke_width`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:13\nmsgid \"Additional arguments to be passed to :class:`Line`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:17\nmsgid \":class:`ArrowTip` :class:`CurvedArrow`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow:21\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:4\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_normal_vector:4\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.scale:8\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:23:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1\nmsgid \"Returns the default tip_length of the arrow.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:23:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_normal_vector:1\nmsgid \"Returns the normal of a vector.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:23:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.reset_normal_vector:1\nmsgid \"Resets the normal of a vector\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:23:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.scale:1\nmsgid \"Scale an arrow, but keep stroke width and arrow tip size fixed.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Arrow.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_default_tip_length:0\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Arrow.get_normal_vector:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.line.DashedLine.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:2\nmsgid \"DashedLine\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.line.DashedLine``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.line.Line`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:1\nmsgid \"A dashed :class:`Line`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:3\nmsgid \"Arguments to be passed to :class:`Line`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:5\nmsgid \"The length of each individual dash of the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:7\nmsgid \"The ratio of dash space to empty space. Range of 0-1.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:9\nmsgid \"Additional arguments to be passed to :class:`Line`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine:16\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:4\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_first_handle:4\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_last_handle:4\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_start:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:23:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1\nmsgid \"Returns the end point of the line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:23:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_first_handle:1\nmsgid \"Returns the point of the first handle.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:23:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_last_handle:1\nmsgid \"Returns the point of the last handle.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:23:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_start:1\nmsgid \"Returns the start point of the line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DashedLine.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DashedLine.get_end:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.line.DoubleArrow.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:2\nmsgid \"DoubleArrow\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.line.DoubleArrow``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.line.Arrow`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:1\nmsgid \"An arrow with tips on both ends.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:3\nmsgid \"Arguments to be passed to :class:`Arrow`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:5\nmsgid \"Additional arguments to be passed to :class:`Arrow`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:9\nmsgid \":class:`.~ArrowTip` :class:`.~CurvedDoubleArrow`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.DoubleArrow:13\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.DoubleArrow.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.line.Elbow.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:2\nmsgid \"Elbow\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.line.Elbow``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:1\nmsgid \"Two lines that create a right angle about each other: L-shape.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:3\nmsgid \"The length of the elbow's sides.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:5\nmsgid \"The rotation of the elbow.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:7\nmsgid \"Additional arguments to be passed to :class:`~.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Elbow:12\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Elbow.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.line.Line.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Line.rst:2\nmsgid \"Line\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Line.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.line.Line``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.arc.TipableVMobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Line.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Line.rst:31:<autosummary>:1\n#: ../../source/reference/manim.mobject.geometry.line.Line.rst:31:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Line.rst:31:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.get_projection:1\nmsgid \"Returns the projection of a point onto a line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Line.rst:31:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.put_start_and_end_on:1\nmsgid \"Sets starts and end coordinates of a line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Line.rst:33\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:3\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.generate_points:3\nmsgid \"Gets called upon creation. This is an empty method that can be implemented by subclasses.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.get_projection:0\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.put_start_and_end_on:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.get_projection:3\nmsgid \"The point to which the line is projected.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Line.get_projection:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.line.RightAngle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:2\nmsgid \"RightAngle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.line.RightAngle``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.line.Angle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:1\nmsgid \"An elbow-type mobject representing a right angle between two lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:3\nmsgid \"The first line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:4\nmsgid \"The second line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:5\nmsgid \"The length of the arms.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:6\nmsgid \"Further keyword arguments that are passed to the constructor of :class:`Angle`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.RightAngle:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.RightAngle.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.line.TangentLine.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:2\nmsgid \"TangentLine\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.line.TangentLine``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.line.Line`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:1\nmsgid \"Constructs a line tangent to a :class:`~.VMobject` at a specific point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:3\nmsgid \"The VMobject on which the tangent line is drawn.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:5\nmsgid \"How far along the shape that the line will be constructed. range: 0-1.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:7\nmsgid \"Length of the tangent line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:9\nmsgid \"The ``dx`` value\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:11\nmsgid \"Additional arguments to be passed to :class:`Line`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.TangentLine:18\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.TangentLine.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.line.Vector.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Vector.rst:2\nmsgid \"Vector\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Vector.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.line.Vector``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.line.Arrow`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:1\nmsgid \"A vector specialized for use in graphs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:0\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:3\nmsgid \"The direction of the arrow.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:5\nmsgid \"The distance of the vector from its endpoints.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:7\nmsgid \"Additional arguments to be passed to :class:`Arrow`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector:11\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:12\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Vector.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Vector.rst:20:<autosummary>:1\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1\nmsgid \"Creates a label based on the coordinates of the vector.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.Vector.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:3\nmsgid \"Whether or not to round the coordinates to integers.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:4\nmsgid \"The number of dimensions of the vector.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:5\nmsgid \"Sets the color of label, optional.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:6\nmsgid \"Additional arguments to be passed to :class:`~.Matrix`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:8\nmsgid \"The label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line.Vector.coordinate_label:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.line.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.line.rst:2\nmsgid \"line\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/line.py:docstring of manim.mobject.geometry.line:1\nmsgid \"Mobjects that are lines or variations of them.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.rst:36:<autosummary>:1\nmsgid \"A circular arc or elbow-type mobject representing an angle of two lines.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.rst:36:<autosummary>:1\nmsgid \"An arrow.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.rst:36:<autosummary>:1\nmsgid \"A dashed :class:`Line`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.rst:36:<autosummary>:1\nmsgid \"An arrow with tips on both ends.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.rst:36:<autosummary>:1\nmsgid \"Two lines that create a right angle about each other: L-shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.rst:36:<autosummary>:1\nmsgid \"An elbow-type mobject representing a right angle between two lines.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.line.rst:36:<autosummary>:1\nmsgid \"Constructs a line tangent to a :class:`~.VMobject` at a specific point.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Cutout.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:2\nmsgid \"Cutout\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.polygram.Cutout``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:1\nmsgid \"A shape with smaller cutouts.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:3\nmsgid \"The primary shape from which cutouts are made.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:5\nmsgid \"The smaller shapes which are to be cut out of the ``main_shape``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:7\nmsgid \"Further keyword arguments that are passed to the constructor of :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:11\nmsgid \"Technically, this class behaves similar to a symmetric difference: if parts of the ``mobjects`` are not located within the ``main_shape``, these parts will be added to the resulting :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Cutout:16\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Cutout.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Polygon.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:2\nmsgid \"Polygon\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.polygram.Polygon``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.Polygram`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:1\nmsgid \"A shape consisting of one closed loop of vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:3\nmsgid \"The vertices of the :class:`Polygon`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:4\nmsgid \"Forwarded to the parent constructor.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygon:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygon.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Polygram.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:2\nmsgid \"Polygram\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.polygram.Polygram``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:1\nmsgid \"A generalized :class:`Polygon`, allowing for disconnected sets of edges.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:0\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.round_corners:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:3\nmsgid \"The groups of vertices making up the :class:`Polygram`.  The first vertex in each group is repeated to close the shape. Each point must be 3-dimensional: ``[x,y,z]``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:3\nmsgid \"The groups of vertices making up the :class:`Polygram`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:5\nmsgid \"The first vertex in each group is repeated to close the shape. Each point must be 3-dimensional: ``[x,y,z]``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:7\nmsgid \"The color of the :class:`Polygram`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:8\nmsgid \"Forwarded to the parent constructor.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram:11\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:7\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertices:7\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.round_corners:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:22:<autosummary>:1\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1\nmsgid \"Gets the vertex groups of the :class:`Polygram`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:22:<autosummary>:1\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertices:1\nmsgid \"Gets the vertices of the :class:`Polygram`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:22:<autosummary>:1\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.round_corners:1\nmsgid \"Rounds off the corners of the :class:`Polygram`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Polygram.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:0\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertices:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:3\nmsgid \"The vertex groups of the :class:`Polygram`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertex_groups:0\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertices:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.get_vertices:3\nmsgid \"The vertices of the :class:`Polygram`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Polygram.round_corners:3\nmsgid \"The curvature of the corners of the :class:`Polygram`.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Rectangle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:2\nmsgid \"Rectangle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.polygram.Rectangle``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.Polygon`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:1\nmsgid \"A quadrilateral with two sets of parallel sides.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:3\nmsgid \"The color of the rectangle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:5\nmsgid \"The vertical height of the rectangle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:7\nmsgid \"The horizontal width of the rectangle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:9\nmsgid \"Space between vertical grid lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:11\nmsgid \"Space between horizontal grid lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:13\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:15\nmsgid \"No purpose.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:17\nmsgid \"Additional arguments to be passed to :class:`Polygon`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Rectangle:21\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Rectangle.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.RegularPolygon.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:2\nmsgid \"RegularPolygon\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.polygram.RegularPolygon``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.RegularPolygram`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:1\nmsgid \"An n-sided regular :class:`Polygon`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:3\nmsgid \"The number of sides of the :class:`RegularPolygon`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:4\nmsgid \"Forwarded to the parent constructor.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygon:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygon.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.RegularPolygram.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:2\nmsgid \"RegularPolygram\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.polygram.RegularPolygram``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.Polygram`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:1\nmsgid \"A :class:`Polygram` with regularly spaced vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:3\nmsgid \"The number of vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:4\nmsgid \"The density of the :class:`RegularPolygram`.  Can be thought of as how many vertices to hop to draw a line between them. Every ``density``-th vertex is connected.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:4\nmsgid \"The density of the :class:`RegularPolygram`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:6\nmsgid \"Can be thought of as how many vertices to hop to draw a line between them. Every ``density``-th vertex is connected.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:9\nmsgid \"The radius of the circle that the vertices are placed on.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:10\nmsgid \"The angle the vertices start at; the rotation of the :class:`RegularPolygram`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:12\nmsgid \"Forwarded to the parent constructor.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RegularPolygram:15\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RegularPolygram.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.RoundedRectangle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:2\nmsgid \"RoundedRectangle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.polygram.RoundedRectangle``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.Rectangle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:1\nmsgid \"A rectangle with rounded corners.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:3\nmsgid \"The curvature of the corners of the rectangle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:5\nmsgid \"Additional arguments to be passed to :class:`Rectangle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.RoundedRectangle:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.RoundedRectangle.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Square.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:2\nmsgid \"Square\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.polygram.Square``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.Rectangle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:1\nmsgid \"A rectangle with equal side lengths.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:3\nmsgid \"The length of the sides of the square.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:5\nmsgid \"Additional arguments to be passed to :class:`Rectangle`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Square:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Square.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Star.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:2\nmsgid \"Star\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.polygram.Star``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.Polygon`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:1\nmsgid \"A regular polygram without the intersecting lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:3\nmsgid \"How many points on the :class:`Star`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:4\nmsgid \"The radius of the circle that the outer vertices are placed on.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:5\nmsgid \"The radius of the circle that the inner vertices are placed on.  If unspecified, the inner radius will be calculated such that the edges of the :class:`Star` perfectly follow the edges of its :class:`RegularPolygram` counterpart.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:5\nmsgid \"The radius of the circle that the inner vertices are placed on.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:7\nmsgid \"If unspecified, the inner radius will be calculated such that the edges of the :class:`Star` perfectly follow the edges of its :class:`RegularPolygram` counterpart.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:11\nmsgid \"The density of the :class:`Star`. Only used if ``inner_radius`` is unspecified.  See :class:`RegularPolygram` for more information.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:11\nmsgid \"The density of the :class:`Star`. Only used if ``inner_radius`` is unspecified.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:14\nmsgid \"See :class:`RegularPolygram` for more information.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:15\nmsgid \"The angle the vertices start at; the rotation of the :class:`Star`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:17\nmsgid \"Forwardeds to the parent constructor.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:19\nmsgid \"If ``inner_radius`` is unspecified and ``density``     is not in the range ``[1, n/2)``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Star:22\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Star.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.Triangle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:2\nmsgid \"Triangle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.polygram.Triangle``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Triangle:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.RegularPolygon`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Triangle:1\nmsgid \"An equilateral triangle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Triangle:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Triangle:3\nmsgid \"Additional arguments to be passed to :class:`RegularPolygon`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram.Triangle:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.Triangle.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.polygram.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:2\nmsgid \"polygram\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/polygram.py:docstring of manim.mobject.geometry.polygram:1\nmsgid \"Mobjects that are simple geometric shapes.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:38:<autosummary>:1\nmsgid \"A shape with smaller cutouts.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:38:<autosummary>:1\nmsgid \"A shape consisting of one closed loop of vertices.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:38:<autosummary>:1\nmsgid \"A generalized :class:`Polygon`, allowing for disconnected sets of edges.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:38:<autosummary>:1\nmsgid \"A quadrilateral with two sets of parallel sides.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:38:<autosummary>:1\nmsgid \"An n-sided regular :class:`Polygon`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:38:<autosummary>:1\nmsgid \"A :class:`Polygram` with regularly spaced vertices.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:38:<autosummary>:1\nmsgid \"A rectangle with rounded corners.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:38:<autosummary>:1\nmsgid \"A rectangle with equal side lengths.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.polygram.rst:38:<autosummary>:1\nmsgid \"A regular polygram without the intersecting lines.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.rst:2\nmsgid \"geometry\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:1\nmsgid \"Various geometric Mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:4\nmsgid \"Modules\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:15:<autosummary>:1\nmsgid \"Mobjects that are curved.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:15:<autosummary>:1\nmsgid \"Boolean operations for two-dimensional mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:15:<autosummary>:1\nmsgid \"Mobjects that are lines or variations of them.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:15:<autosummary>:1\nmsgid \"Mobjects that are simple geometric shapes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/__init__.py:docstring of manim.mobject.geometry:15:<autosummary>:1\nmsgid \"Mobjects used to mark and annotate other mobjects.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:2\nmsgid \"BackgroundRectangle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.shape\\\\_matchers.BackgroundRectangle``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.shape_matchers.SurroundingRectangle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle:1\nmsgid \"A background rectangle. Its default color is the background color of the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle:5\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:22:<autosummary>:1\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1:<autosummary>:1\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:22:<autosummary>:1\nmsgid \"Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject passed as parameter with respect to the bounds.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.BackgroundRectangle.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.get_fill_color:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle:0\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:1\nmsgid \"Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject passed as parameter with respect to the bounds. Points here stand for control points of the bezier curves (anchors and handles)\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:4\nmsgid \"The vmobject that will serve as a model.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:6\nmsgid \"upper-bound.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:8\nmsgid \"lower-bound\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:11\nmsgid \"``self``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.BackgroundRectangle.pointwise_become_partial:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.shape_matchers.Cross.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:2\nmsgid \"Cross\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.shape\\\\_matchers.Cross``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:1\nmsgid \"Creates a cross.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:3\nmsgid \"The mobject linked to this instance. It fits the mobject when specified. Defaults to None.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:4\nmsgid \"Specifies the color of the cross lines. Defaults to RED.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:5\nmsgid \"Specifies the width of the cross lines. Defaults to 6.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:6\nmsgid \"Scales the cross to the provided units. Defaults to 1.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Cross:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Cross.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:2\nmsgid \"SurroundingRectangle\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.shape\\\\_matchers.SurroundingRectangle``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.SurroundingRectangle:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.RoundedRectangle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.SurroundingRectangle:1\nmsgid \"A rectangle surrounding a :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.SurroundingRectangle:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.SurroundingRectangle.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.shape_matchers.Underline.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:2\nmsgid \"Underline\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.shape\\\\_matchers.Underline``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Underline:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.line.Line`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Underline:1\nmsgid \"Creates an underline.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Underline:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Underline:3\nmsgid \"The underline.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers.Underline:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.Underline.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.shape_matchers.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.rst:2\nmsgid \"shape\\\\_matchers\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/shape_matchers.py:docstring of manim.mobject.geometry.shape_matchers:1\nmsgid \"Mobjects used to mark and annotate other mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.rst:26:<autosummary>:1\nmsgid \"A background rectangle.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.rst:26:<autosummary>:1\nmsgid \"Creates a cross.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.shape_matchers.rst:26:<autosummary>:1\nmsgid \"A rectangle surrounding a :class:`~.Mobject`\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:2\nmsgid \"ArrowCircleFilledTip\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.tips.ArrowCircleFilledTip``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowCircleFilledTip:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.tips.ArrowCircleTip`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowCircleFilledTip:1\nmsgid \"Circular arrow tip with filled tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37:<autosummary>:1\nmsgid \"The base point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37:<autosummary>:1\nmsgid \"The length of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37:<autosummary>:1\nmsgid \"The angle of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37:<autosummary>:1\nmsgid \"The tip point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleFilledTip.rst:37:<autosummary>:1\nmsgid \"The vector pointing from the base point to the tip point.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowCircleTip.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:2\nmsgid \"ArrowCircleTip\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.tips.ArrowCircleTip``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowCircleTip:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.tips.ArrowTip`, :py:class:`manim.mobject.geometry.arc.Circle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowCircleTip:1\nmsgid \"Circular arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37:<autosummary>:1\nmsgid \"The base point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37:<autosummary>:1\nmsgid \"The length of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37:<autosummary>:1\nmsgid \"The angle of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37:<autosummary>:1\nmsgid \"The tip point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowCircleTip.rst:37:<autosummary>:1\nmsgid \"The vector pointing from the base point to the tip point.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:2\nmsgid \"ArrowSquareFilledTip\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.tips.ArrowSquareFilledTip``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowSquareFilledTip:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.tips.ArrowSquareTip`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowSquareFilledTip:1\nmsgid \"Square arrow tip with filled tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37:<autosummary>:1\nmsgid \"The base point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37:<autosummary>:1\nmsgid \"The length of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37:<autosummary>:1\nmsgid \"The angle of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37:<autosummary>:1\nmsgid \"The tip point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareFilledTip.rst:37:<autosummary>:1\nmsgid \"The vector pointing from the base point to the tip point.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowSquareTip.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:2\nmsgid \"ArrowSquareTip\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.tips.ArrowSquareTip``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowSquareTip:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.tips.ArrowTip`, :py:class:`manim.mobject.geometry.polygram.Square`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowSquareTip:1\nmsgid \"Square arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37:<autosummary>:1\nmsgid \"The base point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37:<autosummary>:1\nmsgid \"The length of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37:<autosummary>:1\nmsgid \"The angle of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37:<autosummary>:1\nmsgid \"The tip point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowSquareTip.rst:37:<autosummary>:1\nmsgid \"The vector pointing from the base point to the tip point.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowTip.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTip.rst:2\nmsgid \"ArrowTip\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTip.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.tips.ArrowTip``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:1\nmsgid \"Base class for arrow tips.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:4\nmsgid \":class:`ArrowTriangleTip` :class:`ArrowTriangleFilledTip` :class:`ArrowCircleTip` :class:`ArrowCircleFilledTip` :class:`ArrowSquareTip` :class:`ArrowSquareFilledTip`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:12\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:6\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.length:4\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.tip_angle:4\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.tip_point:4\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.vector:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:13\nmsgid \"Cannot be used directly, only intended for inheritance::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:20\nmsgid \"Instead, use one of the pre-defined ones, or make a custom one like this:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:40\nmsgid \"Using a class inherited from :class:`ArrowTip` to get a non-filled tip is a shorthand to manually specifying the arrow tip style as follows::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip:46\nmsgid \"The following example illustrates the usage of all of the predefined arrow tips.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTip.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTip.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1:<autosummary>:1\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1\nmsgid \"The base point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1:<autosummary>:1\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.length:1\nmsgid \"The length of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1:<autosummary>:1\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.tip_angle:1\nmsgid \"The angle of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1:<autosummary>:1\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.tip_point:1\nmsgid \"The tip point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1:<autosummary>:1\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.vector:1\nmsgid \"The vector pointing from the base point to the tip point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTip.base:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:2\nmsgid \"ArrowTriangleFilledTip\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.tips.ArrowTriangleFilledTip``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTriangleFilledTip:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.tips.ArrowTriangleTip`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTriangleFilledTip:1\nmsgid \"Triangular arrow tip with filled tip.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTriangleFilledTip:3\nmsgid \"This is the default arrow tip shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37:<autosummary>:1\nmsgid \"The base point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37:<autosummary>:1\nmsgid \"The length of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37:<autosummary>:1\nmsgid \"The angle of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37:<autosummary>:1\nmsgid \"The tip point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleFilledTip.rst:37:<autosummary>:1\nmsgid \"The vector pointing from the base point to the tip point.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.tips.ArrowTriangleTip.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:2\nmsgid \"ArrowTriangleTip\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:4\nmsgid \"Qualified name: ``manim.mobject.geometry.tips.ArrowTriangleTip``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTriangleTip:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.tips.ArrowTip`, :py:class:`manim.mobject.geometry.polygram.Triangle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips.ArrowTriangleTip:1\nmsgid \"Triangular arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37:<autosummary>:1\nmsgid \"The base point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37:<autosummary>:1\nmsgid \"The length of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37:<autosummary>:1\nmsgid \"The angle of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37:<autosummary>:1\nmsgid \"The tip point of the arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.ArrowTriangleTip.rst:37:<autosummary>:1\nmsgid \"The vector pointing from the base point to the tip point.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.geometry.tips.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.rst:2\nmsgid \"tips\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/geometry/tips.py:docstring of manim.mobject.geometry.tips:1\nmsgid \"A collection of tip mobjects for use with :class:`~.TipableVMobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.rst:32:<autosummary>:1\nmsgid \"Circular arrow tip with filled tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.rst:32:<autosummary>:1\nmsgid \"Circular arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.rst:32:<autosummary>:1\nmsgid \"Square arrow tip with filled tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.rst:32:<autosummary>:1\nmsgid \"Square arrow tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.rst:32:<autosummary>:1\nmsgid \"Base class for arrow tips.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.geometry.tips.rst:32:<autosummary>:1\nmsgid \"Triangular arrow tip with filled tip.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graph.Graph.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graph.Graph.rst:2\nmsgid \"Graph\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graph.Graph.rst:4\nmsgid \"Qualified name: ``manim.mobject.graph.Graph``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:1\nmsgid \"An undirected graph (that is, a collection of vertices connected with edges).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:3\nmsgid \"Graphs can be instantiated by passing both a list of (distinct, hashable) vertex names, together with list of edges (as tuples of vertex names). See the examples below for details.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:9\nmsgid \"This implementation uses updaters to make the edges move with the vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.change_layout:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_vertices:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:12\nmsgid \"A list of vertices. Must be hashable elements.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:13\nmsgid \"A list of edges, specified as tuples ``(u, v)`` where both ``u`` and ``v`` are vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:15\nmsgid \"Controls whether or not vertices are labeled. If ``False`` (the default), the vertices are not labeled; if ``True`` they are labeled using their names (as specified in ``vertices``) via :class:`~.MathTex`. Alternatively, custom labels can be specified by passing a dictionary whose keys are the vertices, and whose values are the corresponding vertex labels (rendered via, e.g., :class:`~.Text` or :class:`~.Tex`).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:21\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:10\nmsgid \"Sets the fill color of the default labels generated when ``labels`` is set to ``True``. Has no effect for other values of ``labels``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:23\nmsgid \"Either one of ``\\\"spring\\\"`` (the default), ``\\\"circular\\\"``, ``\\\"kamada_kawai\\\"``, ``\\\"planar\\\"``, ``\\\"random\\\"``, ``\\\"shell\\\"``, ``\\\"spectral\\\"``, ``\\\"spiral\\\"``, ``\\\"tree\\\"``, and ``\\\"partite\\\"`` for automatic vertex positioning using ``networkx`` (see `their documentation <https://networkx.org/documentation/stable/reference/drawing.html#module-networkx.drawing.layout>`_ for more details), or a dictionary specifying a coordinate (value) for each vertex (key) for manual positioning.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:29\nmsgid \"Only for automatically generated layouts. A dictionary whose entries are passed as keyword arguments to the automatic layout algorithm specified via ``layout`` of``networkx``. The ``tree`` layout also accepts a special parameter ``vertex_spacing`` passed as a keyword argument inside the ``layout_config`` dictionary. Passing a tuple ``(space_x, space_y)`` as this argument overrides the value of ``layout_scale`` and ensures that vertices are arranged in a way such that the centers of siblings in the same layer are at least ``space_x`` units apart horizontally, and neighboring layers are spaced ``space_y`` units vertically.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:39\nmsgid \"The scale of automatically generated layouts: the vertices will be arranged such that the coordinates are located within the interval ``[-scale, scale]``. Some layouts accept a tuple ``(scale_x, scale_y)`` causing the first coordinate to be in the interval ``[-scale_x, scale_x]``, and the second in ``[-scale_y, scale_y]``. Default: 2.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:44\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:12\nmsgid \"The mobject class used for displaying vertices in the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:45\nmsgid \"Either a dictionary containing keyword arguments to be passed to the class specified via ``vertex_type``, or a dictionary whose keys are the vertices, and whose values are dictionaries containing keyword arguments for the mobject related to the corresponding vertex.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:49\nmsgid \"A dictionary whose keys are the vertices, and whose values are mobjects to be used as vertices. Passing vertices here overrides all other configuration options for a vertex.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:52\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:6\nmsgid \"The mobject class used for displaying edges in the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:53\nmsgid \"Either a dictionary containing keyword arguments to be passed to the class specified via ``edge_type``, or a dictionary whose keys are the edges, and whose values are dictionaries containing keyword arguments for the mobject related to the corresponding edge.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.change_layout:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:59\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.change_layout:7\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:7\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_vertices:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:60\nmsgid \"First, we create a small graph and demonstrate that the edges move together with the vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:78\nmsgid \"There are several automatic positioning algorithms to choose from:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:99\nmsgid \"Vertices can also be positioned manually:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:112\nmsgid \"The vertices in graphs can be labeled, and configurations for vertices and edges can be modified both by default and for specific vertices and edges.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:118\nmsgid \"In ``edge_config``, edges can be passed in both directions: if ``(u, v)`` is an edge in the graph, both ``(u, v)`` as well as ``(v, u)`` can be used as keys in the dictionary.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:138\nmsgid \"You can also lay out a partite graph on columns by specifying a list of the vertices on each side and choosing the partite layout.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:143\nmsgid \"All vertices in your graph which are not listed in any of the partitions are collected in their own partition and rendered in the rightmost column.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:159\nmsgid \"The representation of a linear artificial neural network is facilitated by the use of the partite layout and defining partitions for each layer.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:193\nmsgid \"The custom tree layout can be used to show the graph by distance from the root vertex. You must pass the root vertex of the tree.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph:219\nmsgid \"The following code sample illustrates the use of the ``vertex_spacing`` layout parameter specific to the ``\\\"tree\\\"`` layout. As mentioned above, setting ``vertex_spacing`` overrides the specified value for ``layout_scale``, and as such it is harder to control the size of the mobject. However, we can adjust the captured frame and zoom out by using a :class:`.MovingCameraScene`::\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graph.Graph.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graph.Graph.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1\nmsgid \"Add new edges to the graph.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graph.Graph.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:1\nmsgid \"Add a list of vertices to the graph.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graph.Graph.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.change_layout:1\nmsgid \"Change the layout of this graph.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graph.Graph.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:1\nmsgid \"Build a :class:`~.Graph` from a given ``networkx`` graph.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graph.Graph.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:1\nmsgid \"Remove several edges from the graph.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graph.Graph.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_vertices:1\nmsgid \"Remove several vertices from the graph.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graph.Graph.rst:27\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:3\nmsgid \"Edges (as tuples of vertex identifiers) to be added. If a non-existing vertex is passed, a new vertex with default settings will be created. Create new vertices yourself beforehand to customize them.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:7\nmsgid \"A dictionary either containing keyword arguments to be passed to the class specified via ``edge_type``, or a dictionary whose keys are the edge tuples, and whose values are dictionaries containing keyword arguments to be passed for the construction of the corresponding edge.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:12\nmsgid \"Any further keyword arguments are passed to :meth:`.add_vertices` which is used to create new vertices in the passed edges.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:0\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_edges:15\nmsgid \"A group containing all newly added vertices and edges.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:3\nmsgid \"Hashable vertex identifiers.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:4\nmsgid \"A dictionary specifying the coordinates where the new vertices should be added. If ``None``, all vertices are created at the center of the graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:6\nmsgid \"Controls whether or not the vertex is labeled. If ``False`` (the default), the vertex is not labeled; if ``True`` it is labeled using its names (as specified in ``vertex``) via :class:`~.MathTex`. Alternatively, any :class:`~.Mobject` can be passed to be used as the label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:13\nmsgid \"A dictionary containing keyword arguments to be passed to the class specified via ``vertex_type``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.add_vertices:15\nmsgid \"A dictionary whose keys are the vertex identifiers, and whose values are mobjects that should be used as vertices. Overrides all other vertex customization options.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.change_layout:3\nmsgid \"See the documentation of :class:`~.Graph` for details about the keyword arguments.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:3\nmsgid \"A ``networkx`` graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.from_networkx:4\nmsgid \"Keywords to be passed to the constructor of :class:`~.Graph`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:3\nmsgid \"Edges to be removed from the graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph.Graph.remove_edges:5\nmsgid \"A group containing all removed edges.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graph.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graph.rst:2\nmsgid \"graph\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graph.py:docstring of manim.mobject.graph:1\nmsgid \"Mobjects used to represent mathematical graphs (think graph theory, not plotting).\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graph.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.Axes.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:2\nmsgid \"Axes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.coordinate\\\\_systems.Axes``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`, :py:class:`manim.mobject.graphing.coordinate_systems.CoordinateSystem`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:1\nmsgid \"Creates a set of axes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:3\nmsgid \"The ``(x_min, x_max, x_step)`` values of the x-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:4\nmsgid \"The ``(y_min, y_max, y_step)`` values of the y-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:5\nmsgid \"The length of the x-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:6\nmsgid \"The length of the y-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:7\nmsgid \"Arguments to be passed to :class:`~.NumberLine` that influences both axes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:8\nmsgid \"Arguments to be passed to :class:`~.NumberLine` that influence the x-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:9\nmsgid \"Arguments to be passed to :class:`~.NumberLine` that influence the y-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:10\nmsgid \"Whether or not to include the tips on both axes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:11\nmsgid \"Additional arguments to be passed to :class:`CoordinateSystem` and :class:`~.VGroup`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes:14\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:16\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:21\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:23:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1\nmsgid \"Accepts coordinates from the axes and returns a point with respect to the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:23:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.get_axes:1\nmsgid \"Gets the axes.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:23:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:1\nmsgid \"Draws a line graph.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:23:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:1\nmsgid \"Accepts a point from the scene and returns its coordinates with respect to the axes.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.Axes.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:3\nmsgid \"The coordinates. Each coord is passed as a separate argument: ``ax.coords_to_point(1, 2, 3)``.  Also accepts a list of coordinates  ``ax.coords_to_point( [x_0, x_1, ...], [y_0, y_1, ...], ... )``  ``ax.coords_to_point( [[x_0, y_0, z_0], [x_1, y_1, z_1]] )``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:3\nmsgid \"The coordinates. Each coord is passed as a separate argument: ``ax.coords_to_point(1, 2, 3)``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:5\nmsgid \"Also accepts a list of coordinates\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:7\nmsgid \"``ax.coords_to_point( [x_0, x_1, ...], [y_0, y_1, ...], ... )``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:9\nmsgid \"``ax.coords_to_point( [[x_0, y_0, z_0], [x_1, y_1, z_1]] )``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.get_axes:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:11\nmsgid \"A point with respect to the scene's coordinate system. The shape of the array will be similar to the shape of the input.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.coords_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.get_axes:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.get_axes:3\nmsgid \"A pair of axes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:3\nmsgid \"The graph connects the vertices formed from zipping ``x_values``, ``y_values`` and ``z_values``. Also adds :class:`Dots <.Dot>` at the vertices if ``add_vertex_dots`` is set to ``True``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:7\nmsgid \"Iterable of values along the x-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:8\nmsgid \"Iterable of values along the y-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:9\nmsgid \"Iterable of values (zeros if z_values is None) along the z-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:10\nmsgid \"Color for the line graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:11\nmsgid \"Whether or not to add :class:`~.Dot` at each vertex.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:12\nmsgid \"Radius for the :class:`~.Dot` at each vertex.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:13\nmsgid \"Style arguments to be passed into :class:`~.Dot` at each vertex.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:14\nmsgid \"Additional arguments to be passed into :class:`~.VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.plot_line_graph:16\nmsgid \"A VDict containing both the line and dots (if specified). The line can be accessed with: ``line_graph[\\\"line_graph\\\"]``. The dots can be accessed with: ``line_graph[\\\"vertex_dots\\\"]``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.Axes.point_to_coords:3\nmsgid \"The point, i.e. ``RIGHT`` or ``[0, 1, 0]``. Also accepts a list of points as ``[RIGHT, [0, 1, 0]]``.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:2\nmsgid \"ComplexPlane\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.coordinate\\\\_systems.ComplexPlane``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane:1\nmsgid \"Bases: :py:class:`manim.mobject.graphing.coordinate_systems.NumberPlane`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane:1\nmsgid \"A :class:`~.NumberPlane` specialized for use with complex numbers.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1\nmsgid \"Adds the labels produced from :meth:`~.NumberPlane.get_coordinate_labels` to the plane.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:1\nmsgid \"Generates the :class:`~.DecimalNumber` mobjects for the coordinates of the plane.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.n2p:1\nmsgid \"Abbreviation for :meth:`number_to_point`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:1\nmsgid \"Accepts a float/complex number and returns the equivalent point on the plane.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.p2n:1\nmsgid \"Abbreviation for :meth:`point_to_number`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.point_to_number:1\nmsgid \"Accepts a point and returns a complex number equivalent to that point on the plane.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ComplexPlane.rst:27\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.n2p:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.p2n:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.point_to_number:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:3\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:3\nmsgid \"An iterable of floats/complex numbers. Floats are positioned along the x-axis, complex numbers along the y-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.add_coordinates:4\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:4\nmsgid \"Additional arguments to be passed to :meth:`~.NumberLine.get_number_mobject`, i.e. :class:`~.DecimalNumber`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.point_to_number:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:6\nmsgid \"A :class:`~.VGroup` containing the positioned label mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.get_coordinate_labels:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.n2p:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.p2n:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.point_to_number:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:3\nmsgid \"The number. Can be a float or a complex number.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.number_to_point:5\nmsgid \"The point on the plane.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ComplexPlane.point_to_number:3\nmsgid \"The point in manim's coordinate-system\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.CoordinateSystem.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.CoordinateSystem.rst:2\nmsgid \"CoordinateSystem\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.CoordinateSystem.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.coordinate\\\\_systems.CoordinateSystem``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem:1\nmsgid \"Abstract base class for Axes and NumberPlane.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem:4\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:7\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:12\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:17\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:16\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:17\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:16\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:10\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:14\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:22\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:21\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:10\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:12\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:12\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:12\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_coords:5\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:12\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:18\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:20\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:11\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:9\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:8\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:17\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:10\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.CoordinateSystem.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\nmsgid \"Adds labels to the axes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:1\nmsgid \"Returns the angle to the x-axis of the tangent to the plotted curve at a particular x-value.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.c2p:1\nmsgid \"Abbreviation for :meth:`coords_to_point`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:1\nmsgid \"Creates a labelled triangle marker with a vertical line from the x-axis to a curve at a given x-value.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:1\nmsgid \"Returns a :class:`~.Polygon` representing the area under the graph passed.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:1\nmsgid \"Defines labels for the x_axis and y_axis of the graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:1\nmsgid \"Creates a properly positioned label for the passed graph, with an optional dot.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:1\nmsgid \"A horizontal line from the y-axis to a given point in the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:1\nmsgid \"Returns a straight line from a given axis to a point in the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:1\nmsgid \"Generate both horizontal and vertical lines from the axis to a point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_origin:1\nmsgid \"Gets the origin of :class:`~.Axes`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:1\nmsgid \"Generates a :class:`~.VGroup` of the Riemann Rectangles for a given curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:2\nmsgid \"Creates two lines representing `dx` and `df`, the labels for `dx` and `df`, and\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:1\nmsgid \"A vertical line from the x-axis to a given point in the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:1\nmsgid \"Obtains multiple lines from the x-axis to the curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:1\nmsgid \"Generate an x-axis label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:1\nmsgid \"Generate a y-axis label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gc:1\nmsgid \"Alias for :meth:`input_to_graph_coords`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gp:1\nmsgid \"Alias for :meth:`input_to_graph_point`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_coords:1\nmsgid \"Returns a tuple of the axis relative coordinates of the point on the graph based on the x-value given.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:1\nmsgid \"Returns the coordinates of the point on a ``graph`` corresponding to an ``x`` value.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.p2c:1\nmsgid \"Abbreviation for :meth:`point_to_coords`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:1\nmsgid \"Generates a curve based on a function.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:1\nmsgid \"Plots an antiderivative graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:1\nmsgid \"Returns the curve of the derivative of the passed graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:1\nmsgid \"Creates the curves of an implicit function.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:1\nmsgid \"A parametric curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:1\nmsgid \"A polar graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:1\nmsgid \"Generates a surface based on a function.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:1\nmsgid \"Gets polar coordinates from a point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:1\nmsgid \"Gets a point from polar coordinates.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pr2pt:1\nmsgid \"Abbreviation for :meth:`polar_to_point`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pt2pr:1\nmsgid \"Abbreviation for :meth:`point_to_polar`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:1\nmsgid \"Returns the slope of the tangent to the plotted curve at a particular x-value.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:1\nmsgid \"Adds labels to the axes. Use ``Axes.coordinate_labels`` to access the coordinates after creation.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gc:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gp:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_coords:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pr2pt:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pt2pr:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:4\nmsgid \"The numbers to be added to the axes. Use ``None`` to represent an axis with default labels.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.add_coordinates:16\nmsgid \"You can also specifically control the position and value of the labels using a dict.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:4\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:4\nmsgid \"The x-value at which the tangent must touch the curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:5\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:5\nmsgid \"The :class:`~.ParametricFunction` for which to calculate the tangent.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:6\nmsgid \"The change in `x` used to determine the angle of the tangent to the curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_origin:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:8\nmsgid \"The angle of the tangent to the curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.angle_of_tangent:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_origin:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gc:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.i2gp:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_coords:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pr2pt:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.pt2pr:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.slope_of_tangent:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:4\nmsgid \"The position along the curve at which the label, line and triangle will be constructed.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:5\nmsgid \"The :class:`~.ParametricFunction` for which to construct the label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:6\nmsgid \"The label of the vertical line and triangle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:7\nmsgid \"The color of the label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:8\nmsgid \"The size of the triangle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:9\nmsgid \"The color of the triangle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:10\nmsgid \"The function used to construct the vertical line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:11\nmsgid \"The color of the vertical line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_T_label:13\nmsgid \"A :class:`~.VGroup` of the label, triangle and vertical line mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:3\nmsgid \"The graph/curve for which the area needs to be gotten.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:4\nmsgid \"The range of the minimum and maximum x-values of the area. ``x_range = [x_min, x_max]``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:5\nmsgid \"The color of the area. Creates a gradient if a list of colors is provided.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:6\nmsgid \"The opacity of the area.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:7\nmsgid \"If a secondary :attr:`graph` is specified, encloses the area between the two curves.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:8\nmsgid \"Additional parameters passed to :class:`~.Polygon`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:10\nmsgid \"The :class:`~.Polygon` representing the area.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_area:13\nmsgid \"When x_ranges do not match (either area x_range, graph's x_range or bounded_graph's x_range).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:3\nmsgid \"For increased control over the position of the labels, use :meth:`get_x_axis_label` and :meth:`get_y_axis_label`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:6\nmsgid \"The label for the x_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:7\nmsgid \"The label for the y_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:9\nmsgid \"A :class:`~.Vgroup` of the labels for the x_axis and y_axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_axis_labels:13\nmsgid \":class:`get_x_axis_label` :class:`get_y_axis_label`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:3\nmsgid \"The curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:4\nmsgid \"The label for the function's curve. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:5\nmsgid \"The x_value along the curve that positions the label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:6\nmsgid \"The cartesian position, relative to the curve that the label will be at --> ``LEFT``, ``RIGHT``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:7\nmsgid \"The distance between the curve and the label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:8\nmsgid \"The color of the label. Defaults to the color of the curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:9\nmsgid \"Whether to add a dot at the point on the graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:10\nmsgid \"Additional parameters to be passed to :class:`~.Dot`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_graph_label:12\nmsgid \"The positioned label and :class:`~.Dot`, if applicable.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:3\nmsgid \"The point to which the horizontal line will be drawn.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:4\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:4\nmsgid \"Additional parameters to be passed to :class:`get_line_from_axis_to_point`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_horizontal_line:6\nmsgid \"A horizontal line from the y-axis to the point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:3\nmsgid \"Specifies the axis from which to draw the line. `0 = x_axis`, `1 = y_axis`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:4\nmsgid \"The point to which the line will be drawn.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:5\nmsgid \"The function of the :class:`~.Line` mobject used to construct the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:6\nmsgid \"Optional arguments to passed to :attr:`line_func`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:7\nmsgid \"The color of the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:8\nmsgid \"The stroke width of the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:10\nmsgid \"The line from an axis to a point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_line_from_axis_to_point:14\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:10\nmsgid \":meth:`~.CoordinateSystem.get_vertical_line` :meth:`~.CoordinateSystem.get_horizontal_line`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:3\nmsgid \"A point on the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:4\nmsgid \"Additional parameters to be passed to :meth:`get_line_from_axis_to_point`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_lines_to_point:6\nmsgid \"A :class:`~.VGroup` of the horizontal and vertical lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_origin:3\nmsgid \"The center point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:3\nmsgid \"The graph whose area will be approximated by Riemann rectangles.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:4\nmsgid \"The minimum and maximum x-values of the rectangles. ``x_range = [x_min, x_max]``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:5\nmsgid \"The change in x-value that separates each rectangle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:6\nmsgid \"Can be any of ``\\\"left\\\"``, ``\\\"right\\\"`` or ``\\\"center\\\"``. Refers to where the sample point for the height of each Riemann Rectangle will be inside the segments of the partition.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:9\nmsgid \"The stroke_width of the border of the rectangles.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:10\nmsgid \"The color of the border of the rectangle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:11\nmsgid \"The opacity of the rectangles.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:12\nmsgid \"The colors of the rectangles. Creates a balanced gradient if multiple colors are passed.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:13\nmsgid \"Indicates negative area when the curve dips below the x-axis by inverting its color.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:14\nmsgid \"Sets the :attr:`stroke_color` to :attr:`fill_color`, blending the rectangles without clear separation.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:15\nmsgid \"If a secondary graph is specified, encloses the area between the two curves.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:16\nmsgid \"The factor by which the width of the rectangles is scaled.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_riemann_rectangles:18\nmsgid \"A :class:`~.VGroup` containing the Riemann Rectangles.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:2\nmsgid \"the secant to the curve at a particular x-value.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:4\nmsgid \"The x-value at which the secant intersects the graph for the first time.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:5\nmsgid \"The curve for which the secant will be found.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:6\nmsgid \"The change in `x` after which the secant exits.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:7\nmsgid \"The color of the line that indicates the change in `x`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:8\nmsgid \"The color of the line that indicates the change in `y`. Defaults to the color of :attr:`graph`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:9\nmsgid \"The label for the `dx` line. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:10\nmsgid \"The label for the `dy` line. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:11\nmsgid \"Whether to include the secant line in the graph, or just the df/dx lines and labels.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:13\nmsgid \"The color of the secant line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:14\nmsgid \"The length of the secant line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_secant_slope_group:16\nmsgid \"A group containing the elements: `dx_line`, `df_line`, and if applicable also :attr:`dx_label`, :attr:`df_label`, `secant_line`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:3\nmsgid \"The point to which the vertical line will be drawn.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_line:6\nmsgid \"A vertical line from the x-axis to the point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:3\nmsgid \"The graph along which the lines are placed.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:4\nmsgid \"A list containing the lower and and upper bounds of the lines: ``x_range = [x_min, x_max]``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:5\nmsgid \"The number of evenly spaced lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:6\nmsgid \"Additional arguments to be passed to :meth:`~.CoordinateSystem.get_vertical_line`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_vertical_lines_to_graph:8\nmsgid \"The :class:`~.VGroup` of the evenly spaced lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:3\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:3\nmsgid \"The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:4\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:4\nmsgid \"The edge of the x-axis to which the label will be added, by default ``UR``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:5\nmsgid \"Allows for further positioning of the label from an edge, by default ``UR``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:6\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:6\nmsgid \"The distance of the label from the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_x_axis_label:8\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:8\nmsgid \"The positioned label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.get_y_axis_label:5\nmsgid \"Allows for further positioning of the label from an edge, by default ``UR``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:3\nmsgid \"The x-value of a point on the ``graph``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:4\nmsgid \"The :class:`~.ParametricFunction` on which the point lies.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:6\nmsgid \"The coordinates of the point on the :attr:`graph` corresponding to the :attr:`x` value.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.input_to_graph_point:9\nmsgid \"When the target x is not in the range of the line graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:3\nmsgid \"The function used to construct the :class:`~.ParametricFunction`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:4\nmsgid \"The range of the curve along the axes. ``x_range = [x_min, x_max, x_step]``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:5\nmsgid \"Whether to pass in the generated t value array to the function. Only use this if your function supports it. Output should be a numpy array of shape ``[y_0, y_1, ...]``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:7\nmsgid \"Additional parameters to be passed to :class:`~.ParametricFunction`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:9\nmsgid \"The plotted curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot:13\nmsgid \"This method may not produce accurate graphs since Manim currently relies on interpolation between evenly-spaced samples of the curve, instead of intelligent plotting. See the example below for some solutions to this problem.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:3\nmsgid \"The graph for which the antiderivative will be found.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:4\nmsgid \"The y-value at which the graph intercepts the y-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:5\nmsgid \"The number of points to take the area under the graph.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:6\nmsgid \"Whether to use the vectorized version of the antiderivative. This means to pass in the generated t value array to the function. Only use this if your function supports it. Output should be a numpy array of shape ``[y_0, y_1, ...]``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:9\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:5\nmsgid \"Any valid keyword argument of :class:`~.ParametricFunction`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:11\nmsgid \"The curve of the antiderivative.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_antiderivative_graph:15\nmsgid \"This graph is plotted from the values of area under the reference graph. The result might not be ideal if the reference graph contains uncalculatable areas from x=0.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:3\nmsgid \"The graph for which the derivative will be found.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:4\nmsgid \"The color of the derivative curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_derivative_graph:7\nmsgid \"The curve of the derivative.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:3\nmsgid \"The function to graph, in the form of f(x, y) = 0.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:4\nmsgid \"The minimum depth of the function to calculate.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:5\nmsgid \"The maximum number of quads to use.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_implicit_curve:6\nmsgid \"Additional parameters to pass into :class:`ImplicitFunction`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:3\nmsgid \"A parametric function mapping a number to a point in the coordinate system.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:5\nmsgid \"Whether to pass in the generated t value array to the function. Only use this if your function supports it.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:6\nmsgid \"Any further keyword arguments are passed to :class:`.ParametricFunction`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_parametric_curve:9\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:3\nmsgid \"The function r of theta.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:4\nmsgid \"The range of theta as ``theta_range = [theta_min, theta_max, theta_step]``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_polar_graph:5\nmsgid \"Additional parameters passed to :class:`~.ParametricFunction`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:3\nmsgid \"The function used to construct the :class:`~.Surface`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:4\nmsgid \"The range of the ``u`` variable: ``(u_min, u_max)``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:5\nmsgid \"The range of the ``v`` variable: ``(v_min, v_max)``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:6\nmsgid \"Colors of the surface. Passing a list of colors will color the surface by z-value. Passing a list of tuples in the form ``(color, pivot)`` allows user-defined pivots where the color transitions.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:9\nmsgid \"Defines the axis on which the colorscale is applied (0 = x, 1 = y, 2 = z), default is z-axis (2).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:11\nmsgid \"Additional parameters to be passed to :class:`~.Surface`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot_surface:13\nmsgid \"The plotted surface.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:3\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:6\nmsgid \"The point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:5\nmsgid \"The coordinate radius (:math:`r`) and the coordinate azimuth (:math:`\\\\theta`).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.point_to_polar:6\nmsgid \"Tuple[:class:`float`, :class:`float`]\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:3\nmsgid \"The coordinate radius (:math:`r`).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.CoordinateSystem.polar_to_point:4\nmsgid \"The coordinate azimuth (:math:`\\\\theta`).\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:2\nmsgid \"NumberPlane\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.coordinate\\\\_systems.NumberPlane``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:1\nmsgid \"Bases: :py:class:`manim.mobject.graphing.coordinate_systems.Axes`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:1\nmsgid \"Creates a cartesian plane with background lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:3\nmsgid \"The ``[x_min, x_max, x_step]`` values of the plane in the horizontal direction.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:4\nmsgid \"The ``[y_min, y_max, y_step]`` values of the plane in the vertical direction.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:5\nmsgid \"The width of the plane.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:6\nmsgid \"The height of the plane.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:7\nmsgid \"Arguments that influence the construction of the background lines of the plane.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:8\nmsgid \"Similar to :attr:`background_line_style`, affects the construction of the scene's background lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:9\nmsgid \"Determines the number of boxes within the background lines: :code:`2` = 4 boxes, :code:`3` = 9 boxes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:10\nmsgid \"Currently non-functional.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:11\nmsgid \"Additional arguments to be passed to :class:`Axes`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:14\nmsgid \"If :attr:`x_length` or :attr:`y_length` are not defined, they are automatically calculated such that one unit on each axis is one Manim unit long.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.NumberPlane:18\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:34:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:34:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:34:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.NumberPlane.rst:34:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:2\nmsgid \"PolarPlane\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.coordinate\\\\_systems.PolarPlane``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:1\nmsgid \"Bases: :py:class:`manim.mobject.graphing.coordinate_systems.Axes`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:1\nmsgid \"Creates a polar plane with background lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:3\nmsgid \"The number of divisions in the azimuth (also known as the `angular coordinate` or `polar angle`). If ``None`` is specified then it will use the default specified by ``azimuth_units``:  - ``\\\"PI radians\\\"`` or ``\\\"TAU radians\\\"``: 20 - ``\\\"degrees\\\"``: 36 - ``\\\"gradians\\\"``: 40 - ``None``: 1  A non-integer value will result in a partial division at the end of the circle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:3\nmsgid \"The number of divisions in the azimuth (also known as the `angular coordinate` or `polar angle`). If ``None`` is specified then it will use the default specified by ``azimuth_units``:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:6\nmsgid \"``\\\"PI radians\\\"`` or ``\\\"TAU radians\\\"``: 20\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:7\nmsgid \"``\\\"degrees\\\"``: 36\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:8\nmsgid \"``\\\"gradians\\\"``: 40\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:9\nmsgid \"``None``: 1\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:11\nmsgid \"A non-integer value will result in a partial division at the end of the circle.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:12\nmsgid \"The diameter of the plane.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:13\nmsgid \"The distance between faded radius lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:14\nmsgid \"The maximum value of the radius.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:15\nmsgid \"Specifies a default labelling system for the azimuth. Choices are:  - ``\\\"PI radians\\\"``: Fractional labels in the interval :math:`\\\\left[0, 2\\\\pi\\\\right]` with :math:`\\\\pi` as a constant. - ``\\\"TAU radians\\\"``: Fractional labels in the interval :math:`\\\\left[0, \\\\tau\\\\right]` (where :math:`\\\\tau = 2\\\\pi`) with :math:`\\\\tau` as a constant. - ``\\\"degrees\\\"``: Decimal labels in the interval :math:`\\\\left[0, 360\\\\right]` with a degree (:math:`^{\\\\circ}`) symbol. - ``\\\"gradians\\\"``: Decimal labels in the interval :math:`\\\\left[0, 400\\\\right]` with a superscript \\\"g\\\" (:math:`^{g}`). - ``None``: Decimal labels in the interval :math:`\\\\left[0, 1\\\\right]`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:15\nmsgid \"Specifies a default labelling system for the azimuth. Choices are:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:17\nmsgid \"``\\\"PI radians\\\"``: Fractional labels in the interval :math:`\\\\left[0, 2\\\\pi\\\\right]` with :math:`\\\\pi` as a constant.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:18\nmsgid \"``\\\"TAU radians\\\"``: Fractional labels in the interval :math:`\\\\left[0, \\\\tau\\\\right]` (where :math:`\\\\tau = 2\\\\pi`) with :math:`\\\\tau` as a constant.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:19\nmsgid \"``\\\"degrees\\\"``: Decimal labels in the interval :math:`\\\\left[0, 360\\\\right]` with a degree (:math:`^{\\\\circ}`) symbol.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:20\nmsgid \"``\\\"gradians\\\"``: Decimal labels in the interval :math:`\\\\left[0, 400\\\\right]` with a superscript \\\"g\\\" (:math:`^{g}`).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:21\nmsgid \"``None``: Decimal labels in the interval :math:`\\\\left[0, 1\\\\right]`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:22\nmsgid \"If the ``azimuth_units`` choice has fractional labels, choose whether to combine the constant in a compact form :math:`\\\\tfrac{xu}{y}` as opposed to :math:`\\\\tfrac{x}{y}u`, where :math:`u` is the constant.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:25\nmsgid \"The angle offset of the azimuth, expressed in radians.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:26\nmsgid \"The direction of the azimuth.  - ``\\\"CW\\\"``: Clockwise. - ``\\\"CCW\\\"``: Anti-clockwise.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:26\nmsgid \"The direction of the azimuth.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:28\nmsgid \"``\\\"CW\\\"``: Clockwise.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:29\nmsgid \"``\\\"CCW\\\"``: Anti-clockwise.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:30\nmsgid \"The buffer for the azimuth labels.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:31\nmsgid \"The font size of the azimuth labels.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:32\nmsgid \"The axis config for the radius.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane:35\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1\nmsgid \"Adds the coordinates.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_axes:1\nmsgid \"Gets the axes.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:25:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:1\nmsgid \"Gets labels for the coordinates\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.PolarPlane.rst:27\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:3\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:3\nmsgid \"Iterable of values along the radius, by default None.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.add_coordinates:4\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:4\nmsgid \"Iterable of values along the azimuth, by default None.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_axes:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_axes:3\nmsgid \"A pair of axes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_axes:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.PolarPlane.get_coordinate_labels:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.rst:2\nmsgid \"ThreeDAxes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.coordinate\\\\_systems.ThreeDAxes``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:1\nmsgid \"Bases: :py:class:`manim.mobject.graphing.coordinate_systems.Axes`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:1\nmsgid \"A 3-dimensional set of axes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:0\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:3\nmsgid \"The ``[x_min, x_max, x_step]`` values of the x-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:4\nmsgid \"The ``[y_min, y_max, y_step]`` values of the y-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:5\nmsgid \"The ``[z_min, z_max, z_step]`` values of the z-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:6\nmsgid \"The length of the x-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:7\nmsgid \"The length of the y-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:8\nmsgid \"The length of the z-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:9\nmsgid \"Arguments to be passed to :class:`~.NumberLine` that influence the z-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:10\nmsgid \"The direction of the normal.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:11\nmsgid \"The number of pieces used to construct the axes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:12\nmsgid \"The direction of the light source.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:13\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:14\nmsgid \"Currently non-functional.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes:15\nmsgid \"Additional arguments to be passed to :class:`Axes`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.rst:20:<autosummary>:1\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1\nmsgid \"Generate a z-axis label.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.ThreeDAxes.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:3\nmsgid \"The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:4\nmsgid \"The edge of the x-axis to which the label will be added, by default ``UR``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:5\nmsgid \"Allows for further positioning of the label from an edge, by default ``UR``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:6\nmsgid \"The distance of the label from the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:7\nmsgid \"The angle at which to rotate the label, by default ``PI/2``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:8\nmsgid \"The axis about which to rotate the label, by default ``RIGHT``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:10\nmsgid \"The positioned label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems.ThreeDAxes.get_z_axis_label:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.coordinate_systems.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:2\nmsgid \"coordinate\\\\_systems\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/coordinate_systems.py:docstring of manim.mobject.graphing.coordinate_systems:1\nmsgid \"Mobjects that represent coordinate systems.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:30:<autosummary>:1\nmsgid \"Creates a set of axes.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:30:<autosummary>:1\nmsgid \"A :class:`~.NumberPlane` specialized for use with complex numbers.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:30:<autosummary>:1\nmsgid \"Abstract base class for Axes and NumberPlane.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:30:<autosummary>:1\nmsgid \"Creates a cartesian plane with background lines.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.coordinate_systems.rst:30:<autosummary>:1\nmsgid \"Creates a polar plane with background lines.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.functions.FunctionGraph.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:2\nmsgid \"FunctionGraph\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.functions.FunctionGraph``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.FunctionGraph:1\nmsgid \"Bases: :py:class:`manim.mobject.graphing.functions.ParametricFunction`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.FunctionGraph:1\nmsgid \"A :class:`ParametricFunction` that spans the length of the scene by default.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.FunctionGraph:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:34:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:34:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:34:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.FunctionGraph.rst:34:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.functions.ImplicitFunction.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:2\nmsgid \"ImplicitFunction\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.functions.ImplicitFunction``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:1\nmsgid \"An implicit function.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:3\nmsgid \"The implicit function in the form ``f(x, y) = 0``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:4\nmsgid \"The x min and max of the function.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:5\nmsgid \"The y min and max of the function.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:6\nmsgid \"The minimum depth of the function to calculate.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:7\nmsgid \"The maximum number of quads to use.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:8\nmsgid \"Whether or not to smoothen the curves.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:9\nmsgid \"Additional parameters to pass into :class:`VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:12\nmsgid \"A small ``min_depth`` :math:`d` means that some small details might be ignored if they don't cross an edge of one of the :math:`4^d` uniform quads.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:16\nmsgid \"The value of ``max_quads`` strongly corresponds to the quality of the curve, but a higher number of quads may take longer to render.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction:21\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:21:<autosummary>:1\n#: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:21:<autosummary>:1\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.ImplicitFunction.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ImplicitFunction.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.functions.ParametricFunction.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:2\nmsgid \"ParametricFunction\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.functions.ParametricFunction``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:1\nmsgid \"A parametric curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:3\nmsgid \"The function to be plotted in the form of ``(lambda x: x**2)``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:4\nmsgid \"Determines the length that the function spans. By default ``[0, 1]``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:5\nmsgid \"Scaling class applied to the points of the function. Default of :class:`~.LinearBase`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:6\nmsgid \"Whether to interpolate between the points of the function after they have been created. (Will have odd behaviour with a low number of points)\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:8\nmsgid \"Whether to pass in the generated t value array to the function as ``[t_0, t_1, ...]``. Only use this if your function supports it. Output should be a numpy array of shape ``[[x_0, x_1, ...], [y_0, y_1, ...], [z_0, z_1, ...]]`` but ``z`` can also be 0 if the Axes is 2D\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:12\nmsgid \"Values of t at which the function experiences discontinuity.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:13\nmsgid \"The left and right tolerance for the discontinuities.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:16\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction:46\nmsgid \"If your function has discontinuities, you'll have to specify the location of the discontinuities manually. See the following example for guidance.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:23:<autosummary>:1\n#: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:23:<autosummary>:1\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.ParametricFunction.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions.ParametricFunction.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.functions.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.rst:2\nmsgid \"functions\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/functions.py:docstring of manim.mobject.graphing.functions:1\nmsgid \"Mobjects representing function graphs.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.rst:24:<autosummary>:1\nmsgid \"A :class:`ParametricFunction` that spans the length of the scene by default.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.functions.rst:24:<autosummary>:1\nmsgid \"An implicit function.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.number_line.NumberLine.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:2\nmsgid \"NumberLine\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.number\\\\_line.NumberLine``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.line.Line`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:1\nmsgid \"Creates a number line with tick marks.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.n2p:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.p2n:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:3\nmsgid \"The ``[x_min, x_max, x_step]`` values to create the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:4\nmsgid \"The length of the number line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:5\nmsgid \"The distance between each tick of the line. Overwritten by :attr:`length`, if specified.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:6\nmsgid \"Whether to include ticks on the number line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:7\nmsgid \"The length of each tick mark.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:8\nmsgid \"An iterable of specific values with elongated ticks.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:9\nmsgid \"Influences how many times larger elongated ticks are than regular ticks (2 = 2x).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:10\nmsgid \"The angle (in radians) at which the line is rotated.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:11\nmsgid \"The thickness of the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:12\nmsgid \"Whether to add a tip to the end of the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:13\nmsgid \"The width of the tip.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:14\nmsgid \"The height of the tip.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:15\nmsgid \"Whether to add numbers to the tick marks. The number of decimal places is determined by the step size, this default can be overridden by ``decimal_number_config``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:17\nmsgid \"The way the ``x_range`` is value is scaled, i.e. :class:`~.LogBase` for a logarithmic numberline. Defaults to :class:`~.LinearBase`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:18\nmsgid \"The size of the label mobjects. Defaults to 36.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:19\nmsgid \"The specific position to which label mobjects are added on the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:20\nmsgid \"Determines the mobject class that will be used to construct the labels of the number line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:21\nmsgid \"The distance between the line and the label mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:22\nmsgid \"Arguments that can be passed to :class:`~.numbers.DecimalNumber` to influence number mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:23\nmsgid \"An explicit iterable of numbers to not be added to the number line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:24\nmsgid \"An explicit iterable of numbers to add to the number line\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:25\nmsgid \"Additional arguments to be passed to :class:`~.Line`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:29\nmsgid \"Number ranges that include both negative and positive values will be generated from the 0 point, and may not include a tick at the min / max values as the tick locations are dependent on the step size.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine:34\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:10\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:10\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36:<autosummary>:1\nmsgid \"Adds specifically positioned labels to the :class:`~.NumberLine` using a ``dict``.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36:<autosummary>:1\nmsgid \"Adds :class:`~.DecimalNumber` mobjects representing their position at each tick of the number line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36:<autosummary>:1\nmsgid \"Adds ticks to the number line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36:<autosummary>:1\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:1\nmsgid \"Generates a positioned :class:`~.DecimalNumber` mobject generated according to ``label_constructor``.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36:<autosummary>:1\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:1\nmsgid \"Generates a tick and positions it along the number line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36:<autosummary>:1\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick_range:1\nmsgid \"Generates the range of values on which labels are plotted based on the ``x_range`` attribute of the number line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36:<autosummary>:1\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.n2p:1\nmsgid \"Abbreviation for :meth:`~.NumberLine.number_to_point`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36:<autosummary>:1\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:1\nmsgid \"Accepts a value along the number line and returns a point with respect to the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36:<autosummary>:1\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.p2n:1\nmsgid \"Abbreviation for :meth:`~.NumberLine.point_to_number`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:36:<autosummary>:1\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:1\nmsgid \"Accepts a point with respect to the scene and returns a float along the number line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.NumberLine.rst:38\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:1\nmsgid \"Adds specifically positioned labels to the :class:`~.NumberLine` using a ``dict``. The labels can be accessed after creation via ``self.labels``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:4\nmsgid \"A dictionary consisting of the position along the number line and the mobject to be added: ``{1: Tex(\\\"Monday\\\"), 3: Tex(\\\"Tuesday\\\")}``. :attr:`label_constructor` will be used to construct the labels if the value is not a mobject (``str`` or ``float``).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:7\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:5\nmsgid \"Determines the direction at which the label is positioned next to the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:8\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:6\nmsgid \"The distance of the label from the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:9\nmsgid \"The font size of the mobject to be positioned.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:10\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:10\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:8\nmsgid \"The :class:`~.VMobject` class that will be used to construct the label. Defaults to the ``label_constructor`` attribute of the number line if not specified.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_labels:14\nmsgid \"If the label does not have a ``font_size`` attribute, an ``AttributeError`` is raised.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:1\nmsgid \"Adds :class:`~.DecimalNumber` mobjects representing their position at each tick of the number line. The numbers can be accessed after creation via ``self.numbers``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:5\nmsgid \"An iterable of the values used to position and create the labels. Defaults to the output produced by :meth:`~.NumberLine.get_tick_range`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:7\nmsgid \"A list of values to exclude from :attr:`x_values`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_numbers:8\nmsgid \"The font size of the labels. Defaults to the ``font_size`` attribute of the number line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.add_ticks:1\nmsgid \"Adds ticks to the number line. Ticks can be accessed after creation via ``self.ticks``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:4\nmsgid \"The x-value at which the mobject should be positioned.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:7\nmsgid \"The font size of the label mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick_range:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:12\nmsgid \"The positioned mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_number_mobject:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick_range:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.n2p:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.p2n:0\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:3\nmsgid \"The position of the tick.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:4\nmsgid \"The factor by which the tick is scaled.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick:6\nmsgid \"A positioned tick.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.get_tick_range:4\nmsgid \"A numpy array of floats represnting values along the number line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:4\nmsgid \"The value to be transformed into a coordinate. Or a list of values.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.number_to_point:6\nmsgid \"A point with respect to the scene's coordinate system. Or a list of points.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.NumberLine.point_to_number:4\nmsgid \"A sequence of values consisting of ``(x_coord, y_coord, z_coord)``.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.number_line.UnitInterval.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:2\nmsgid \"UnitInterval\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.number\\\\_line.UnitInterval``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line.UnitInterval:1\nmsgid \"Bases: :py:class:`manim.mobject.graphing.number_line.NumberLine`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.UnitInterval.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.number_line.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.rst:2\nmsgid \"number\\\\_line\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/number_line.py:docstring of manim.mobject.graphing.number_line:1\nmsgid \"Mobject representing a number line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.number_line.rst:22:<autosummary>:1\nmsgid \"Creates a number line with tick marks.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.rst:2\nmsgid \"graphing\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:1\nmsgid \"Coordinate systems and function graphing related mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:4\nmsgid \"Modules\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:14:<autosummary>:1\nmsgid \"Mobjects that represent coordinate systems.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:14:<autosummary>:1\nmsgid \"Mobjects representing function graphs.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:14:<autosummary>:1\nmsgid \"Mobject representing a number line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/__init__.py:docstring of manim.mobject.graphing:14:<autosummary>:1\nmsgid \"Mobjects representing objects from probability theory and statistics.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.probability.BarChart.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:2\nmsgid \"BarChart\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.probability.BarChart``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:1\nmsgid \"Bases: :py:class:`manim.mobject.graphing.coordinate_systems.Axes`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:1\nmsgid \"Creates a bar chart. Inherits from :class:`~.Axes`, so it shares its methods and attributes. Each axis inherits from :class:`~.NumberLine`, so pass in ``x_axis_config``/``y_axis_config`` to control their attributes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:0\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:0\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:5\nmsgid \"A sequence of values that determines the height of each bar. Accepts negative values.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:6\nmsgid \"A sequence of names for each bar. Does not have to match the length of ``values``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:7\nmsgid \"The y_axis range of values. If ``None``, the range will be calculated based on the min/max of ``values`` and the step will be calculated based on ``y_length``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:9\nmsgid \"The length of the x-axis. If ``None``, it is automatically calculated based on the number of values and the width of the screen.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:11\nmsgid \"The length of the y-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:12\nmsgid \"The color for the bars. Accepts a sequence of colors (can contain just one item). If the length of``bar_colors`` does not match that of ``values``, intermediate colors will be automatically determined.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:15\nmsgid \"The length of a bar. Must be between 0 and 1.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:16\nmsgid \"The fill opacity of the bars.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:17\nmsgid \"The stroke width of the bars.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart:20\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:8\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:10\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:21:<autosummary>:1\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1\nmsgid \"Updates the height of the bars of the chart.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:21:<autosummary>:1\nmsgid \"Annotates each bar with its corresponding value.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.BarChart.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:3\nmsgid \"The values that will be used to update the height of the bars. Does not have to match the number of bars.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.change_bar_values:5\nmsgid \"Whether to re-initalize the colors of the bars based on ``self.bar_colors``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:1\nmsgid \"Annotates each bar with its corresponding value. Use ``self.bar_labels`` to access the labels after creation.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:4\nmsgid \"The color of each label. By default ``None`` and is based on the parent's bar color.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:5\nmsgid \"The font size of each label.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.BarChart.get_bar_labels:6\nmsgid \"The distance from each label to its bar. By default 0.4.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.probability.SampleSpace.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:2\nmsgid \"SampleSpace\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.probability.SampleSpace``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.SampleSpace:1\nmsgid \"Bases: :py:class:`manim.mobject.geometry.polygram.Rectangle`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability.SampleSpace:2\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:34\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:45:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:45:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:45:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.SampleSpace.rst:45:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.probability.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.rst:2\nmsgid \"probability\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/probability.py:docstring of manim.mobject.graphing.probability:1\nmsgid \"Mobjects representing objects from probability theory and statistics.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.probability.rst:22:<autosummary>:1\nmsgid \"Creates a bar chart.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.scale.LinearBase.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.scale.LinearBase.rst:2\nmsgid \"LinearBase\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.scale.LinearBase.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.scale.LinearBase``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase:1\nmsgid \"Bases: :py:class:`manim.mobject.graphing.scale._ScaleBase`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase:1\nmsgid \"The default scaling class.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase:0\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:0\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.inverse_function:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase:3\nmsgid \"The slope of the linear function, by default 1.0\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.scale.LinearBase.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:1\nmsgid \"Multiplies the value by the scale factor.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:1:<autosummary>:1\nmsgid \"Inverse of function.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:3\nmsgid \"Value to be multiplied by the scale factor.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.function:0\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.inverse_function:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LinearBase.inverse_function:1\nmsgid \"Inverse of function. Divides the value by the scale factor.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.scale.LogBase.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.scale.LogBase.rst:2\nmsgid \"LogBase\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.scale.LogBase.rst:4\nmsgid \"Qualified name: ``manim.mobject.graphing.scale.LogBase``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:1\nmsgid \"Bases: :py:class:`manim.mobject.graphing.scale._ScaleBase`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:1\nmsgid \"Scale for logarithmic graphs/functions.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:0\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:0\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:0\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.inverse_function:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:3\nmsgid \"The base of the log, by default 10.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:4\nmsgid \"For use with :class:`~.Axes`: Whetherer or not to include ``LaTeX`` axis labels, by default True.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.scale.LogBase.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:1\nmsgid \"Scales the value to fit it to a logarithmic scale.``self.function(5)==10**5``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:1:<autosummary>:1\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:1\nmsgid \"Produces custom :class:`~.Integer` labels in the form of ``10^2``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:1:<autosummary>:1\nmsgid \"Inverse of ``function``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.function:0\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:0\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.inverse_function:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:3\nmsgid \"The iterable of values used to create the labels. Determines the exponent.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:4\nmsgid \"The number of decimal places to include in the exponent\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/graphing/scale.py:docstring of manim.mobject.graphing.scale.LogBase.get_custom_labels:5\nmsgid \"Additional arguments to be passed to :class:`~.Integer`.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.graphing.scale.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.graphing.scale.rst:2\nmsgid \"scale\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.scale.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.graphing.scale.rst:22:<autosummary>:1\nmsgid \"The default scaling class.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.logo.ManimBanner.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.logo.ManimBanner.rst:2\nmsgid \"ManimBanner\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.logo.ManimBanner.rst:4\nmsgid \"Qualified name: ``manim.mobject.logo.ManimBanner``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:1\nmsgid \"Convenience class representing Manim's banner.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:3\nmsgid \"Can be animated using custom methods.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:0\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:0\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:0\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:5\nmsgid \"If ``True`` (the default), the dark theme version of the logo (with light text font) will be rendered. Otherwise, if ``False``, the light theme version (with dark text font) is used.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner:10\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:23\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.logo.ManimBanner.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.logo.ManimBanner.rst:22:<autosummary>:1\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1\nmsgid \"The creation animation for Manim's logo.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.logo.ManimBanner.rst:22:<autosummary>:1\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:1\nmsgid \"An animation that expands Manim's logo into its banner.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.logo.ManimBanner.rst:22:<autosummary>:1\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:1\nmsgid \"Scale the banner by the specified scale factor.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.logo.ManimBanner.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:3\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:16\nmsgid \"The run time of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:0\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:0\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:5\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:19\nmsgid \"An animation to be used in a :meth:`.Scene.play` call.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.create:0\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:0\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:3\nmsgid \"The returned animation transforms the banner from its initial state (representing Manim's logo with just the icons) to its expanded state (showing the full name together with the icons).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:7\nmsgid \"See the class documentation for how to use this.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:11\nmsgid \"Before calling this method, the text \\\"anim\\\" is not a submobject of the banner object. After the expansion, it is added as a submobject so subsequent animations to the banner object apply to the text \\\"anim\\\" as well.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.expand:17\nmsgid \"The direction in which the logo is expanded.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:3\nmsgid \"The factor used for scaling the banner.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo.ManimBanner.scale:5\nmsgid \"The scaled banner.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.logo.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.logo.rst:2\nmsgid \"logo\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/logo.py:docstring of manim.mobject.logo:1\nmsgid \"Utilities for Manim's logo and banner.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.logo.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.matrix.DecimalMatrix.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:2\nmsgid \"DecimalMatrix\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:4\nmsgid \"Qualified name: ``manim.mobject.matrix.DecimalMatrix``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:1\nmsgid \"Bases: :py:class:`manim.mobject.matrix.Matrix`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:1\nmsgid \"A mobject that displays a matrix with decimal entries on the screen.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:17\nmsgid \"Will round/truncate the decimal places as per the provided config.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:19\nmsgid \"A numpy 2d array or list of lists\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:21\nmsgid \"Mobject to use, by default DecimalNumber\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.DecimalMatrix:23\nmsgid \"Config for the desired mobject, by default {\\\"num_decimal_places\\\": 1}\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.DecimalMatrix.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.matrix.IntegerMatrix.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:2\nmsgid \"IntegerMatrix\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:4\nmsgid \"Qualified name: ``manim.mobject.matrix.IntegerMatrix``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:1\nmsgid \"Bases: :py:class:`manim.mobject.matrix.Matrix`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:1\nmsgid \"A mobject that displays a matrix with integer entries on the screen.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:16\nmsgid \"Will round if there are decimal entries in the matrix.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:18\nmsgid \"A numpy 2d array or list of lists\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.IntegerMatrix:20\nmsgid \"Mobject to use, by default Integer\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.IntegerMatrix.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.matrix.Matrix.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:2\nmsgid \"Matrix\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:4\nmsgid \"Qualified name: ``manim.mobject.matrix.Matrix``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:1\nmsgid \"A mobject that displays a matrix on the screen.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:4\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:7\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:7\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_entries:7\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:7\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:10\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:10\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:5\nmsgid \"The first example shows a variety of uses of this module while the second example exlpains the use of the options `add_background_rectangles_to_entries` and `include_background_rectangle`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:56\nmsgid \"A numpy 2d array or list of lists.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:57\nmsgid \"Vertical distance between elements, by default 0.8.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:58\nmsgid \"Horizontal distance between elements, by default 1.3.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:59\nmsgid \"Distance of the brackets from the matrix, by default ``MED_SMALL_BUFF``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:60\nmsgid \"Height of the brackets, by default ``MED_SMALL_BUFF``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:61\nmsgid \"``True`` if should add backgraound rectangles to entries, by default ``False``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:62\nmsgid \"``True`` if should include background rectangle, by default ``False``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:63\nmsgid \"The mobject class used to construct the elements, by default :class:`~.MathTex`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:64\nmsgid \"Additional arguments to be passed to the constructor in ``element_to_mobject``, by default ``{}``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:66\nmsgid \"The corner to which elements are aligned, by default ``DR``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:67\nmsgid \"The left bracket type, by default ``\\\"[\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:68\nmsgid \"The right bracket type, by default ``\\\"]\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:69\nmsgid \"``True`` if should stretch the brackets to fit the height of matrix contents, by default ``True``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix:70\nmsgid \"Additional arguments to be passed to :class:`~.MathTex` when constructing the brackets.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:27:<autosummary>:1\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1\nmsgid \"Add a black background rectangle to the matrix, see above for an example.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:27:<autosummary>:1\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:1\nmsgid \"Return the bracket mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:27:<autosummary>:1\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:1\nmsgid \"Return columns of the matrix as VGroups.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:27:<autosummary>:1\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_entries:1\nmsgid \"Return the individual entries of the matrix.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:27:<autosummary>:1\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_mob_matrix:1\nmsgid \"Return the underlying mob matrix mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:27:<autosummary>:1\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:1\nmsgid \"Return rows of the matrix as VGroups.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:27:<autosummary>:1\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:1\nmsgid \"Set individual colors for each columns of the matrix.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:27:<autosummary>:1\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:1\nmsgid \"Set individual colors for each row of the matrix.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.Matrix.rst:29\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_entries:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_mob_matrix:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:4\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:6\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:6\nmsgid \"The current matrix object (self).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.add_background_to_entries:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_entries:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_mob_matrix:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:0\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_row_colors:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:3\nmsgid \"Each VGroup contains a bracket\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_brackets:4\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:4\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_mob_matrix:4\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:4\nmsgid \"List[:class:`~.VGroup`]\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_columns:3\nmsgid \"Each VGroup contains a column of the matrix.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_entries:3\nmsgid \"VGroup containing entries of the matrix.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_mob_matrix:3\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.get_rows:3\nmsgid \"Each VGroup contains a row of the matrix.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.Matrix.set_column_colors:3\nmsgid \"The list of colors; each color specified corresponds to a column.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.matrix.MobjectMatrix.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:2\nmsgid \"MobjectMatrix\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:4\nmsgid \"Qualified name: ``manim.mobject.matrix.MobjectMatrix``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:1\nmsgid \"Bases: :py:class:`manim.mobject.matrix.Matrix`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:1\nmsgid \"A mobject that displays a matrix of mobject entries on the screen.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:17\nmsgid \"A numpy 2d array or list of lists.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:18\nmsgid \"Vertical distance between elements, by default 0.8.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:19\nmsgid \"Horizontal distance between elements, by default 1.3.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:20\nmsgid \"Distance of the brackets from the matrix, by default ``MED_SMALL_BUFF``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:21\nmsgid \"Height of the brackets, by default ``MED_SMALL_BUFF``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:22\nmsgid \"``True`` if should add backgraound rectangles to entries, by default ``False``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:23\nmsgid \"``True`` if should include background rectangle, by default ``False``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:24\nmsgid \"The mobject class used to construct the elements, by default :class:`~.MathTex`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:25\nmsgid \"Additional arguments to be passed to the constructor in ``element_to_mobject``, by default ``{}``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:27\nmsgid \"The corner to which elements are aligned, by default ``DR``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:28\nmsgid \"The left bracket type, by default ``\\\"[\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:29\nmsgid \"The right bracket type, by default ``\\\"]\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:30\nmsgid \"``True`` if should stretch the brackets to fit the height of matrix contents, by default ``True``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.MobjectMatrix:31\nmsgid \"Additional arguments to be passed to :class:`~.MathTex` when constructing the brackets.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.MobjectMatrix.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.matrix.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.matrix.rst:2\nmsgid \"matrix\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix:1\nmsgid \"Mobjects representing matrices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix:4\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:16\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.rst:32:<autosummary>:1\nmsgid \"A mobject that displays a matrix with decimal entries on the screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.rst:32:<autosummary>:1\nmsgid \"A mobject that displays a matrix with integer entries on the screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.rst:32:<autosummary>:1\nmsgid \"A mobject that displays a matrix on the screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.rst:32:<autosummary>:1\nmsgid \"A mobject that displays a matrix of mobject entries on the screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.matrix.rst:35\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:1\nmsgid \"Helper function to create determinant.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:3\nmsgid \"The matrix whose determinant is to be created\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:5\nmsgid \"The value of the determinant of the matrix\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:7\nmsgid \"The background rectangle\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:9\nmsgid \"The scale of the text `det` w.r.t the matrix\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:12\nmsgid \"A VGroup containing the determinant\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/matrix.py:docstring of manim.mobject.matrix.get_det_text:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.mobject.Group.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.mobject.Group.rst:2\nmsgid \"Group\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Group.rst:4\nmsgid \"Qualified name: ``manim.mobject.mobject.Group``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Group:1\nmsgid \"Bases: :py:class:`manim.mobject.mobject.Mobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Group:1\nmsgid \"Groups together multiple :class:`Mobjects <.Mobject>`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Group:4\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Group:5\nmsgid \"When adding the same mobject more than once, repetitions are ignored. Use :meth:`.Mobject.copy` to create a separate copy which can then be added to the group.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Group.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Group.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Group.rst:28:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Group.rst:28:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Group.rst:28:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.mobject.Mobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:2\nmsgid \"Mobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:4\nmsgid \"Qualified name: ``manim.mobject.mobject.Mobject``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:1\nmsgid \"Mathematical Object: base class for objects that can be displayed on screen.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:3\nmsgid \"There is a compatibility layer that allows for getting and setting generic attributes with ``get_*`` and ``set_*`` methods. See :meth:`set` for more details.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:9\nmsgid \"The contained objects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:0\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:11\nmsgid \"List[:class:`Mobject`]\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject:15\nmsgid \"The points of the objects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:1\nmsgid \"Add mobjects as submobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:1\nmsgid \"Add an animation override.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:1\nmsgid \"Add a BackgroundRectangle as submobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:1\nmsgid \"Add all passed mobjects to the back of the submobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:1\nmsgid \"Add an update function to this mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_data:1\nmsgid \"Aligns the data of this mobject with another mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_on_border:1\nmsgid \"Direction just needs to be a vector pointing towards side or corner in the 2d plane.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_to:1\nmsgid \"Aligns mobject to another :class:`~.Mobject` in a certain direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:1\nmsgid \"Returns the function defining a specific animation override for this class.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\nmsgid \"Applies a complex function to a :class:`Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:1\nmsgid \"Apply a function to ``self`` and every submobject with points recursively.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange:1\nmsgid \"Sorts :class:`~.Mobject` next to each other on screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:1\nmsgid \"Arrange submobjects in a grid.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_submobjects:1\nmsgid \"Arrange the position of :attr:`submobjects` with a small buffer.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:1\nmsgid \"Edit points, colors and submobjects to be identical to another :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:1\nmsgid \"Remove every updater.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:1\nmsgid \"Create and return an identical copy of the :class:`Mobject` including all :attr:`submobjects`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.flip:1\nmsgid \"Flips/Mirrors an mobject about its center.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_bottom:1\nmsgid \"Get bottom coordinates of a box bounding the :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_center:1\nmsgid \"Get center coordinates\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_color:1\nmsgid \"Returns the color of the :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_coord:1\nmsgid \"Meant to generalize ``get_x``, ``get_y`` and ``get_z``\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_corner:1\nmsgid \"Get corner coordinates for certain direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\nmsgid \"Picture a box bounding the :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_edge_center:1\nmsgid \"Get edge coordinates for certain direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_end:1\nmsgid \"Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_left:1\nmsgid \"Get left coordinates of a box bounding the :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_midpoint:1\nmsgid \"Get coordinates of the middle of the path that forms the  :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_nadir:1\nmsgid \"Get nadir (opposite the zenith) coordinates of a box bounding a 3D :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\nmsgid \"The simplest :class:`~.Mobject` to be transformed to or from self.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_right:1\nmsgid \"Get right coordinates of a box bounding the :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_start:1\nmsgid \"Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_start_and_end:1\nmsgid \"Returns starting and ending point of a stroke as a ``tuple``.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:1\nmsgid \"Return all updaters using the ``dt`` parameter.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_top:1\nmsgid \"Get top coordinates of a box bounding the :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_updaters:1\nmsgid \"Return all updaters.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_x:1\nmsgid \"Returns x coordinate of the center of the :class:`~.Mobject` as ``float``\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_y:1\nmsgid \"Returns y coordinate of the center of the :class:`~.Mobject` as ``float``\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_z:1\nmsgid \"Returns z coordinate of the center of the :class:`~.Mobject` as ``float``\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_zenith:1\nmsgid \"Get zenith coordinates of a box bounding a 3D :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_no_points:1\nmsgid \"Check if :class:`~.Mobject` *does not* contains points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_points:1\nmsgid \"Check if :class:`~.Mobject` contains points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_time_based_updater:1\nmsgid \"Test if ``self`` has a time based updater.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.init_colors:1\nmsgid \"Initializes the colors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:1\nmsgid \"Inserts a mobject at a specific position into self.submobjects\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.interpolate:1\nmsgid \"Turns this :class:`~.Mobject` into an interpolation between ``mobject1`` and ``mobject2``.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.invert:1\nmsgid \"Inverts the list of :attr:`submobjects`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.length_over_dim:1\nmsgid \"Measure the length of an :class:`~.Mobject` in a certain direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_color:1\nmsgid \"Match the color with the color of another :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_coord:1\nmsgid \"Match the coordinates with the coordinates of another :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_depth:1\nmsgid \"Match the depth with the depth of another :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_dim_size:1\nmsgid \"Match the specified dimension with the dimension of another :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_height:1\nmsgid \"Match the height with the height of another :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_points:1\nmsgid \"Edit points, positions, and submobjects to be identical to another :class:`~.Mobject`, while keeping the style unchanged.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:1\nmsgid \"Match the updaters of the given mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_width:1\nmsgid \"Match the width with the width of another :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\nmsgid \"Match x coord.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\nmsgid \"Match y coord.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\nmsgid \"Match z coord.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.move_to:1\nmsgid \"Move center of the :class:`~.Mobject` to certain coordinate.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.next_to:1\nmsgid \"Move this :class:`~.Mobject` next to another's :class:`~.Mobject` or coordinate.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.null_point_align:1\nmsgid \"If a :class:`~.Mobject` with points is being aligned to one without, treat both as groups, and push the one with points into its own submobjects list.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:1\nmsgid \"Remove :attr:`submobjects`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:1\nmsgid \"Remove an updater.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.repeat:1\nmsgid \"This can make transition animations nicer\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.reset_points:1\nmsgid \"Sets :attr:`points` to be an empty array.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.restore:1\nmsgid \"Restores the state that was previously saved with :meth:`~.Mobject.save_state`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:1\nmsgid \"Enable updating from updaters and animations.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.rotate:1\nmsgid \"Rotates the :class:`~.Mobject` about a certain point.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.rotate_about_origin:1\nmsgid \"Rotates the :class:`~.Mobject` about the ORIGIN, which is at [0,0,0].\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.save_image:1\nmsgid \"Saves an image of only this :class:`Mobject` at its position to a png file.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\nmsgid \"Save the current state (position, color & size).\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:1\nmsgid \"Scale the size by a factor.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_depth:1\nmsgid \"Scales the :class:`~.Mobject` to fit a depth while keeping width/height proportional.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_height:1\nmsgid \"Scales the :class:`~.Mobject` to fit a height while keeping width/depth proportional.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_width:1\nmsgid \"Scales the :class:`~.Mobject` to fit a width while keeping height/depth proportional.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:1\nmsgid \"Sets attributes.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\nmsgid \"Condition is function which takes in one arguments, (x, y, z).\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_default:1\nmsgid \"Sets the default values of keyword arguments.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_x:1\nmsgid \"Set x value of the center of the :class:`~.Mobject` (``int`` or ``float``)\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_y:1\nmsgid \"Set y value of the center of the :class:`~.Mobject` (``int`` or ``float``)\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z:1\nmsgid \"Set z value of the center of the :class:`~.Mobject` (``int`` or ``float``)\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:1\nmsgid \"Sets the :class:`~.Mobject`'s :attr:`z_index` to the value specified in `z_index_value`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index_by_z_coordinate:1\nmsgid \"Sets the :class:`~.Mobject`'s z coordinate to the value of :attr:`z_index`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:1\nmsgid \"Shift by the given vectors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shuffle:1\nmsgid \"Shuffles the list of :attr:`submobjects`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shuffle_submobjects:1\nmsgid \"Shuffles the order of :attr:`submobjects`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.sort:1\nmsgid \"Sorts the list of :attr:`submobjects` by a function defined by ``submob_func``.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.sort_submobjects:1\nmsgid \"Sort the :attr:`submobjects`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_depth:1\nmsgid \"Stretches the :class:`~.Mobject` to fit a depth, not keeping width/height proportional.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_height:1\nmsgid \"Stretches the :class:`~.Mobject` to fit a height, not keeping width/depth proportional.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_width:1\nmsgid \"Stretches the :class:`~.Mobject` to fit a width, not keeping height/depth proportional.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:1\nmsgid \"Disable updating from updaters and animations.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:175:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:1\nmsgid \"Apply all updaters.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.Mobject.rst:177\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:1:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:1:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.depth:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:1:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.height:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:1:<autosummary>:1\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.width:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:3\nmsgid \"The mobjects are added to :attr:`submobjects`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:5\nmsgid \"Subclasses of mobject may implement ``+`` and ``+=`` dunder methods.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_data:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_to:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.invert:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_color:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_coord:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_depth:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_dim_size:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_height:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_points:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_width:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_x:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_y:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_z:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.null_point_align:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.repeat:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.rotate:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_color:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_default:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:7\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:6\nmsgid \"The mobjects to add.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_updaters:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_time_based_updater:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.null_point_align:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_height:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_width:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index_by_z_coordinate:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_height:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_width:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:9\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:11\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:8\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:17\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:6\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:20\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:5\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:5\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.null_point_align:6\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:9\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:7\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:5\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:11\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_height:3\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_width:3\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:33\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:6\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_height:3\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_width:3\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:6\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:9\nmsgid \"``self``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.depth:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_bottom:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_center:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_corner:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_edge_center:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_left:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_midpoint:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_nadir:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_right:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_top:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_updaters:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_x:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_y:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_z:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_zenith:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_no_points:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_points:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_time_based_updater:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.height:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.null_point_align:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_height:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_width:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index_by_z_coordinate:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_height:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_width:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.width:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:0\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:12\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:18\nmsgid \"When a mobject tries to add itself.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:13\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:19\nmsgid \"When trying to add an object that is not an instance of :class:`Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:16\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:22\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:27\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:17\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:23\nmsgid \"A mobject cannot contain itself, and it cannot contain a submobject more than once.  If the parent mobject is displayed, the newly-added submobjects will also be displayed (i.e. they are automatically added to the parent Scene).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:25\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:21\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:46\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange:4\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:36\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_submobjects:4\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:16\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.flip:4\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_midpoint:4\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.height:6\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.interpolate:5\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.invert:6\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_points:5\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.next_to:4\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:15\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_height:7\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale_to_fit_width:7\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:37\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_default:12\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:10\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shuffle_submobjects:4\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_height:7\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.stretch_to_fit_width:7\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.width:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:32\nmsgid \"Duplicates are not added again::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:38\nmsgid \"Adding an object to itself raises an error::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add:45\nmsgid \"A given mobject cannot be added as a submobject twice to some parent::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:3\nmsgid \"This does not apply to subclasses.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:5\nmsgid \"The animation type to be overridden\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:6\nmsgid \"The function returning an animation replacing the default animation. It gets passed the parameters given to the animnation constructor.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_animation_override:9\nmsgid \"If the overridden animation was already overridden.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:3\nmsgid \"The BackgroundRectangle is added behind other submobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:5\nmsgid \"This can be used to increase the mobjects visibility in front of a noisy background.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:7\nmsgid \"The color of the BackgroundRectangle\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:8\nmsgid \"The opacity of the BackgroundRectangle\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_background_rectangle:9\nmsgid \"Additional keyword arguments passed to the BackgroundRectangle constructor\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:3\nmsgid \"If :attr:`submobjects` already contains the given mobjects, they just get moved to the back instead.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_to_back:13\nmsgid \"Technically, this is done by adding (or moving) the mobjects to the head of :attr:`submobjects`. The head of this list is rendered first, which places the corresponding mobjects behind the subsequent list members.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:3\nmsgid \"Update functions, or updaters in short, are functions that are applied to the Mobject in every frame.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:6\nmsgid \"The update function to be added. Whenever :meth:`update` is called, this update function gets called using ``self`` as the first parameter. The updater can have a second parameter ``dt``. If it uses this parameter, it gets called using a second value ``dt``, usually representing the time in seconds since the last call of :meth:`update`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:12\nmsgid \"The index at which the new updater should be added in ``self.updaters``. In case ``index`` is ``None`` the updater will be added at the end.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.add_updater:14\nmsgid \"Whether or not to call the updater initially. If ``True``, the updater will be called using ``dt=0``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_data:3\nmsgid \"Afterwards, the two mobjects will have the same number of submobjects (see :meth:`.align_submobjects`), the same parent structure (see :meth:`.null_point_align`). If ``skip_point_alignment`` is false, they will also have the same number of points (see :meth:`.align_points`).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_data:8\nmsgid \"The other mobject this mobject should be aligned to.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_data:9\nmsgid \"Controls whether or not the computationally expensive point alignment is skipped (default: False).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_to:3\nmsgid \"Examples: mob1.align_to(mob2, UP) moves mob1 vertically so that its top edge lines ups with mob2's top edge.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.align_to:7\nmsgid \"mob1.align_to(mob2, alignment_vect = RIGHT) moves mob1 horizontally so that it's center is directly above/below the center of mob2\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:3\nmsgid \"Any method called on :code:`animate` is converted to an animation of applying that method on the mobject itself.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:6\nmsgid \"For example, :code:`square.set_fill(WHITE)` sets the fill color of a square, while :code:`square.animate.set_fill(WHITE)` animates this action.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:9\nmsgid \"Multiple methods can be put in a single animation once via chaining:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:17\nmsgid \"Passing multiple animations for the same :class:`Mobject` in one call to :meth:`~.Scene.play` is discouraged and will most likely not work properly. Instead of writing an animation like\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:25\nmsgid \"make use of method chaining.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:27\nmsgid \"Keyword arguments that can be passed to :meth:`.Scene.play` can be passed directly after accessing ``.animate``, like so::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:32\nmsgid \"This is especially useful when animating simultaneous ``.animate`` calls that you want to behave differently::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:89\nmsgid \"``.animate``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animate:85\nmsgid \"will interpolate the :class:`~.Mobject` between its points prior to ``.animate`` and its points after applying ``.animate`` to it. This may result in unexpected behavior when attempting to interpolate along paths, or rotations. If you want animations to consider the points between, consider using :class:`~.ValueTracker` with updaters instead.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:3\nmsgid \"The animation class for which the override function should be returned.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.animation_override_for:5\nmsgid \"The function returning the override animation or ``None`` if no such animation override is defined.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_complex_function:1\nmsgid \"Applies a complex function to a :class:`Mobject`. The x and y coordinates correspond to the real and imaginary parts respectively.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_complex_function:5\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.apply_to_family:3\nmsgid \"The function to apply to each mobject. ``func`` gets passed the respective (sub)mobject as parameter.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:3\nmsgid \"The number of rows in the grid.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:4\nmsgid \"The number of columns in the grid.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:5\nmsgid \"The gap between grid cells. To specify a different buffer in the horizontal and vertical directions, a tuple of two values can be given - ``(row, col)``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:7\nmsgid \"The way each submobject is aligned in its grid cell.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:8\nmsgid \"The vertical alignment for each row (top to bottom). Accepts the following characters: ``\\\"u\\\"`` - up, ``\\\"c\\\"`` - center, ``\\\"d\\\"`` - down.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:10\nmsgid \"The horizontal alignment for each column (left to right). Accepts the following characters ``\\\"l\\\"`` - left, ``\\\"c\\\"`` - center, ``\\\"r\\\"`` - right.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:12\nmsgid \"Defines a list of heights for certain rows (top to bottom). If the list contains ``None``, the corresponding row will fit its height automatically based on the highest element in that row.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:15\nmsgid \"Defines a list of widths for certain columns (left to right). If the list contains ``None``, the corresponding column will fit its width automatically based on the widest element in that column.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:17\nmsgid \"The order in which submobjects fill the grid. Can be one of the following values: \\\"rd\\\", \\\"dr\\\", \\\"ld\\\", \\\"dl\\\", \\\"ru\\\", \\\"ur\\\", \\\"lu\\\", \\\"ul\\\". (\\\"rd\\\" -> fill rightwards then downwards)\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:23\nmsgid \"If ``rows`` and ``cols`` are too small to fit all submobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:24\nmsgid \"If :code:`cols`, :code:`col_alignments` and :code:`col_widths` or :code:`rows`,     :code:`row_alignments` and :code:`row_heights` have mismatching sizes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:28\nmsgid \"If only one of ``cols`` and ``rows`` is set implicitly, the other one will be chosen big enough to fit all submobjects. If neither is set, they will be chosen to be about the same, tending towards ``cols`` > ``rows`` (simply because videos are wider than they are high).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.arrange_in_grid:32\nmsgid \"If both ``cell_alignment`` and ``row_alignments`` / ``col_alignments`` are defined, the latter has higher priority.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:6\nmsgid \"If both match_height and match_width are ``True`` then the transformed :class:`~.Mobject` will match the height first and then the width\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:9\nmsgid \"If ``True``, then the transformed :class:`~.Mobject` will match the height of the original\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:10\nmsgid \"If ``True``, then the transformed :class:`~.Mobject` will match the width of the original\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:11\nmsgid \"If ``True``, then the transformed :class:`~.Mobject` will match the depth of the original\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:12\nmsgid \"If ``True``, then the transformed :class:`~.Mobject` will match the center of the original\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.become:13\nmsgid \"If ``True``, then the transformed :class:`~.Mobject` will stretch to fit the proportions of the original\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.clear_updaters:3\nmsgid \"Whether to recursively call ``clear_updaters`` on all submobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:4\nmsgid \"The copy.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.copy:7\nmsgid \"The clone is initially not visible in the Scene, even if the original was.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.generate_points:3\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.init_colors:3\nmsgid \"Gets called upon creation. This is an empty method that can be implemented by subclasses.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_critical_point:1\nmsgid \"Picture a box bounding the :class:`~.Mobject`.  Such a box has 9 'critical points': 4 corners, 4 edge center, the center. This returns one of them, along the given direction.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_point_mobject:1\nmsgid \"The simplest :class:`~.Mobject` to be transformed to or from self. Should by a point of the appropriate type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:3\nmsgid \"The updaters use this parameter as the input for difference in time.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:5\nmsgid \"The list of time based updaters.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_time_based_updaters:6\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_updaters:4\nmsgid \"List[:class:`Callable`]\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.get_updaters:3\nmsgid \"The list of updaters.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_time_based_updater:3\nmsgid \"**class** -- ``True`` if at least one updater uses the ``dt`` parameter, ``False`` otherwise.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.has_time_based_updater:5\nmsgid \"`bool`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:3\nmsgid \"Effectively just calls  ``self.submobjects.insert(index, mobject)``, where ``self.submobjects`` is a list.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:6\nmsgid \"Highly adapted from ``Mobject.add``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:8\nmsgid \"The index at which\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.insert:9\nmsgid \"The mobject to be inserted.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.invert:3\nmsgid \"If ``True``, all submobject lists of this mobject's family are inverted.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:3\nmsgid \"The mobject whose updaters get matched.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_updaters:10\nmsgid \"All updaters from submobjects are removed, but only updaters of the given mobject are matched, not those of it's submobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_x:1\nmsgid \"Match x coord. to the x coord. of another :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_y:1\nmsgid \"Match y coord. to the x coord. of another :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.match_z:1\nmsgid \"Match z coord. to the x coord. of another :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:3\nmsgid \"The mobjects are removed from :attr:`submobjects`, if they exist.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:5\nmsgid \"Subclasses of mobject may implement ``-`` and ``-=`` dunder methods.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove:7\nmsgid \"The mobjects to remove.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:3\nmsgid \"If the same updater is applied multiple times, every instance gets removed.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.remove_updater:5\nmsgid \"The update function to be removed.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.resume_updating:3\nmsgid \"Whether to recursively enable updating on all submobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.save_state:1\nmsgid \"Save the current state (position, color & size). Can be restored with :meth:`~.Mobject.restore`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:3\nmsgid \"Default behavior is to scale about the center of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:5\nmsgid \"The scaling factor :math:`\\\\alpha`. If :math:`0 < |\\\\alpha| < 1`, the mobject will shrink, and for :math:`|\\\\alpha| > 1` it will grow. Furthermore, if :math:`\\\\alpha < 0`, the mobject is also flipped.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.scale:8\nmsgid \"Additional keyword arguments passed to :meth:`apply_points_function_about_point`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:3\nmsgid \"I.e. ``my_mobject.set(foo=1)`` applies ``my_mobject.foo = 1``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:5\nmsgid \"This is a convenience to be used along with :attr:`animate` to animate setting attributes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:8\nmsgid \"In addition to this method, there is a compatibility layer that allows ``get_*`` and ``set_*`` methods to get and set generic attributes. For instance::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:20\nmsgid \"This compatibility layer does not interfere with any ``get_*`` or ``set_*`` methods that are explicitly defined.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:26\nmsgid \"This compatibility layer is for backwards compatibility and is not guaranteed to stay around. Where applicable, please prefer getting/setting attributes normally or with the :meth:`set` method.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set:31\nmsgid \"The attributes and corresponding values to set.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_color:1\nmsgid \"Condition is function which takes in one arguments, (x, y, z). Here it just recurses to submobjects, but in subclasses this should be further implemented based on the the inner workings of color\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_default:3\nmsgid \"If this method is called without any additional keyword arguments, the original default values of the initialization method of this class are restored.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_default:7\nmsgid \"Passing any keyword argument will update the default values of the keyword arguments of the initialization function of this class.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:3\nmsgid \"The new value of :attr:`z_index` set.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:4\nmsgid \"If ``True``, the :attr:`z_index` value of all submobjects is also set.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index:6\nmsgid \"The Mobject itself, after :attr:`z_index` is set. For chaining purposes. (Returns `self`.)\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.set_z_index_by_z_coordinate:3\nmsgid \"The Mobject itself, after :attr:`z_index` is set. (Returns `self`.)\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.shift:3\nmsgid \"Vectors to shift by. If multiple vectors are given, they are added together.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.suspend_updating:4\nmsgid \"Whether to recursively suspend updating on all submobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:3\nmsgid \"Does nothing if updating is suspended.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:5\nmsgid \"The parameter ``dt`` to pass to the update functions. Usually this is the time in seconds since the last call of ``update``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.Mobject.update:7\nmsgid \"Whether to recursively update all submobjects.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.mobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.mobject.rst:2\nmsgid \"mobject\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject:1\nmsgid \"Base classes for objects that can be displayed.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.rst:28:<autosummary>:1\nmsgid \"Groups together multiple :class:`Mobjects <.Mobject>`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.rst:28:<autosummary>:1\nmsgid \"Mathematical Object: base class for objects that can be displayed on screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.mobject.rst:31\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.override_animate:1\nmsgid \"Decorator for overriding method animations.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.override_animate:3\nmsgid \"This allows to specify a method (returning an :class:`~.Animation`) which is called when the decorated method is used with the ``.animate`` syntax for animating the application of a method.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/mobject.py:docstring of manim.mobject.mobject.override_animate:13\nmsgid \"Overridden methods cannot be combined with normal or other overridden methods using method chaining with the ``.animate`` syntax.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.mobject_update_utils.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.number_line.NumberLine.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.number_line.UnitInterval.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.number_line.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.numbers.DecimalNumber.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.numbers.Integer.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.numbers.Variable.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.numbers.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.polyhedra.Dodecahedron.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.polyhedra.Icosahedron.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.polyhedra.Octahedron.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.polyhedra.Polyhedron.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.polyhedra.Tetrahedron.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.polyhedra.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.probability.BarChart.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.probability.SampleSpace.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.probability.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.shape_matchers.BackgroundRectangle.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.shape_matchers.Cross.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.shape_matchers.SurroundingRectangle.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.shape_matchers.Underline.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.shape_matchers.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.brace.ArcBrace.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:2\nmsgid \"ArcBrace\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:4\nmsgid \"Qualified name: ``manim.mobject.svg.brace.ArcBrace``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:1\nmsgid \"Bases: :py:class:`manim.mobject.svg.brace.Brace`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:1\nmsgid \"Creates a :class:`~Brace` that wraps around an :class:`~.Arc`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:3\nmsgid \"The direction parameter allows the brace to be applied from outside or inside the arc.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:7\nmsgid \"The :class:`ArcBrace` is smaller for arcs with smaller radii.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:10\nmsgid \"The :class:`ArcBrace` is initially a vertical :class:`Brace` defined by the length of the :class:`~.Arc`, but is scaled down to match the start and end angles. An exponential function is then applied after it is shifted based on the radius of the arc.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:15\nmsgid \"The scaling effect is not applied for arcs with radii smaller than 1 to prevent over-scaling.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:18\nmsgid \"The :class:`~.Arc` that wraps around the :class:`Brace` mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:19\nmsgid \"The direction from which the brace faces the arc. ``LEFT`` for inside the arc, and ``RIGHT`` for the outside.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.ArcBrace:23\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.ArcBrace.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.brace.Brace.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.brace.Brace.rst:2\nmsgid \"Brace\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.Brace.rst:4\nmsgid \"Qualified name: ``manim.mobject.svg.brace.Brace``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:1\nmsgid \"Bases: :py:class:`manim.mobject.svg.svg_path.SVGPathMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:1\nmsgid \"Takes a mobject and draws a brace adjacent to it.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:3\nmsgid \"Passing a direction vector determines the direction from which the brace is drawn. By default it is drawn from below.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:6\nmsgid \"The mobject adjacent to which the brace is placed.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:8\nmsgid \"The direction from which the brace faces the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace:13\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.Brace.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.Brace.rst:24:<autosummary>:1\nmsgid \"Uses :func:`~.space_ops.shoelace_direction` to calculate the direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.Brace.rst:26\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:1\nmsgid \"Uses :func:`~.space_ops.shoelace_direction` to calculate the direction. The direction of points determines in which direction the object is drawn, clockwise or counterclockwise.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:7\nmsgid \"The default direction of a :class:`~.Circle` is counterclockwise::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:13\nmsgid \"Either ``\\\"CW\\\"`` or ``\\\"CCW\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.Brace.get_direction:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.brace.BraceBetweenPoints.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:2\nmsgid \"BraceBetweenPoints\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:4\nmsgid \"Qualified name: ``manim.mobject.svg.brace.BraceBetweenPoints``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:1\nmsgid \"Bases: :py:class:`manim.mobject.svg.brace.Brace`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:1\nmsgid \"Similar to Brace, but instead of taking a mobject it uses 2 points to place the brace.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:4\nmsgid \"A fitting direction for the brace is computed, but it still can be manually overridden. If the points go from left to right, the brace is drawn from below. Swapping the points places the brace on the opposite side.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:9\nmsgid \"The first point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:10\nmsgid \"The second point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:11\nmsgid \"The direction from which the brace faces towards the points.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceBetweenPoints:14\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceBetweenPoints.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.brace.BraceLabel.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:2\nmsgid \"BraceLabel\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:4\nmsgid \"Qualified name: ``manim.mobject.svg.brace.BraceLabel``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceLabel:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:36:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:36:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:36:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceLabel.rst:36:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.brace.BraceText.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:2\nmsgid \"BraceText\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:4\nmsgid \"Qualified name: ``manim.mobject.svg.brace.BraceText``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace.BraceText:1\nmsgid \"Bases: :py:class:`manim.mobject.svg.brace.BraceLabel`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.BraceText.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.brace.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.brace.rst:2\nmsgid \"brace\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/brace.py:docstring of manim.mobject.svg.brace:1\nmsgid \"Mobject representing curly braces.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.rst:28:<autosummary>:1\nmsgid \"Creates a :class:`~Brace` that wraps around an :class:`~.Arc`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.rst:28:<autosummary>:1\nmsgid \"Takes a mobject and draws a brace adjacent to it.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.brace.rst:28:<autosummary>:1\nmsgid \"Similar to Brace, but instead of taking a mobject it uses 2 points to place the brace.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.code_mobject.Code.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.code_mobject.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.rst:2\nmsgid \"svg\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/__init__.py:docstring of manim.mobject.svg:1\nmsgid \"Mobjects related to SVG images.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/__init__.py:docstring of manim.mobject.svg:4\nmsgid \"Modules\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/__init__.py:docstring of manim.mobject.svg:13:<autosummary>:1\nmsgid \"Mobject representing curly braces.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/__init__.py:docstring of manim.mobject.svg:13:<autosummary>:1\nmsgid \"Utility functions for parsing SVG styles.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/__init__.py:docstring of manim.mobject.svg:13:<autosummary>:1\nmsgid \"Mobjects generated from an SVG file.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.style_utils.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.style_utils.rst:2\nmsgid \"style\\\\_utils\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils:1\nmsgid \"Utility functions for parsing SVG styles.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.style_utils.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:1\nmsgid \"Collect the element's style attributes based upon both its inheritance and its own attributes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:3\nmsgid \"SVG uses cascading element styles. A closer ancestor's style takes precedence over a more distant ancestor's style. In order to correctly calculate the styles, the attributes are passed down through the inheritance tree, updating where necessary.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:7\nmsgid \"Note that this method only copies the values and does not parse them. See :meth:`parse_color_string` for converting from SVG attributes to manim keyword arguments.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:0\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:0\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:0\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_style:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:10\nmsgid \"Element of the SVG parse tree\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:12\nmsgid \"Dictionary of SVG attributes inherited from the parent element.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:0\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:0\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:0\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_style:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:15\nmsgid \"Dictionary mapping svg attributes to values with `element`'s values overriding inherited values.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.cascade_element_style:0\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:0\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:0\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_style:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:1\nmsgid \"Fill in the default values for properties of SVG elements, if they are not currently set in the style dictionary.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:4\nmsgid \"Style dictionary with SVG property names. Some may be missing.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.fill_default_values:7\nmsgid \"Style attributes; none are missing.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:1\nmsgid \"Handle the SVG-specific color strings and convert them to HTML #rrggbb format.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:3\nmsgid \"String in any web-compatible format\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_color_string:6\nmsgid \"Hexadecimal color string in the format `#rrggbb`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_style:1\nmsgid \"Convert a dictionary of SVG attributes to Manim VMobject keyword arguments.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/style_utils.py:docstring of manim.mobject.svg.style_utils.parse_style:3\nmsgid \"Style attributes as a string-to-string dictionary. Keys are valid SVG element attributes (fill, stroke, etc)\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.svg_mobject.SVGMobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:2\nmsgid \"SVGMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:4\nmsgid \"Qualified name: ``manim.mobject.svg.svg\\\\_mobject.SVGMobject``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:1\nmsgid \"A SVGMobject is a Vector Mobject constructed from an SVG (or XDV) file.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:3\nmsgid \"SVGMobjects are constructed from the XML data within the SVG file structure. As such, subcomponents from the XML data can be accessed via the submobjects attribute. There is varying amounts of support for SVG elements, experiment with SVG files at your own peril.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:16\nmsgid \"The file's path name. When possible, the full path is preferred but a relative path may be used as well. Relative paths are relative to the directory specified by the `--assets_dir` command line argument.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:21\nmsgid \"Whether the SVGMobject should be centered to the origin. Defaults to `True`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:23\nmsgid \"Specify the final height of the SVG file. Defaults to 2 units.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:25\nmsgid \"Specify the width the SVG file should occupy. Defaults to `None`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:27\nmsgid \"Whether the hierarchies of VGroups generated should be flattened. Defaults to `True`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:29\nmsgid \"The stroke width of the outer edge of an SVG path element. Defaults to `4`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject:31\nmsgid \"Specifies the opacity of the image. `1` is opaque, `0` is transparent. Defaults to `1`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:23:<autosummary>:1\n#: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:23:<autosummary>:1\nmsgid \"Called by the Mobject abstract base class.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:23:<autosummary>:1\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.init_colors:1\nmsgid \"Initializes the colors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_mobject.SVGMobject.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject.SVGMobject.generate_points:1\nmsgid \"Called by the Mobject abstract base class. Responsible for generating the SVGMobject's points from XML tags, populating self.mobjects, and any submobjects within self.mobjects.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.svg_mobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.svg_mobject.rst:2\nmsgid \"svg\\\\_mobject\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_mobject.py:docstring of manim.mobject.svg.svg_mobject:1\nmsgid \"Mobjects generated from an SVG file.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_mobject.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.svg_path.SVGPathMobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:2\nmsgid \"SVGPathMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:4\nmsgid \"Qualified name: ``manim.mobject.svg.svg\\\\_path.SVGPathMobject``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26:<autosummary>:1\n#: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26:<autosummary>:1\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1\nmsgid \"Generates points from a given an SVG ``d`` attribute.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26:<autosummary>:1\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_original_path_string:1\nmsgid \"A simple getter for the path's ``d`` attribute.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26:<autosummary>:1\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:1\nmsgid \"Returns a list of possible path commands used within an SVG ``d`` attribute.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26:<autosummary>:1\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.handle_command:1\nmsgid \"Core logic for handling each of the various path commands.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:26:<autosummary>:1\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.string_to_points:1\nmsgid \"Convert an SVG command string into a sequence of absolute-positioned control points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.SVGPathMobject.rst:28\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:4\nmsgid \"See: https://svgwg.org/svg2-draft/paths.html#DProperty for further details on what each path command does.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:7\nmsgid \"The various upper and lower cased path commands.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.get_path_commands:8\nmsgid \"List[:class:`str`]\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.string_to_points:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.string_to_points:3\nmsgid \"A string containing a single uppercase letter representing the SVG command.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.string_to_points:5\nmsgid \"Whether the command is relative to the end of the previous command\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.SVGPathMobject.string_to_points:7\nmsgid \"A string that contains many comma- or space-separated numbers that defined the control points. Different commands require different numbers of numbers as arguments.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.svg_path.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.rst:2\nmsgid \"svg\\\\_path\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path:1\nmsgid \"Mobjects generated from an SVG pathstring.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.svg.svg_path.rst:29\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.correct_out_of_range_radii:1\nmsgid \"Correction of out-of-range radii.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.correct_out_of_range_radii:3\nmsgid \"See: https://www.w3.org/TR/SVG11/implnote.html#ArcCorrectionOutOfRangeRadii\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.elliptical_arc_to_cubic_bezier:1\nmsgid \"Generate cubic bezier points to approximate SVG elliptical arc.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.elliptical_arc_to_cubic_bezier:3\nmsgid \"See: http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.get_elliptical_arc_center_parameters:1\nmsgid \"Conversion from endpoint to center parameterization.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.get_elliptical_arc_center_parameters:3\nmsgid \"See: https://www.w3.org/TR/SVG11/implnote.html#ArcConversionEndpointToCenter\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.grouped:1\nmsgid \"Group iterable into arrays of n items.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:1\nmsgid \"Parse the SVG string representing a sequence of numbers into an array of floats.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:3\nmsgid \"String representing a sequence of numbers, separated by commas, spaces, etc.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:6\nmsgid \"List of float values parsed out of the string.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.string_to_numbers:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/svg/svg_path.py:docstring of manim.mobject.svg.svg_path.vector_angle:1\nmsgid \"Calculate the dot product angle between two vectors.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.BulletedList.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.MathTex.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.SingleStringMathTex.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.Tex.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.TexSymbol.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.Title.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.tex_mobject.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.text_mobject.MarkupText.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.text_mobject.Paragraph.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.text_mobject.Text.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.svg.text_mobject.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.table.DecimalTable.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.table.DecimalTable.rst:2\nmsgid \"DecimalTable\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.DecimalTable.rst:4\nmsgid \"Qualified name: ``manim.mobject.table.DecimalTable``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:1\nmsgid \"Bases: :py:class:`manim.mobject.table.Table`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:1\nmsgid \"A specialized :class:`~.Table` mobject for use with :class:`~.DecimalNumber` to display decimal entries.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:19\nmsgid \"Special case of :class:`~.Table` with ``element_to_mobject`` set to :class:`~.DecimalNumber`. By default, ``num_decimal_places`` is set to 1. Will round/truncate the decimal places based on the provided ``element_to_mobject_config``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:23\nmsgid \"A 2D array, or a list of lists. Content of the table must be valid input for :class:`~.DecimalNumber`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:25\nmsgid \"The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.DecimalNumber`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:26\nmsgid \"Element to mobject config, here set as {\\\"num_decimal_places\\\": 1}.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.DecimalTable:27\nmsgid \"Additional arguments to be passed to :class:`~.Table`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.DecimalTable.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.DecimalTable.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.DecimalTable.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.DecimalTable.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.DecimalTable.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.DecimalTable.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.table.IntegerTable.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.table.IntegerTable.rst:2\nmsgid \"IntegerTable\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.IntegerTable.rst:4\nmsgid \"Qualified name: ``manim.mobject.table.IntegerTable``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:1\nmsgid \"Bases: :py:class:`manim.mobject.table.Table`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:1\nmsgid \"A specialized :class:`~.Table` mobject for use with :class:`~.Integer`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:24\nmsgid \"Special case of :class:`~.Table` with `element_to_mobject` set to :class:`~.Integer`. Will round if there are decimal entries in the table.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:27\nmsgid \"A 2d array or list of lists. Content of the table has to be valid input for :class:`~.Integer`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:29\nmsgid \"The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.Integer`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.IntegerTable:30\nmsgid \"Additional arguments to be passed to :class:`~.Table`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.IntegerTable.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.IntegerTable.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.IntegerTable.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.IntegerTable.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.IntegerTable.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.IntegerTable.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.table.MathTable.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.table.MathTable.rst:2\nmsgid \"MathTable\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MathTable.rst:4\nmsgid \"Qualified name: ``manim.mobject.table.MathTable``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:1\nmsgid \"Bases: :py:class:`manim.mobject.table.Table`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:1\nmsgid \"A specialized :class:`~.Table` mobject for use with LaTeX.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:18\nmsgid \"Special case of :class:`~.Table` with `element_to_mobject` set to :class:`~.MathTex`. Every entry in `table` is set in a Latex `align` environment.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:21\nmsgid \"A 2d array or list of lists. Content of the table have to be valid input for :class:`~.MathTex`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:23\nmsgid \"The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.MathTex`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MathTable:24\nmsgid \"Additional arguments to be passed to :class:`~.Table`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MathTable.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MathTable.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MathTable.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MathTable.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MathTable.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MathTable.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.table.MobjectTable.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.table.MobjectTable.rst:2\nmsgid \"MobjectTable\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MobjectTable.rst:4\nmsgid \"Qualified name: ``manim.mobject.table.MobjectTable``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:1\nmsgid \"Bases: :py:class:`manim.mobject.table.Table`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:1\nmsgid \"A specialized :class:`~.Table` mobject for use with :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:26\nmsgid \"Special case of :class:`~.Table` with ``element_to_mobject`` set to an identity function. Here, every item in ``table`` must already be of type :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:29\nmsgid \"A 2D array or list of lists. Content of the table must be of type :class:`~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:30\nmsgid \"The :class:`~.Mobject` class applied to the table entries. Set as ``lambda m : m`` to return itself.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.MobjectTable:31\nmsgid \"Additional arguments to be passed to :class:`~.Table`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MobjectTable.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MobjectTable.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MobjectTable.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MobjectTable.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MobjectTable.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.MobjectTable.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.table.Table.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:2\nmsgid \"Table\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:4\nmsgid \"Qualified name: ``manim.mobject.table.Table``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:1\nmsgid \"A mobject that displays a table on the screen.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:4\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:10\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:15\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:12\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_col_labels:7\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_columns:7\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:12\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:12\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:10\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_horizontal_lines:7\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_labels:7\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_row_labels:7\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_rows:7\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_vertical_lines:7\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:15\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_column_colors:6\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_row_colors:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_column_colors:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_row_colors:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:62\nmsgid \"A 2D array or list of lists. Content of the table has to be a valid input for the callable set in ``element_to_mobject``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:64\nmsgid \"List of :class:`~.VMobject` representing the labels of each row.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:65\nmsgid \"List of :class:`~.VMobject` representing the labels of each column.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:66\nmsgid \"The top-left entry of the table, can only be specified if row and column labels are given.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:68\nmsgid \"Vertical buffer passed to :meth:`~.Mobject.arrange_in_grid`, by default 0.8.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:69\nmsgid \"Horizontal buffer passed to :meth:`~.Mobject.arrange_in_grid`, by default 1.3.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:70\nmsgid \"``True`` if the table should include outer lines, by default False.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:71\nmsgid \"``True`` if background rectangles should be added to entries, by default ``False``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:72\nmsgid \"Background color of entries if ``add_background_rectangles_to_entries`` is ``True``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:73\nmsgid \"``True`` if the table should have a background rectangle, by default ``False``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:74\nmsgid \"Background color of table if ``include_background_rectangle`` is ``True``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:75\nmsgid \"The :class:`~.Mobject` class applied to the table entries. by default :class:`~.Paragraph`. For common choices, see :mod:`~.text_mobject`/:mod:`~.tex_mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:76\nmsgid \"Custom configuration passed to :attr:`element_to_mobject`, by default {}.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:77\nmsgid \"Dict passed to :meth:`~.Mobject.arrange_in_grid`, customizes the arrangement of the table.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:78\nmsgid \"Dict passed to :class:`~.Line`, customizes the lines of the table.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table:79\nmsgid \"Additional arguments to be passed to :class:`~.VGroup`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1\nmsgid \"Adds a black :class:`~.BackgroundRectangle` to each entry of the table.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:1\nmsgid \"Highlights one cell at a specific position on the table by adding a :class:`~.BackgroundRectangle`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:1\nmsgid \"Customized create-type function for tables.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:1\nmsgid \"Returns one specific cell as a rectangular :class:`~.Polygon` without the entry.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_col_labels:1\nmsgid \"Return the column labels of the table.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_columns:1\nmsgid \"Return columns of the table as a :class:`~.VGroup` of :class:`~.VGroup`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:1\nmsgid \"Return the individual entries of the table (including labels) or one specific entry if the parameter, ``pos``,  is set.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:1\nmsgid \"Return the individual entries of the table (without labels) or one specific entry if the parameter, ``pos``, is set.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:1\nmsgid \"Returns a :class:`~.BackgroundRectangle` of the cell at the given position.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_horizontal_lines:1\nmsgid \"Return the horizontal lines of the table.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_labels:1\nmsgid \"Returns the labels of the table.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_row_labels:1\nmsgid \"Return the row labels of the table.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_rows:1\nmsgid \"Return the rows of the table as a :class:`~.VGroup` of :class:`~.VGroup`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_vertical_lines:1\nmsgid \"Return the vertical lines of the table.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:1\nmsgid \"Scale the size by a factor.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_column_colors:1\nmsgid \"Set individual colors for each column of the table.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:36:<autosummary>:1\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_row_colors:1\nmsgid \"Set individual colors for each row of the table.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.Table.rst:38\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_background_to_entries:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_col_labels:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_columns:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_horizontal_lines:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_labels:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_row_labels:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_rows:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_vertical_lines:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_column_colors:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_row_colors:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:3\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:3\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:4\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:3\nmsgid \"The position of a specific entry on the table. ``(1,1)`` being the top left entry of the table.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:5\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:5\nmsgid \"The color used to highlight the cell.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.add_highlighted_cell:6\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_highlighted_cell:6\nmsgid \"Additional arguments to be passed to :class:`~.BackgroundRectangle`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:3\nmsgid \"The run time of the line creation and the writing of the elements.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:4\nmsgid \"The lag ratio of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:5\nmsgid \"The animation style of the table lines, see :mod:`~.creation` for examples.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:6\nmsgid \"The animation style of the table labels, see :mod:`~.creation` for examples.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:7\nmsgid \"The animation style of the table elements, see :mod:`~.creation` for examples.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:8\nmsgid \"Further arguments passed to the creation animations.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_col_labels:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_columns:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_horizontal_lines:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_labels:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_row_labels:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_rows:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_vertical_lines:0\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.create:11\nmsgid \"AnimationGroup containing creation of the lines and of the elements.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:5\nmsgid \"Additional arguments to be passed to :class:`~.Polygon`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_cell:8\nmsgid \"Polygon mimicking one specific cell of the Table.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_col_labels:3\nmsgid \"VGroup containing the column labels of the table.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_columns:3\nmsgid \":class:`~.VGroup` containing each column in a :class:`~.VGroup`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:7\nmsgid \":class:`~.VGroup` containing all entries of the table (including labels) or the :class:`~.VMobject` at the given position if ``pos`` is set.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries:9\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:9\nmsgid \"Union[:class:`~.VMobject`, :class:`~.VGroup`]\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:4\nmsgid \"The position of a specific entry on the table. ``(1,1)`` being the top left entry of the table (without labels).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_entries_without_labels:7\nmsgid \":class:`~.VGroup` containing all entries of the table (without labels) or the :class:`~.VMobject` at the given position if ``pos`` is set.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_horizontal_lines:3\nmsgid \":class:`~.VGroup` containing all the horizontal lines of the table.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_labels:3\nmsgid \":class:`~.VGroup` containing all the labels of the table.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_row_labels:3\nmsgid \":class:`~.VGroup` containing the row labels of the table.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_rows:3\nmsgid \":class:`~.VGroup` containing each row in a :class:`~.VGroup`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.get_vertical_lines:3\nmsgid \":class:`~.VGroup` containing all the vertical lines of the table.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:3\nmsgid \"Default behavior is to scale about the center of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:5\nmsgid \"The scaling factor :math:`\\\\alpha`. If :math:`0 < |\\\\alpha| < 1`, the mobject will shrink, and for :math:`|\\\\alpha| > 1` it will grow. Furthermore, if :math:`\\\\alpha < 0`, the mobject is also flipped.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:8\nmsgid \"Additional keyword arguments passed to :meth:`apply_points_function_about_point`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.scale:11\nmsgid \"``self``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table.Table.set_column_colors:3\nmsgid \"An iterable of colors; each color corresponds to a column.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.table.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.table.rst:2\nmsgid \"table\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table:1\nmsgid \"Mobjects representing tables.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/table.py:docstring of manim.mobject.table:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.rst:28:<autosummary>:1\nmsgid \"A specialized :class:`~.Table` mobject for use with :class:`~.DecimalNumber` to display decimal entries.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.rst:28:<autosummary>:1\nmsgid \"A specialized :class:`~.Table` mobject for use with :class:`~.Integer`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.rst:28:<autosummary>:1\nmsgid \"A specialized :class:`~.Table` mobject for use with LaTeX.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.table.rst:28:<autosummary>:1\nmsgid \"A specialized :class:`~.Table` mobject for use with :class:`~.Mobject`.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.code_mobject.Code.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:2\nmsgid \"Code\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.code\\\\_mobject.Code``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:1\nmsgid \"A highlighted source code listing.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:3\nmsgid \"An object ``listing`` of :class:`.Code` is a :class:`.VGroup` consisting of three objects:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:6\nmsgid \"The background, ``listing.background_mobject``. This is either a :class:`.Rectangle` (if the listing has been initialized with ``background=\\\"rectangle\\\"``, the default option) or a :class:`.VGroup` resembling a window (if ``background=\\\"window\\\"`` has been passed).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:11\nmsgid \"The line numbers, ``listing.line_numbers`` (a :class:`.Paragraph` object).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:14\nmsgid \"The highlighted code itself, ``listing.code`` (a :class:`.Paragraph` object).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:19\nmsgid \"Using a :class:`.Transform` on text with leading whitespace (and in this particular case: code) can look `weird <https://github.com/3b1b/manim/issues/1067>`_. Consider using :meth:`remove_invisible_chars` to resolve this issue.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:25\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:26\nmsgid \"Normal usage::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:39\nmsgid \"We can also render code passed as a string (but note that the language has to be specified in this case):\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:60\nmsgid \"Name of the code file to display.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:62\nmsgid \"If ``file_name`` is not specified, a code string can be passed directly.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:65\nmsgid \"Number of space characters corresponding to a tab character. Defaults to 3.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:67\nmsgid \"Amount of space between lines in relation to font size. Defaults to 0.3, which means 30% of font size.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:69\nmsgid \"A number which scales displayed code. Defaults to 24.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:71\nmsgid \"The name of the text font to be used. Defaults to ``\\\"Monospac821 BT\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:73\nmsgid \"Stroke width for text. 0 is recommended, and the default.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:75\nmsgid \"Inner margin of text from the background. Defaults to 0.3.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:77\nmsgid \"\\\"Indentation chars\\\" refers to the spaces/tabs at the beginning of a given code line. Defaults to ``\\\"    \\\"`` (spaces).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:79\nmsgid \"Defines the background's type. Currently supports only ``\\\"rectangle\\\"`` (default) and ``\\\"window\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:81\nmsgid \"Defines the stroke width of the background. Defaults to 1.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:83\nmsgid \"Defines the stroke color for the background. Defaults to ``WHITE``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:85\nmsgid \"Defines the corner radius for the background. Defaults to 0.2.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:87\nmsgid \"Defines whether line numbers should be inserted in displayed code. Defaults to ``True``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:89\nmsgid \"Defines the first line's number in the line count. Defaults to 1.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:91\nmsgid \"Defines the spacing between line numbers and displayed code. Defaults to 0.4.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:93\nmsgid \"Defines the style type of displayed code. You can see possible names of styles in with :attr:`styles_list`. Defaults to ``\\\"vim\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:95\nmsgid \"Specifies the programming language the given code was written in. If ``None`` (the default), the language will be automatically detected. For the list of possible options, visit https://pygments.org/docs/lexers/ and look for 'aliases or short names'.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:100\nmsgid \"Defines whether to generate highlighted html code to the folder `assets/codes/generated_html_files`. Defaults to `False`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:105\nmsgid \"The background of the code listing.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:0\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:0\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:0\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:111\nmsgid \"The line numbers for the code listing. Empty, if ``insert_line_no=False`` has been specified.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject.Code:118\nmsgid \"The highlighted code.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:33:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:33:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:33:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.code_mobject.Code.rst:33:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.code_mobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.code_mobject.rst:2\nmsgid \"code\\\\_mobject\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/code_mobject.py:docstring of manim.mobject.text.code_mobject:1\nmsgid \"Mobject representing highlighted source code listings.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.code_mobject.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.numbers.DecimalNumber.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.numbers.DecimalNumber.rst:2\nmsgid \"DecimalNumber\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.DecimalNumber.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.numbers.DecimalNumber``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber:1\nmsgid \"An mobject representing a decimal number.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.DecimalNumber.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.DecimalNumber.rst:22:<autosummary>:1\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.set_value:1\nmsgid \"Set the value of the :class:`~.DecimalNumber` to a new number.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.DecimalNumber.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1:<autosummary>:1\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1\nmsgid \"The font size of the tex mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.font_size:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber:0\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.DecimalNumber.set_value:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.numbers.Integer.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Integer.rst:2\nmsgid \"Integer\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Integer.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.numbers.Integer``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Integer:1\nmsgid \"Bases: :py:class:`manim.mobject.text.numbers.DecimalNumber`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Integer:1\nmsgid \"A class for displaying Integers.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Integer:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Integer.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Integer.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Integer.rst:34:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Integer.rst:34:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Integer.rst:34:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Integer.rst:34:<autosummary>:1\nmsgid \"The font size of the tex mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Integer.rst:34:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.numbers.Variable.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Variable.rst:2\nmsgid \"Variable\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Variable.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.numbers.Variable``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:1\nmsgid \"A class for displaying text that shows \\\"label = value\\\" with the value continuously updated from a :class:`~.ValueTracker`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:4\nmsgid \"The initial value you need to keep track of and display.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:6\nmsgid \"The label for your variable. Raw strings are convertex to :class:`~.MathTex` objects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:8\nmsgid \"The class used for displaying the number. Defaults to :class:`DecimalNumber`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:10\nmsgid \"The number of decimal places to display in your variable. Defaults to 2. If `var_type` is an :class:`Integer`, this parameter is ignored.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:13\nmsgid \"Other arguments to be passed to `~.Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:18\nmsgid \"The label for your variable, for example ``x = ...``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:0\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:0\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:0\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:20\nmsgid \"Union[:class:`str`, :class:`~.Tex`, :class:`~.MathTex`, :class:`~.Text`, :class:`~.TexSymbol`, :class:`~.SingleStringMathTex`]\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:24\nmsgid \"Useful in updating the value of your variable on-screen.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:30\nmsgid \"The tex for the value of your variable.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:32\nmsgid \"Union[:class:`DecimalNumber`, :class:`Integer`]\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:35\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers.Variable:36\nmsgid \"Normal usage::\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Variable.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Variable.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Variable.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Variable.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Variable.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.Variable.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.numbers.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.numbers.rst:2\nmsgid \"numbers\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/numbers.py:docstring of manim.mobject.text.numbers:1\nmsgid \"Mobjects representing numbers.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.rst:24:<autosummary>:1\nmsgid \"An mobject representing a decimal number.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.numbers.rst:24:<autosummary>:1\nmsgid \"A class for displaying Integers.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.rst:2\nmsgid \"text\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/__init__.py:docstring of manim.mobject.text:1\nmsgid \"Mobjects used to display Text using Pango or LaTeX.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/__init__.py:docstring of manim.mobject.text:4\nmsgid \"Modules\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/__init__.py:docstring of manim.mobject.text:13:<autosummary>:1\nmsgid \"Mobject representing highlighted source code listings.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/__init__.py:docstring of manim.mobject.text:13:<autosummary>:1\nmsgid \"Mobjects representing numbers.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/__init__.py:docstring of manim.mobject.text:13:<autosummary>:1\nmsgid \"Mobjects representing text rendered using LaTeX.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.BulletedList.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:2\nmsgid \"BulletedList\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.tex\\\\_mobject.BulletedList``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.BulletedList:1\nmsgid \"Bases: :py:class:`manim.mobject.text.tex_mobject.Tex`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.BulletedList:2\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:34:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:34:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:34:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:34:<autosummary>:1\nmsgid \"The font size of the tex mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.BulletedList.rst:34:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.MathTex.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:2\nmsgid \"MathTex\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.tex\\\\_mobject.MathTex``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:1\nmsgid \"Bases: :py:class:`manim.mobject.text.tex_mobject.SingleStringMathTex`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:1\nmsgid \"A string compiled with LaTeX in math mode.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:14\nmsgid \"Tests\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:15\nmsgid \"Check that creating a :class:`~.MathTex` works::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.MathTex:20\nmsgid \"Check that double brace group splitting works correctly::\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:28\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40:<autosummary>:1\nmsgid \"The font size of the tex mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.MathTex.rst:40:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.rst:2\nmsgid \"SingleStringMathTex\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.tex\\\\_mobject.SingleStringMathTex``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex:1\nmsgid \"Bases: :py:class:`manim.mobject.svg.svg_mobject.SVGMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex:1\nmsgid \"Elementary building block for rendering text with LaTeX.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex:4\nmsgid \"Tests\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex:5\nmsgid \"Check that creating a :class:`~.SingleStringMathTex` object works::\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.rst:22:<autosummary>:1\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.init_colors:1\nmsgid \"Initializes the colors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.SingleStringMathTex.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1:<autosummary>:1\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1\nmsgid \"The font size of the tex mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex.font_size:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.SingleStringMathTex:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.Tex.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:2\nmsgid \"Tex\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.tex\\\\_mobject.Tex``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Tex:1\nmsgid \"Bases: :py:class:`manim.mobject.text.tex_mobject.MathTex`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Tex:1\nmsgid \"A string compiled with LaTeX in normal mode.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Tex:4\nmsgid \"Tests\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Tex:5\nmsgid \"Check whether writing a LaTeX string works::\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:33:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:33:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:33:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:33:<autosummary>:1\nmsgid \"The font size of the tex mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Tex.rst:33:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.TexSymbol.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:2\nmsgid \"TexSymbol\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.tex\\\\_mobject.TexSymbol``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.TexSymbol:1\nmsgid \"Bases: :py:class:`manim.mobject.svg.svg_path.SVGPathMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.TexSymbol:1\nmsgid \"Purely a renaming of SVGPathMobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.TexSymbol.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.Title.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:2\nmsgid \"Title\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.tex\\\\_mobject.Title``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Title:1\nmsgid \"Bases: :py:class:`manim.mobject.text.tex_mobject.Tex`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject.Title:2\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:33:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:33:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:33:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:33:<autosummary>:1\nmsgid \"The font size of the tex mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.Title.rst:33:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.tex_mobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.rst:2\nmsgid \"tex\\\\_mobject\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject:1\nmsgid \"Mobjects representing text rendered using LaTeX.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject:5\nmsgid \"See the corresponding tutorial :ref:`rendering-with-latex`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/tex_mobject.py:docstring of manim.mobject.text.tex_mobject:9\nmsgid \"Just as you can use :class:`~.Text` (from the module :mod:`~.text_mobject`) to add text to your videos, you can use :class:`~.Tex` and :class:`~.MathTex` to insert LaTeX.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.rst:0\n#: ../../source/reference/manim.mobject.text.tex_mobject.rst:0\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.rst:30:<autosummary>:1\nmsgid \"A string compiled with LaTeX in math mode.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.rst:30:<autosummary>:1\nmsgid \"Elementary building block for rendering text with LaTeX.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.rst:30:<autosummary>:1\nmsgid \"A string compiled with LaTeX in normal mode.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.tex_mobject.rst:30:<autosummary>:1\nmsgid \"Purely a renaming of SVGPathMobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.text_mobject.MarkupText.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:2\nmsgid \"MarkupText\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.text\\\\_mobject.MarkupText``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:1\nmsgid \"Bases: :py:class:`manim.mobject.svg.svg_mobject.SVGMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:1\nmsgid \"Display (non-LaTeX) text rendered using `Pango <https://pango.gnome.org/>`_.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:3\nmsgid \"Text objects behave like a :class:`.VGroup`-like iterable of all characters in the given text. In particular, slicing is possible.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:6\nmsgid \"**What is PangoMarkup?**\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:8\nmsgid \"PangoMarkup is a small markup language like html and it helps you avoid using \\\"range of characters\\\" while coloring or styling a piece a Text. You can use this language with :class:`~.MarkupText`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:12\nmsgid \"A simple example of a marked-up string might be::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:16\nmsgid \"and it can be used with :class:`~.MarkupText` as\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:26\nmsgid \"A more elaborate example would be:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:42\nmsgid \"PangoMarkup can also contain XML features such as numeric character entities such as ``&#169;`` for © can be used too.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:45\nmsgid \"The most general markup tag is ``<span>``, then there are some convenience tags.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:48\nmsgid \"Here is a list of supported tags:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:50\nmsgid \"``<b>bold</b>``, ``<i>italic</i>`` and ``<b><i>bold+italic</i></b>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:51\nmsgid \"``<ul>underline</ul>`` and ``<s>strike through</s>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:52\nmsgid \"``<tt>typewriter font</tt>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:53\nmsgid \"``<big>bigger font</big>`` and ``<small>smaller font</small>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:54\nmsgid \"``<sup>superscript</sup>`` and ``<sub>subscript</sub>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:55\nmsgid \"``<span underline=\\\"double\\\" underline_color=\\\"green\\\">double underline</span>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:56\nmsgid \"``<span underline=\\\"error\\\">error underline</span>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:57\nmsgid \"``<span overline=\\\"single\\\" overline_color=\\\"green\\\">overline</span>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:58\nmsgid \"``<span strikethrough=\\\"true\\\" strikethrough_color=\\\"red\\\">strikethrough</span>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:59\nmsgid \"``<span font_family=\\\"sans\\\">temporary change of font</span>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:60\nmsgid \"``<span foreground=\\\"red\\\">temporary change of color</span>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:61\nmsgid \"``<span fgcolor=\\\"red\\\">temporary change of color</span>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:62\nmsgid \"``<gradient from=\\\"YELLOW\\\" to=\\\"RED\\\">temporary gradient</gradient>``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:64\nmsgid \"For ``<span>`` markup, colors can be specified either as hex triples like ``#aabbcc`` or as named CSS colors like ``AliceBlue``. The ``<gradient>`` tag is handled by Manim rather than Pango, and supports hex triplets or Manim constants like ``RED`` or ``RED_A``. If you want to use Manim constants like ``RED_A`` together with ``<span>``, you will need to use Python's f-String syntax as follows::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:76\nmsgid \"If your text contains ligatures, the :class:`MarkupText` class may incorrectly determine the first and last letter when creating the gradient. This is due to the fact that ``fl`` are two separate characters, but might be set as one single glyph - a ligature. If your language does not depend on ligatures, consider setting ``disable_ligatures`` to ``True``. If you must use ligatures, the ``gradient`` tag supports an optional attribute ``offset`` which can be used to compensate for that error.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:84\nmsgid \"For example:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:86\nmsgid \"``<gradient from=\\\"RED\\\" to=\\\"YELLOW\\\" offset=\\\"1\\\">example</gradient>`` to *start* the gradient one letter earlier\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:87\nmsgid \"``<gradient from=\\\"RED\\\" to=\\\"YELLOW\\\" offset=\\\",1\\\">example</gradient>`` to *end* the gradient one letter earlier\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:88\nmsgid \"``<gradient from=\\\"RED\\\" to=\\\"YELLOW\\\" offset=\\\"2,1\\\">example</gradient>`` to *start* the gradient two letters earlier and *end* it one letter earlier\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:90\nmsgid \"Specifying a second offset may be necessary if the text to be colored does itself contain ligatures. The same can happen when using HTML entities for special chars.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:94\nmsgid \"When using ``underline``, ``overline`` or ``strikethrough`` together with ``<gradient>`` tags, you will also need to use the offset, because underlines are additional paths in the final :class:`SVGMobject`. Check out the following example.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:99\nmsgid \"Escaping of special characters: ``>`` **should** be written as ``&gt;`` whereas ``<`` and ``&`` *must* be written as ``&lt;`` and ``&amp;``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:103\nmsgid \"You can find more information about Pango markup formatting at the corresponding documentation page: `Pango Markup <https://docs.gtk.org/Pango/pango_markup.html>`_. Please be aware that not all features are supported by this class and that the ``<gradient>`` tag mentioned above is not supported by Pango.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:109\nmsgid \"The text that needs to be created as mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:110\nmsgid \"The fill opacity, with 1 meaning opaque and 0 meaning transparent.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:111\nmsgid \"Stroke width.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:112\nmsgid \"Font size.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:113\nmsgid \"Line spacing.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:114\nmsgid \"Global font setting for the entire text. Local overrides are possible.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:115\nmsgid \"Global slant setting, e.g. `NORMAL` or `ITALIC`. Local overrides are possible.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:116\nmsgid \"Global weight setting, e.g. `NORMAL` or `BOLD`. Local overrides are possible.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:117\nmsgid \"Global gradient setting. Local overrides are possible.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:119\nmsgid \"The text displayed in form of a :class:`.VGroup`-like mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:123\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:224\nmsgid \"As :class:`MarkupText` uses Pango to render text, rendering non-English characters is easily possible:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:243\nmsgid \"You can justify the text by passing :attr:`justify` parameter.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:278\nmsgid \"Tests\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.MarkupText:279\nmsgid \"Check that the creation of :class:`~.MarkupText` works::\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:33:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:33:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:33:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.MarkupText.rst:33:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.text_mobject.Paragraph.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:2\nmsgid \"Paragraph\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.text\\\\_mobject.Paragraph``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:1\nmsgid \"Display a paragraph of text.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:3\nmsgid \"For a given :class:`.Paragraph` ``par``, the attribute ``par.chars`` is a :class:`.VGroup` containing all the lines. In this context, every line is constructed as a :class:`.VGroup` of characters contained in the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:8\nmsgid \"Represents the spacing between lines. Defaults to -1, which means auto.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:9\nmsgid \"Defines the alignment of paragraph. Defaults to None. Possible values are \\\"left\\\", \\\"right\\\" or \\\"center\\\".\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:12\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:13\nmsgid \"Normal usage::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Paragraph:20\nmsgid \"Remove unwanted invisible characters::\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Paragraph.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.text_mobject.Text.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Text.rst:2\nmsgid \"Text\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Text.rst:4\nmsgid \"Qualified name: ``manim.mobject.text.text\\\\_mobject.Text``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:1\nmsgid \"Bases: :py:class:`manim.mobject.svg.svg_mobject.SVGMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:1\nmsgid \"Display (non-LaTeX) text rendered using `Pango <https://pango.gnome.org/>`_.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:3\nmsgid \"Text objects behave like a :class:`.VGroup`-like iterable of all characters in the given text. In particular, slicing is possible.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:6\nmsgid \"The text that needs to be created as a mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:8\nmsgid \"The mobject-like :class:`.VGroup`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:12\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:61\nmsgid \"As :class:`Text` uses Pango to render text, rendering non-English characters is easily possible:\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:94\nmsgid \"Tests\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text:95\nmsgid \"Check that the creation of :class:`~.Text` works::\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Text.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Text.rst:20:<autosummary>:1\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1\nmsgid \"Initializes the colors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.Text.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.Text.init_colors:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.text.text_mobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.rst:2\nmsgid \"text\\\\_mobject\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject:1\nmsgid \"Mobjects used for displaying (non-LaTeX) text.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject:4\nmsgid \"Just as you can use :class:`~.Tex` and :class:`~.MathTex` (from the module :mod:`~.tex_mobject`) to insert LaTeX to your videos, you can use :class:`~.Text` to to add normal text.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject:9\nmsgid \"See the corresponding tutorial :ref:`rendering-with-latex`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject:12\nmsgid \"The simplest way to add text to your animations is to use the :class:`~.Text` class. It uses the Pango library to render text. With Pango, you are also able to render non-English alphabets like `你好` or  `こんにちは` or `안녕하세요` or `مرحبا بالعالم`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject:16\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:13\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.rst:30:<autosummary>:1\n#: ../../source/reference/manim.mobject.text.text_mobject.rst:30:<autosummary>:1\nmsgid \"Display (non-LaTeX) text rendered using `Pango <https://pango.gnome.org/>`_.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.rst:30:<autosummary>:1\nmsgid \"Display a paragraph of text.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.text.text_mobject.rst:33\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:1\nmsgid \"Temporarily add a font file to Pango's search path.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:3\nmsgid \"This searches for the font_file at various places. The order it searches it described below.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:5\nmsgid \"Absolute path.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:6\nmsgid \"In ``assets/fonts`` folder.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:7\nmsgid \"In ``font/`` folder.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:8\nmsgid \"In the same directory.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:0\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:0\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:10\nmsgid \"The font file to add.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:14\nmsgid \"Use ``with register_font(...)`` to add a font file to search path.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:22\nmsgid \"If the font doesn't exists.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:23\nmsgid \"If this method is used on macOS.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.register_font:24\nmsgid \"This method is available for macOS for ``ManimPango>=v0.2.3``. Using this     method with previous releases will raise an :class:`AttributeError` on macOS.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:1\nmsgid \"Function to remove unwanted invisible characters from some mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:3\nmsgid \"Any SVGMobject from which we want to remove unwanted invisible characters.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:5\nmsgid \"The SVGMobject without unwanted invisible characters.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/text/text_mobject.py:docstring of manim.mobject.text.text_mobject.remove_invisible_chars:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.Dodecahedron.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:2\nmsgid \"Dodecahedron\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.polyhedra.Dodecahedron``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Dodecahedron:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.polyhedra.Polyhedron`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Dodecahedron:1\nmsgid \"A dodecahedron, one of the five platonic solids. It has 12 faces, 30 edges and 20 vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Dodecahedron:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Dodecahedron:3\nmsgid \"The length of an edge between any two vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Dodecahedron:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Dodecahedron.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.Icosahedron.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:2\nmsgid \"Icosahedron\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.polyhedra.Icosahedron``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Icosahedron:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.polyhedra.Polyhedron`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Icosahedron:1\nmsgid \"An icosahedron, one of the five platonic solids. It has 20 faces, 30 edges and 12 vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Icosahedron:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Icosahedron:3\nmsgid \"The length of an edge between any two vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Icosahedron:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Icosahedron.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.Octahedron.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:2\nmsgid \"Octahedron\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.polyhedra.Octahedron``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Octahedron:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.polyhedra.Polyhedron`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Octahedron:1\nmsgid \"An octahedron, one of the five platonic solids. It has 8 faces, 12 edges and 6 vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Octahedron:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Octahedron:3\nmsgid \"The length of an edge between any two vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Octahedron:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Octahedron.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.Polyhedron.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:2\nmsgid \"Polyhedron\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.polyhedra.Polyhedron``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:1\nmsgid \"An abstract polyhedra class.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:3\nmsgid \"In this implementation, polyhedra are defined with a list of vertex coordinates in space, and a list of faces. This implementation mirrors that of a standard polyhedral data format (OFF, object file format).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:0\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:0\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.get_edges:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:6\nmsgid \"A list of coordinates of the corresponding vertices in the polyhedron. Each coordinate will correspond to a vertex. The vertices are indexed with the usual indexing of Python.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:8\nmsgid \"A list of faces. Each face is a sublist containing the indices of the vertices that form the corners of that face.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:9\nmsgid \"Configuration for the polygons representing the faces of the polyhedron.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:10\nmsgid \"Configuration for the graph containing the vertices and edges of the polyhedron.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:13\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:14\nmsgid \"To understand how to create a custom polyhedra, let's use the example of a rather simple one - a square pyramid.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:39\nmsgid \"In defining the polyhedron above, we first defined the coordinates of the vertices. These are the corners of the square base, given as the first four coordinates in the vertex list, and the apex, the last coordinate in the list.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:43\nmsgid \"Next, we define the faces of the polyhedron. The triangular surfaces of the pyramid are polygons with two adjacent vertices in the base and the vertex at the apex as corners. We thus define these surfaces in the first four elements of our face list. The last element defines the base of the pyramid.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron:47\nmsgid \"The graph and faces of polyhedra can also be accessed and modified directly, after instantiation. They are stored in the `graph` and `faces` attributes respectively.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:23:<autosummary>:1\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1\nmsgid \"Creates VGroup of faces from a list of face coordinates.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:23:<autosummary>:1\nmsgid \"Extracts the coordinates of the vertices in the graph.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:23:<autosummary>:1\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.get_edges:1\nmsgid \"Creates list of cyclic pairwise tuples.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Polyhedron.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.create_faces:0\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.extract_face_coords:0\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Polyhedron.get_edges:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.Tetrahedron.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:2\nmsgid \"Tetrahedron\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.polyhedra.Tetrahedron``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Tetrahedron:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.polyhedra.Polyhedron`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Tetrahedron:1\nmsgid \"A tetrahedron, one of the five platonic solids. It has 4 faces, 6 edges, and 4 vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Tetrahedron:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Tetrahedron:3\nmsgid \"The length of an edge between any two vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra.Tetrahedron:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.Tetrahedron.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.polyhedra.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.rst:2\nmsgid \"polyhedra\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/polyhedra.py:docstring of manim.mobject.three_d.polyhedra:1\nmsgid \"General polyhedral class and platonic solids.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.rst:28:<autosummary>:1\nmsgid \"A dodecahedron, one of the five platonic solids.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.rst:28:<autosummary>:1\nmsgid \"An icosahedron, one of the five platonic solids.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.rst:28:<autosummary>:1\nmsgid \"An octahedron, one of the five platonic solids.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.polyhedra.rst:28:<autosummary>:1\nmsgid \"An abstract polyhedra class.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.rst:2\nmsgid \"three\\\\_d\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/__init__.py:docstring of manim.mobject.three_d:1\n#: ../../../manim/mobject/three_d/__init__.py:docstring of manim.mobject.three_d:12:<autosummary>:1\nmsgid \"Three-dimensional mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/__init__.py:docstring of manim.mobject.three_d:4\nmsgid \"Modules\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/__init__.py:docstring of manim.mobject.three_d:12:<autosummary>:1\nmsgid \"General polyhedral class and platonic solids.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/__init__.py:docstring of manim.mobject.three_d:12:<autosummary>:1\nmsgid \"Utility functions for three-dimensional mobjects.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_d_utils.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_d_utils.rst:2\nmsgid \"three\\\\_d\\\\_utils\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_d_utils.py:docstring of manim.mobject.three_d.three_d_utils:1\nmsgid \"Utility functions for three-dimensional mobjects.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Arrow3D.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:2\nmsgid \"Arrow3D\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.Arrow3D``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.three_dimensions.Line3D`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:1\nmsgid \"An arrow made out of a cylindrical line and a conical tip.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:15\nmsgid \"The start position of the arrow.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:17\nmsgid \"The end position of the arrow.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:19\nmsgid \"The thickness of the arrow.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:21\nmsgid \"The height of the conical tip.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Arrow3D:23\nmsgid \"The base radius of the conical tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Arrow3D.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Cone.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:2\nmsgid \"Cone\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.Cone``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.three_dimensions.Surface`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:1\nmsgid \"A circular cone. Can be defined using 2 parameters: its height, and its base radius. The polar angle, theta, can be calculated using arctan(base_radius / height) The spherical radius, r, is calculated using the pythagorean theorem.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:8\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:19\nmsgid \"The base radius from which the cone tapers.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:21\nmsgid \"The height measured from the plane formed by the base_radius to the apex of the cone.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:23\nmsgid \"The direction of the apex.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:25\nmsgid \"Whether to show the base plane or not.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:27\nmsgid \"The azimuthal angle to start and end at.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:29\nmsgid \"The radius at the apex.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone:31\nmsgid \"Show checkerboard grid texture on the cone.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:22:<autosummary>:1\nmsgid \"Converts from spherical coordinates to cartesian.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:22:<autosummary>:1\nmsgid \"Uses :func:`~.space_ops.shoelace_direction` to calculate the direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cone.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.func:1\nmsgid \"Converts from spherical coordinates to cartesian. :param u: The radius. :type u: :class:`float` :param v: The azimuthal angle. :type v: :class:`float`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:1\nmsgid \"Uses :func:`~.space_ops.shoelace_direction` to calculate the direction. The direction of points determines in which direction the object is drawn, clockwise or counterclockwise.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:7\nmsgid \"The default direction of a :class:`~.Circle` is counterclockwise::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:13\nmsgid \"Either ``\\\"CW\\\"`` or ``\\\"CCW\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cone.get_direction:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Cube.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:2\nmsgid \"Cube\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.Cube``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:21:<autosummary>:1\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:21:<autosummary>:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cube.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cube.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Cylinder.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:2\nmsgid \"Cylinder\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.Cylinder``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.three_dimensions.Surface`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:1\nmsgid \"A cylinder, defined by its height, radius and direction,\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:15\nmsgid \"The radius of the cylinder.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:17\nmsgid \"The height of the cylinder.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:19\nmsgid \"The direction of the central axis of the cylinder.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:21\nmsgid \"The height along the height axis (given by direction) to start and end on.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder:23\nmsgid \"Whether to show the end caps or not.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:23:<autosummary>:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1\nmsgid \"Adds the end caps of the cylinder.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:23:<autosummary>:1\nmsgid \"Converts from cylindrical coordinates to cartesian.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:23:<autosummary>:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.get_direction:1\nmsgid \"Returns the direction of the central axis of the cylinder.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Cylinder.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Cylinder.add_bases:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Dot3D.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:2\nmsgid \"Dot3D\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.Dot3D``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.three_dimensions.Sphere`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:1\nmsgid \"A spherical dot.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:3\nmsgid \"The location of the dot.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:5\nmsgid \"The radius of the dot.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:7\nmsgid \"The color of the :class:`Dot3D`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Dot3D:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Dot3D.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Line3D.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:2\nmsgid \"Line3D\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.Line3D``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.three_dimensions.Cylinder`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:1\nmsgid \"A cylindrical line, for use in ThreeDScene.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:4\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:9\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:0\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:0\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:15\nmsgid \"The start position of the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:17\nmsgid \"The end position of the line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D:19\nmsgid \"The thickness of the line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:25:<autosummary>:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1\nmsgid \"Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:25:<autosummary>:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_start:1\nmsgid \"Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:25:<autosummary>:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:1\nmsgid \"Returns a line parallel to another line going through a given point.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:25:<autosummary>:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:1\nmsgid \"Returns a line perpendicular to another line going through a given point.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:25:<autosummary>:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.set_start_and_end_attrs:1\nmsgid \"Sets the start and end points of the line.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Line3D.rst:27\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.get_end:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:4\nmsgid \"The line to be parallel to.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:5\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:5\nmsgid \"The point to pass through.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.parallel_to:6\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:6\nmsgid \"Additional parameters to be passed to the class.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Line3D.perpendicular_to:4\nmsgid \"The line to be perpendicular to.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Prism.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Prism.rst:2\nmsgid \"Prism\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Prism.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.Prism``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.three_dimensions.Cube`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism:1\nmsgid \"A cuboid.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Prism.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Prism.rst:20:<autosummary>:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Prism.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Prism.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Sphere.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:2\nmsgid \"Sphere\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.Sphere``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Sphere:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.three_dimensions.Surface`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Sphere:1\nmsgid \"A mobject representing a three-dimensional sphere.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Sphere:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:33:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:33:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:33:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Sphere.rst:33:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Surface.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Surface.rst:2\nmsgid \"Surface\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Surface.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.Surface``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:1\nmsgid \"Creates a Parametric Surface using a checkerboard pattern.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:0\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:3\nmsgid \"The function that defines the surface.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:4\nmsgid \"The range of the ``u`` variable: ``(u_min, u_max)``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:5\nmsgid \"The range of the ``v`` variable: ``(v_min, v_max)``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:6\nmsgid \"The number of samples taken of the surface. A tuple can be used to define different resolutions for ``u`` and ``v`` respectively.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:0\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface:11\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:12\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Surface.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Surface.rst:21:<autosummary>:1\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1\nmsgid \"Sets the color of each mobject of a parametric surface to a color relative to its axis-value\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Surface.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:3\nmsgid \"The axes for the parametric surface, which will be used to map axis-values to colors.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:4\nmsgid \"A list of colors, ordered from lower axis-values to higher axis-values. If a list of tuples is passed containing colors paired with numbers, then those numbers will be used as the pivots.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:6\nmsgid \"The chosen axis to use for the color mapping. (0 = x, 1 = y, 2 = z)\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Surface.set_fill_by_value:8\nmsgid \"The parametric surface with a gradient applied by value. For chaining.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:2\nmsgid \"ThreeDVMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.ThreeDVMobject``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.ThreeDVMobject:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.ThreeDVMobject.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.Torus.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:2\nmsgid \"Torus\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:4\nmsgid \"Qualified name: ``manim.mobject.three\\\\_d.three\\\\_dimensions.Torus``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:1\nmsgid \"Bases: :py:class:`manim.mobject.three_d.three_dimensions.Surface`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:1\nmsgid \"A torus.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:15\nmsgid \"Distance from the center of the tube to the center of the torus.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions.Torus:17\nmsgid \"Radius of the tube.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:33:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:33:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:33:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.Torus.rst:33:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d.three_dimensions.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:2\nmsgid \"three\\\\_dimensions\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/three_d/three_dimensions.py:docstring of manim.mobject.three_d.three_dimensions:1\nmsgid \"Three-dimensional mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40:<autosummary>:1\nmsgid \"An arrow made out of a cylindrical line and a conical tip.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40:<autosummary>:1\nmsgid \"A circular cone.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40:<autosummary>:1\nmsgid \"A cylinder, defined by its height, radius and direction,\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40:<autosummary>:1\nmsgid \"A spherical dot.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40:<autosummary>:1\nmsgid \"A cylindrical line, for use in ThreeDScene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40:<autosummary>:1\nmsgid \"A cuboid.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40:<autosummary>:1\nmsgid \"A mobject representing a three-dimensional sphere.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.three_d.three_dimensions.rst:40:<autosummary>:1\nmsgid \"Creates a Parametric Surface using a checkerboard pattern.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_d_utils.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.Arrow3D.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.Cone.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.Cube.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.Cylinder.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.Dot3D.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.Line3D.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.ParametricSurface.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.Prism.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.Sphere.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.Surface.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.ThreeDVMobject.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.Torus.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.three_dimensions.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.image_mobject.AbstractImageMobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:2\nmsgid \"AbstractImageMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.image\\\\_mobject.AbstractImageMobject``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject:1\nmsgid \"Bases: :py:class:`manim.mobject.mobject.Mobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject:1\nmsgid \"Automatically filters out black pixels\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject:0\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject:3\nmsgid \"At this resolution the image is placed pixel by pixel onto the screen, so it will look the sharpest and best. This is a custom parameter of ImageMobject so that rendering a scene with e.g. the ``--quality low`` or ``--quality medium`` flag for faster rendering won't effect the position of the image on the screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:23:<autosummary>:1\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.reset_points:1\nmsgid \"Sets :attr:`points` to be an empty array.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:23:<autosummary>:1\nmsgid \"Condition is function which takes in one arguments, (x, y, z).\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:23:<autosummary>:1\nmsgid \"Sets the interpolation method for upscaling the image.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.AbstractImageMobject.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.reset_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.reset_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.reset_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.reset_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_color:1\nmsgid \"Condition is function which takes in one arguments, (x, y, z). Here it just recurses to submobjects, but in subclasses this should be further implemented based on the the inner workings of color\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:1\nmsgid \"Sets the interpolation method for upscaling the image. By default the image is interpolated using bicubic algorithm. This method lets you change it. Interpolation is done internally using Pillow, and the function besides the string constants describing the algorithm accepts the Pillow integer constants.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:11\nmsgid \"* 'bicubic' or 'cubic' * 'nearest' or 'none' * 'box' * 'bilinear' or 'linear' * 'hamming' * 'lanczos' or 'antialias'\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:12\nmsgid \"'bicubic' or 'cubic'\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:13\nmsgid \"'nearest' or 'none'\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:14\nmsgid \"'box'\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:15\nmsgid \"'bilinear' or 'linear'\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.AbstractImageMobject.set_resampling_algorithm:16\nmsgid \"'hamming'\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.image_mobject.ImageMobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:2\nmsgid \"ImageMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.image\\\\_mobject.ImageMobject``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:1\nmsgid \"Bases: :py:class:`manim.mobject.types.image_mobject.AbstractImageMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:1\nmsgid \"Displays an Image from a numpy array or a file.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:0\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:0\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.interpolate_color:0\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.set_opacity:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:3\nmsgid \"At this resolution the image is placed pixel by pixel onto the screen, so it will look the sharpest and best. This is a custom parameter of ImageMobject so that rendering a scene with e.g. the ``--quality low`` or ``--quality medium`` flag for faster rendering won't effect the position of the image on the screen.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:11\nmsgid \"Example\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject:22\nmsgid \"Changing interpolation style:\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:25:<autosummary>:1\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:1\nmsgid \"Sets the image's opacity using a 1 - alpha relationship.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:25:<autosummary>:1\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.get_pixel_array:1\nmsgid \"A simple getter method.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:25:<autosummary>:1\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.interpolate_color:1\nmsgid \"Interpolates an array of pixel color values into another array of equal size.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:25:<autosummary>:1\nmsgid \"Condition is function which takes in one arguments, (x, y, z).\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:25:<autosummary>:1\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.set_opacity:1\nmsgid \"Sets the image's opacity.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobject.rst:27\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:3\nmsgid \"The alpha value of the object, 1 being transparent and 0 being opaque.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.fade:6\nmsgid \"Whether the submobjects of the ImageMobject should be affected.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.interpolate_color:4\nmsgid \"The ImageMobject to transform from.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.interpolate_color:6\nmsgid \"The ImageMobject to transform into.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.interpolate_color:8\nmsgid \"Used to track the lerp relationship. Not opacity related.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobject.set_color:1\nmsgid \"Condition is function which takes in one arguments, (x, y, z). Here it just recurses to submobjects, but in subclasses this should be further implemented based on the the inner workings of color\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:2\nmsgid \"ImageMobjectFromCamera\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.image\\\\_mobject.ImageMobjectFromCamera``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject.ImageMobjectFromCamera:1\nmsgid \"Bases: :py:class:`manim.mobject.types.image_mobject.AbstractImageMobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:31:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:31:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.ImageMobjectFromCamera.rst:31:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.image_mobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.rst:2\nmsgid \"image\\\\_mobject\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/image_mobject.py:docstring of manim.mobject.types.image_mobject:1\nmsgid \"Mobjects representing raster images.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.rst:24:<autosummary>:1\nmsgid \"Automatically filters out black pixels\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.image_mobject.rst:24:<autosummary>:1\nmsgid \"Displays an Image from a numpy array or a file.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:2\nmsgid \"Mobject1D\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.point\\\\_cloud\\\\_mobject.Mobject1D``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Mobject1D:1\nmsgid \"Bases: :py:class:`manim.mobject.types.point_cloud_mobject.PMobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:29:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:29:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject1D.rst:29:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:2\nmsgid \"Mobject2D\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.point\\\\_cloud\\\\_mobject.Mobject2D``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Mobject2D:1\nmsgid \"Bases: :py:class:`manim.mobject.types.point_cloud_mobject.PMobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:28:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:28:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Mobject2D.rst:28:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.PGroup.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:2\nmsgid \"PGroup\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.point\\\\_cloud\\\\_mobject.PGroup``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PGroup:1\nmsgid \"Bases: :py:class:`manim.mobject.types.point_cloud_mobject.PMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PGroup:2\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:29:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:29:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PGroup.rst:29:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.PMobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:2\nmsgid \"PMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.point\\\\_cloud\\\\_mobject.PMobject``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject:1\nmsgid \"Bases: :py:class:`manim.mobject.mobject.Mobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject:1\nmsgid \"A disc made of a cloud of Dots\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40:<autosummary>:1\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:1\nmsgid \"Add points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40:<autosummary>:1\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.get_color:1\nmsgid \"Returns the color of the :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40:<autosummary>:1\nmsgid \"The simplest :class:`~.Mobject` to be transformed to or from self.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40:<autosummary>:1\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.reset_points:1\nmsgid \"Sets :attr:`points` to be an empty array.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40:<autosummary>:1\nmsgid \"Condition is function which takes in one arguments, (x, y, z).\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40:<autosummary>:1\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.sort_points:1\nmsgid \"Function is any map from R^3 to R\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:40:<autosummary>:1\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.thin_out:1\nmsgid \"Removes all but every nth point for n = factor\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PMobject.rst:42\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.add_points:3\nmsgid \"Points must be a Nx3 numpy array. Rgbas must be a Nx4 numpy array if it is not None.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PMobject.get_point_mobject:1\nmsgid \"The simplest :class:`~.Mobject` to be transformed to or from self. Should by a point of the appropriate type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.Point.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Point.rst:2\nmsgid \"Point\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Point.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.point\\\\_cloud\\\\_mobject.Point``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point:1\nmsgid \"Bases: :py:class:`manim.mobject.types.point_cloud_mobject.PMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point:2\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Point.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Point.rst:21:<autosummary>:1\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.Point.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.Point.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.rst:2\nmsgid \"PointCloudDot\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.point\\\\_cloud\\\\_mobject.PointCloudDot``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot:1\nmsgid \"Bases: :py:class:`manim.mobject.types.point_cloud_mobject.Mobject1D`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot:1\nmsgid \"A disc made of a cloud of Dots .. rubric:: Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.rst:21:<autosummary>:1\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot.generate_points:1\nmsgid \"Initializes :attr:`points` and therefore the shape.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.PointCloudDot.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot.generate_points:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot.generate_points:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot.generate_points:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject.PointCloudDot.generate_points:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.point_cloud_mobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.rst:2\nmsgid \"point\\\\_cloud\\\\_mobject\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/point_cloud_mobject.py:docstring of manim.mobject.types.point_cloud_mobject:1\nmsgid \"Mobjects representing point clouds.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.rst:30:<autosummary>:0\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.rst:30:<autosummary>:0\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.point_cloud_mobject.rst:30:<autosummary>:1\nmsgid \"A disc made of a cloud of Dots\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.rst:2\nmsgid \"types\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/__init__.py:docstring of manim.mobject.types:1\nmsgid \"Specialized mobject base classes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/__init__.py:docstring of manim.mobject.types:4\nmsgid \"Modules\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/__init__.py:docstring of manim.mobject.types:12:<autosummary>:1\nmsgid \"Mobjects representing raster images.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/__init__.py:docstring of manim.mobject.types:12:<autosummary>:1\nmsgid \"Mobjects representing point clouds.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:2\nmsgid \"CurvesAsSubmobjects\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.vectorized\\\\_mobject.CurvesAsSubmobjects``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects:1\nmsgid \"Convert a curve's elements to submobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.CurvesAsSubmobjects.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:2\nmsgid \"DashedVMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.vectorized\\\\_mobject.DashedVMobject``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:1\nmsgid \"A :class:`VMobject` composed of dashes instead of lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:3\nmsgid \"The object that will get dashed\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:4\nmsgid \"Number of dashes to add.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:5\nmsgid \"Ratio of dash to empty space.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:6\nmsgid \"Shifts the starting point of dashes along the path. Value 1 shifts by one full dash length.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:8\nmsgid \"If ``True``, dashes will be (approximately) equally long. If ``False``, dashes will be split evenly in the curve's input t variable (legacy behavior).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.DashedVMobject:13\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:32:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:32:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:32:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.DashedVMobject.rst:32:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.VDict.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:2\nmsgid \"VDict\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.vectorized\\\\_mobject.VDict``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:1\nmsgid \"A VGroup-like class, also offering submobject access by key, like a python dict\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:4\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:6\nmsgid \"The parameter specifying the key-value mapping of keys and mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:6\nmsgid \"Whether to also display the key associated with the mobject. This might be useful when debugging, especially when there are a lot of mobjects in the :class:`VDict`. Defaults to False.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:11\nmsgid \"Other arguments to be passed to `Mobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:16\nmsgid \"Whether to also display the key associated with the mobject. This might be useful when debugging, especially when there are a lot of mobjects in the :class:`VDict`. When displayed, the key is towards the left of the mobject. Defaults to False.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:0\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:27\nmsgid \"Is the actual python dictionary that is used to bind the keys to the mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict:33\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:13\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:14\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:7\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:13\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:23:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1\nmsgid \"Adds the key-value pairs to the :class:`VDict` object.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:23:<autosummary>:1\nmsgid \"A utility function used by :meth:`add` to add the key-value pair to :attr:`submob_dict`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:23:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:1\nmsgid \"To get all the submobjects associated with a particular :class:`VDict` object\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:23:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:1\nmsgid \"Removes the mobject from the :class:`VDict` object having the key `key`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VDict.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:3\nmsgid \"Also, it internally adds the value to the `submobjects` :class:`list` of :class:`~.Mobject`, which is responsible for actual on-screen display.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:9\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:9\nmsgid \"Returns the :class:`VDict` object on which this method was called.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add:14\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:15\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:8\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:14\nmsgid \"Normal usage::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:1\nmsgid \"A utility function used by :meth:`add` to add the key-value pair to :attr:`submob_dict`. Not really meant to be used externally.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:4\nmsgid \"The key of the submobject to be added.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:6\nmsgid \"The mobject associated with the key\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.add_key_value_pair:11\nmsgid \"If the value is not an instance of VMobject\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.get_all_submobjects:3\nmsgid \"All the submobjects associated with the :class:`VDict` object\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VDict.remove:3\nmsgid \"Also, it internally removes the mobject from the `submobjects` :class:`list` of :class:`~.Mobject`, (which is responsible for removing it from the screen)\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.VGroup.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VGroup.rst:2\nmsgid \"VGroup\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VGroup.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.vectorized\\\\_mobject.VGroup``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:1\nmsgid \"A group of vectorized mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:3\nmsgid \"This can be used to group multiple :class:`~.VMobject` instances together in order to scale, move, ... them together.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:7\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:8\nmsgid \"When adding the same mobject more than once, repetitions are ignored. Use :meth:`.Mobject.copy` to create a separate copy which can then be added to the group.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:13\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:11\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup:14\nmsgid \"To add :class:`~.VMobject`s to a :class:`~.VGroup`, you can either use the :meth:`~.VGroup.add` method, or use the `+` and `+=` operators. Similarly, you can subtract elements of a VGroup via :meth:`~.VGroup.remove` method, or `-` and `-=` operators:\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VGroup.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VGroup.rst:20:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1\nmsgid \"Checks if all passed elements are an instance of VMobject and then add them to submobjects\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VGroup.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:3\nmsgid \"List of VMobject to add\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VGroup.add:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.VMobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:2\nmsgid \"VMobject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.vectorized\\\\_mobject.VMobject``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1\nmsgid \"Bases: :py:class:`manim.mobject.mobject.Mobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1\nmsgid \"A vectorized mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_quadratic_bezier_curve_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.force_direction:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen_direction:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:3\nmsgid \"The purpose of background stroke is to have something that won't overlap fill, e.g.  For text against some textured background.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:6\nmsgid \"When a color c is set, there will be a second color computed based on interpolating c to WHITE by with sheen_factor, and the display will gradient to this secondary color in the direction of sheen_direction.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:10\nmsgid \"Indicates that it will not be displayed, but that it should count in parent mobject's path\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:12\nmsgid \"This is within a pixel\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1\nmsgid \"Add cubic bezier curve to the path.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:1\nmsgid \"Add a straight line from the last point of VMobject to the given point.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_quadratic_bezier_curve_to:1\nmsgid \"Add Quadratic bezier curve to the path.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\nmsgid \"Creates a smooth curve from given points and add it to the VMobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:1\nmsgid \"Adds points to self and vmobject so that they both have the same number of subpaths, with corresponding subpaths each containing the same number of points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\nmsgid \"Changes the anchor mode of the bezier curves.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:1\nmsgid \"Determine if two points are close enough to be considered equal.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.force_direction:1\nmsgid \"Makes sure that points are either directed clockwise or counterclockwise.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:1\nmsgid \"Returns the bezier tuples from an array of points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\nmsgid \"First arg can be either a color, or a tuple/list of colors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors:1\nmsgid \"Returns the anchors of the curves forming the VMobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors_and_handles:1\nmsgid \"Returns anchors1, handles1, handles2, anchors2, where (anchors1[i], handles1[i], handles2[i], anchors2[i]) will be four points defining a cubic bezier curve for any i in range(0, len(anchors1))\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:1\nmsgid \"Return the approximated length of the whole curve.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_color:1\nmsgid \"Returns the color of the :class:`~.Mobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions:1\nmsgid \"Gets the functions for the curves of the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:1\nmsgid \"Gets the functions and lengths of the curves for the mobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\nmsgid \"Uses :func:`~.space_ops.shoelace_direction` to calculate the direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_end_anchors:1\nmsgid \"Return the end anchors of the bezier curves.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.fill_color:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_fill_color:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_fill_opacity:1\nmsgid \"If there are multiple opacities, this returns the first\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:1\nmsgid \"Returns the expression of the nth curve.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:1\nmsgid \"Returns the expression of the nth curve along with its (approximate) length.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:1\nmsgid \"Returns the (approximate) length of the nth curve.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:1\nmsgid \"Returns the array of short line lengths used for length approximation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:1\nmsgid \"Returns the points defining the nth curve of the vmobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_num_curves:1\nmsgid \"Returns the number of curves of the vmobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\nmsgid \"The simplest :class:`~.Mobject` to be transformed to or from self.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_start_anchors:1\nmsgid \"Returns the start anchors of the bezier curves.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\nmsgid \"Returns the subcurve of the VMobject between the interval [a, b].\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subpaths:1\nmsgid \"Returns subpaths formed by the curves of the VMobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.init_colors:1\nmsgid \"Initializes the colors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:1\nmsgid \"Inserts n curves to the bezier curves of the vmobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:1\nmsgid \"Given an array of k points defining a bezier curves (anchors and handles), returns points defining exactly k + n bezier curves.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:1\nmsgid \"Gets the point at a proportion along the path of the :class:`VMobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\nmsgid \"Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject passed as parameter with respect to the bounds.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:1\nmsgid \"Returns the proportion along the path of the :class:`VMobject` a particular given point is at.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.reverse_direction:1\nmsgid \"Reverts the point direction by inverting the point order.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate:1\nmsgid \"Rotates the :class:`~.Mobject` about a certain point.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:1\nmsgid \"Rotates the direction of the applied sheen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\nmsgid \"If the distance between a given handle point H and its associated anchor point A is d, then it changes H to be a distances factor*d away from A, but so that the line from A to H doesn't change.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:1\nmsgid \"Given two sets of anchors and handles, process them to set them as anchors and handles of the VMobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\nmsgid \"Condition is function which takes in one arguments, (x, y, z).\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:1\nmsgid \"Set the fill color and fill opacity of a :class:`VMobject`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:1\nmsgid \"Given an array of points, set them as corner of the vmobject.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen:1\nmsgid \"Applies a color gradient from a direction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:114:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen_direction:1\nmsgid \"Sets the direction of the applied sheen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VMobject.rst:116\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:3\nmsgid \"NOTE : the first anchor is not a parameter as by default the end of the last sub-path!\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:5\nmsgid \"first handle\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:7\nmsgid \"second handle\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:9\nmsgid \"anchor\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_quadratic_bezier_curve_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors_and_handles:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_end_anchors:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_num_curves:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_start_anchors:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subpaths:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.reverse_direction:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:12\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:6\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_quadratic_bezier_curve_to:3\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:7\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:9\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:5\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:5\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:11\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:11\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:9\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:7\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:9\nmsgid \"``self``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_cubic_bezier_curve_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_quadratic_bezier_curve_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors_and_handles:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_end_anchors:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_num_curves:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_start_anchors:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subpaths:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.reverse_direction:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_line_to:3\nmsgid \"end of the straight line.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:1\nmsgid \"Creates a smooth curve from given points and add it to the VMobject. If two points are passed in, the first is interpreted as a handle, the second as an anchor.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:4\nmsgid \"Points (anchor and handle, or just anchor) to add a smooth curve from\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.add_smooth_curve_to:10\nmsgid \"If 0 or more than 2 points are given.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:4\nmsgid \"Points are added either by subdividing curves evenly along the subpath, or by creating new subpaths consisting of a single point repeated.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.align_points:7\nmsgid \"The object to align points with.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:1\nmsgid \"Changes the anchor mode of the bezier curves. This will modify the handles.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.change_anchor_mode:3\nmsgid \"There can be only two modes, \\\"jagged\\\", and \\\"smooth\\\".\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:3\nmsgid \"This uses the algorithm from np.isclose(), but expanded here for the 2D point case. NumPy is overkill for such a small question. :param p0: first point :type p0: np.ndarray :param p1: second point :type p1: np.ndarray\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.consider_points_equals_2d:10\nmsgid \"whether two points considered close.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.force_direction:4\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:13\nmsgid \"Either ``\\\"CW\\\"`` or ``\\\"CCW\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:3\nmsgid \"self.points is a list of the anchors and handles of the bezier curves of the mobject (ie [anchor1, handle1, handle2, anchor2, anchor3 ..]) This algorithm basically retrieve them by taking an element every n, where n is the number of control points of the bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:8\nmsgid \"Points from which control points will be extracted.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.gen_cubic_bezier_tuples_from_points:11\nmsgid \"Bezier control points.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.generate_rgbas_array:1\nmsgid \"First arg can be either a color, or a tuple/list of colors. Likewise, opacity can either be a float, or a tuple of floats. If self.sheen_factor is not zero, and only one color was passed in, a second slightly light color will automatically be added for the gradient\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors:3\nmsgid \"The anchors.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_anchors_and_handles:6\nmsgid \"Iterable of the anchors and handles.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:3\nmsgid \"Number of sample points per curve used to approximate the length. More points result in a better approximation.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_arc_length:5\nmsgid \"The length of the :class:`VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions:3\nmsgid \"The functions for the curves.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:3\nmsgid \"The keyword arguments passed to :meth:`get_nth_curve_function_with_length`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_curve_functions_with_lengths:5\nmsgid \"The functions and lengths of the curves.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:1\nmsgid \"Uses :func:`~.space_ops.shoelace_direction` to calculate the direction. The direction of points determines in which direction the object is drawn, clockwise or counterclockwise.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:6\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.reverse_direction:7\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:9\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:11\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen:11\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen_direction:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_direction:7\nmsgid \"The default direction of a :class:`~.Circle` is counterclockwise::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_end_anchors:3\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_start_anchors:3\nmsgid \"Starting anchors\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:3\nmsgid \"index of the desired curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function:6\nmsgid \"expression of the nth bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:3\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:3\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:3\nmsgid \"The index of the desired curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:4\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:4\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:4\nmsgid \"The number of points to sample to find the length.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:6\nmsgid \"* **curve** (*typing.Callable[[float], np.ndarray]*) -- The function for the nth curve. * **length** (:class:`float`) -- The length of the nth curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:6\nmsgid \"**curve** (*typing.Callable[[float], np.ndarray]*) -- The function for the nth curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_function_with_length:7\nmsgid \"**length** (:class:`float`) -- The length of the nth curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length:6\nmsgid \"**length** -- The length of the nth curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_length_pieces:6\nmsgid \"The short length-pieces of the nth curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:3\nmsgid \"index of the desired bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_nth_curve_points:6\nmsgid \"points defininf the nth bezier curve (anchors, handles)\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_num_curves:3\nmsgid \"number of curves. of the vmobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_point_mobject:1\nmsgid \"The simplest :class:`~.Mobject` to be transformed to or from self. Should by a point of the appropriate type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:1\nmsgid \"Returns the subcurve of the VMobject between the interval [a, b]. The curve is a VMobject itself.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:4\nmsgid \"The lower bound.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:5\nmsgid \"The upper bound.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subcurve:7\nmsgid \"The subcurve between of [a, b]\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subpaths:3\nmsgid \"Subpaths are ranges of curves with each pair of consecutive curves having their end/start points coincident.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.get_subpaths:5\nmsgid \"subpaths.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.init_colors:3\nmsgid \"Gets called upon creation. This is an empty method that can be implemented by subclasses.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves:3\nmsgid \"Number of curves to insert.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:3\nmsgid \"Number of desired curves.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:5\nmsgid \"Starting points.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.insert_n_curves_to_point_list:8\nmsgid \"Points generated.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:3\nmsgid \"The proportion along the the path of the :class:`VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:5\nmsgid \"The point on the :class:`VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:8\nmsgid \"If ``alpha`` is not between 0 and 1.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.point_from_proportion:9\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:10\nmsgid \"If the :class:`VMobject` has no points.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:1\nmsgid \"Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject passed as parameter with respect to the bounds. Points here stand for control points of the bezier curves (anchors and handles)\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:4\nmsgid \"The vmobject that will serve as a model.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:6\nmsgid \"upper-bound.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.pointwise_become_partial:8\nmsgid \"lower-bound\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:4\nmsgid \"The Cartesian coordinates of the point which may or may not lie on the :class:`VMobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:6\nmsgid \"The proportion along the path of the :class:`VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.proportion_from_point:9\nmsgid \"If ``point`` does not lie on the curve.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.reverse_direction:3\nmsgid \"Returns self.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:3\nmsgid \"Angle by which the direction of sheen is rotated.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:5\nmsgid \"Axis of rotation.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.rotate_sheen_direction:10\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen_direction:8\nmsgid \"Normal usage::\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:1\nmsgid \"If the distance between a given handle point H and its associated anchor point A is d, then it changes H to be a distances factor*d away from A, but so that the line from A to H doesn't change. This is mostly useful in the context of applying a (differentiable) function, to preserve tangency properties.  One would pull all the handles closer to their anchors, apply the function then push them out again.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.scale_handle_to_anchor_distances:9\nmsgid \"The factor used for scaling.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_anchors_and_handles:4\nmsgid \"anchors1[i], handles1[i], handles2[i] and anchors2[i] define the i-th bezier curve of the vmobject. There are four hardcoded parameters and this is a problem as it makes the number of points per cubic curve unchangeable from 4 (two anchors and two handles).\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_color:1\nmsgid \"Condition is function which takes in one arguments, (x, y, z). Here it just recurses to submobjects, but in subclasses this should be further implemented based on the the inner workings of color\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:3\nmsgid \"Fill color of the :class:`VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:4\nmsgid \"Fill opacity of the :class:`VMobject`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_fill:5\nmsgid \"If ``True``, the fill color of all submobjects is also set.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:3\nmsgid \"To achieve that, this algorithm sets handles aligned with the anchors such that the resultant bezier curve will be the segment between the two anchors.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_points_as_corners:6\nmsgid \"Array of points that will be set as corners.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen:3\nmsgid \"The extent of lustre/gradient to apply. If negative, the gradient starts from black, if positive the gradient starts from white and changes to the current color.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen:7\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject.set_sheen_direction:3\nmsgid \"Direction from where the gradient is applied.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.VectorizedPoint.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VectorizedPoint.rst:2\nmsgid \"VectorizedPoint\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VectorizedPoint.rst:4\nmsgid \"Qualified name: ``manim.mobject.types.vectorized\\\\_mobject.VectorizedPoint``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VMobject`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VectorizedPoint.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.VectorizedPoint.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.height:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VMobject:1:<autosummary>:1\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.width:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.height:0\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.width:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.height:6\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject.VectorizedPoint.width:6\nmsgid \"Examples\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.types.vectorized_mobject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:2\nmsgid \"vectorized\\\\_mobject\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/types/vectorized_mobject.py:docstring of manim.mobject.types.vectorized_mobject:1\nmsgid \"Mobjects that use vector graphics.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:30:<autosummary>:1\nmsgid \"Convert a curve's elements to submobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:30:<autosummary>:1\nmsgid \"A :class:`VMobject` composed of dashes instead of lines.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:30:<autosummary>:1\nmsgid \"A VGroup-like class, also offering submobject access by key, like a python dict\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:30:<autosummary>:1\nmsgid \"A group of vectorized mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.types.vectorized_mobject.rst:30:<autosummary>:1\nmsgid \"A vectorized mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.value_tracker.ComplexValueTracker.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:2\nmsgid \"ComplexValueTracker\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:4\nmsgid \"Qualified name: ``manim.mobject.value\\\\_tracker.ComplexValueTracker``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker:1\nmsgid \"Bases: :py:class:`manim.mobject.value_tracker.ValueTracker`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker:1\nmsgid \"Tracks a complex-valued parameter.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker:3\nmsgid \"When the value is set through :attr:`animate`, the value will take a straight path from the source point to the destination point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:21:<autosummary>:1\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.get_value:1\nmsgid \"Get the current value of this value tracker as a complex number.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:21:<autosummary>:1\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.set_value:1\nmsgid \"Sets a new complex value to the ComplexValueTracker\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ComplexValueTracker.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.get_value:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.get_value:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.get_value:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ComplexValueTracker.get_value:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.value_tracker.ValueTracker.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:2\nmsgid \"ValueTracker\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:4\nmsgid \"Qualified name: ``manim.mobject.value\\\\_tracker.ValueTracker``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:1\nmsgid \"Bases: :py:class:`manim.mobject.mobject.Mobject`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:1\nmsgid \"A mobject that can be used for tracking (real-valued) parameters. Useful for animating parameter changes.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:4\nmsgid \"Not meant to be displayed.  Instead the position encodes some number, often one which another animation or continual_animation uses for its update function, and by treating it as a mobject it can still be animated and manipulated just like anything else.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:9\nmsgid \"This value changes continuously when animated using the :attr:`animate` syntax.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:12\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker:41\nmsgid \"You can also link ValueTrackers to updaters. In this case, you have to make sure that the ValueTracker is added to the scene by ``add``\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:23:<autosummary>:1\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:1\nmsgid \"Get the current value of this ValueTracker.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:23:<autosummary>:1\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.increment_value:1\nmsgid \"Increments (adds) a scalar value  to the ValueTracker\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:23:<autosummary>:1\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.interpolate:1\nmsgid \"Turns self into an interpolation between mobject1 and mobject2.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:23:<autosummary>:1\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.set_value:1\nmsgid \"Sets a new scalar value to the ValueTracker\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.ValueTracker.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker.ValueTracker.get_value:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.value_tracker.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.value_tracker.rst:2\nmsgid \"value\\\\_tracker\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/value_tracker.py:docstring of manim.mobject.value_tracker:1\nmsgid \"Simple mobjects that can be used for storing (and updating) a value.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.value_tracker.rst:22:<autosummary>:1\nmsgid \"Tracks a complex-valued parameter.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.vector_field.ArrowVectorField.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.vector_field.ArrowVectorField.rst:2\nmsgid \"ArrowVectorField\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.ArrowVectorField.rst:4\nmsgid \"Qualified name: ``manim.mobject.vector\\\\_field.ArrowVectorField``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:1\nmsgid \"Bases: :py:class:`manim.mobject.vector_field.VectorField`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:1\nmsgid \"A :class:`VectorField` represented by a set of change vectors.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:3\nmsgid \"Vector fields are always based on a function defining the :class:`~.Vector` at every position. The values of this functions is displayed as a grid of vectors. By default the color of each vector is determined by it's magnitude. Other color schemes can be used however.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:8\nmsgid \"The function defining the rate of change at every position of the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:9\nmsgid \"The color of the vector field. If set, position-specific coloring is disabled.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:10\nmsgid \"A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:11\nmsgid \"The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:12\nmsgid \"The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:13\nmsgid \"The colors defining the color gradient of the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:14\nmsgid \"A sequence of x_min, x_max, delta_x\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:15\nmsgid \"A sequence of y_min, y_max, delta_y\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:16\nmsgid \"A sequence of z_min, z_max, delta_z\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:17\nmsgid \"Enables three_dimensions. Default set to False, automatically turns True if z_range is not None.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:19\nmsgid \"The function determining the displayed size of the vectors. The actual size of the vector is passed, the returned value will be used as display size for the vector. By default this is used to cap the displayed size of vectors to reduce the clutter.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:22\nmsgid \"The opacity of the arrows.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:23\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:8\nmsgid \"Additional arguments to be passed to the :class:`~.Vector` constructor\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:24\nmsgid \"Additional arguments to be passed to the :class:`~.VGroup` constructor\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField:28\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.ArrowVectorField.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.ArrowVectorField.rst:20:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1\nmsgid \"Creates a vector in the vector field.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.ArrowVectorField.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.ArrowVectorField.get_vector:3\nmsgid \"The created vector is based on the function of the vector field and is rooted in the given point. Color and length fit the specifications of this vector field.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.vector_field.StreamLines.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:2\nmsgid \"StreamLines\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:4\nmsgid \"Qualified name: ``manim.mobject.vector\\\\_field.StreamLines``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:1\nmsgid \"Bases: :py:class:`manim.mobject.vector_field.VectorField`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:1\nmsgid \"StreamLines represent the flow of a :class:`VectorField` using the trace of moving agents.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:3\nmsgid \"Vector fields are always based on a function defining the vector at every position. The values of this functions is displayed by moving many agents along the vector field and showing their trace.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:7\nmsgid \"The function defining the rate of change at every position of the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:8\nmsgid \"The color of the vector field. If set, position-specific coloring is disabled.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:9\nmsgid \"A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:10\nmsgid \"The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:11\nmsgid \"The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:12\nmsgid \"The colors defining the color gradient of the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:13\nmsgid \"A sequence of x_min, x_max, delta_x\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:14\nmsgid \"A sequence of y_min, y_max, delta_y\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:15\nmsgid \"A sequence of z_min, z_max, delta_z\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:16\nmsgid \"Enables three_dimensions. Default set to False, automatically turns True if z_range is not None.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:18\nmsgid \"The amount by which the starting position of each agent is altered along each axis. Defaults to :code:`delta_y / 2` if not defined.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:19\nmsgid \"The number of agents generated at each starting point.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:20\nmsgid \"The factor by which the distance an agent moves per step is stretched. Lower values result in a better approximation of the trajectories in the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:21\nmsgid \"The time the agents get to move in the vector field. Higher values therefore result in longer stream lines. However, this whole time gets simulated upon creation.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:22\nmsgid \"The maximum number of anchors per line. Lines with more anchors get reduced in complexity, not in length.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:23\nmsgid \"The distance agents can move out of the generation area before being terminated.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:24\nmsgid \"The stroke with of the stream lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:25\nmsgid \"The opacity of the stream lines.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines:28\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:14\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:11\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:13\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:22:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:10\nmsgid \"The creation animation of the stream lines.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:22:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:1\nmsgid \"End the stream line animation smoothly.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:22:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:1\nmsgid \"Animates the stream lines using an updater.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.StreamLines.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:3\nmsgid \"The stream lines appear in random order.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:5\nmsgid \"The lag ratio of the animation. If undefined, it will be selected so that the total animation length is 1.5 times the run time of each stream line creation.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:7\nmsgid \"The run time of every single stream line creation. The runtime of the whole animation might be longer due to the `lag_ratio`. If undefined, the virtual time of the stream lines is used as run time.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.create:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:3\nmsgid \"Returns an animation resulting in fully displayed stream lines without a noticeable cut.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:5\nmsgid \"The animation fading out the running stream animation.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.end_animation:8\nmsgid \"if no stream line animation is running\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:3\nmsgid \"The stream lines will continuously flow\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:5\nmsgid \"If `True` the animation is initialized line by line. Otherwise it starts with all lines shown.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:7\nmsgid \"At `flow_speed=1` the distance the flow moves per second is equal to the magnitude of the vector field along its path. The speed value scales the speed of this flow.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:8\nmsgid \"The proportion of the stream line shown while being animated\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.StreamLines.start_animation:9\nmsgid \"The rate function of each stream line flashing\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.vector_field.VectorField.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:2\nmsgid \"VectorField\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:4\nmsgid \"Qualified name: ``manim.mobject.vector\\\\_field.VectorField``\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:1\nmsgid \"Bases: :py:class:`manim.mobject.types.vectorized_mobject.VGroup`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:1\nmsgid \"A vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:3\nmsgid \"Vector fields are based on a function defining a vector at every position. This class does by default not include any visible elements but provides methods to move other :class:`~.Mobject` s along the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:7\nmsgid \"The function defining the rate of change at every position of the `VectorField`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:8\nmsgid \"The color of the vector field. If set, position-specific coloring is disabled.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:9\nmsgid \"A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:10\nmsgid \"The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:11\nmsgid \"The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:12\nmsgid \"The colors defining the color gradient of the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField:13\nmsgid \"Additional arguments to be passed to the :class:`~.VGroup` constructor\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1\nmsgid \"Scale the vector field to fit a coordinate system.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:1\nmsgid \"Generate an image that displays the vector field.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:1\nmsgid \"Get an update function to move a :class:`~.Mobject` along the vector field.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:1\nmsgid \"Generates a gradient of rgbas as a numpy array\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:1\nmsgid \"Nudge a :class:`~.Mobject` along the vector field.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:1\nmsgid \"Apply a nudge along the vector field to all submobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:1\nmsgid \"Scale a vector field function.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:1\nmsgid \"Shift a vector field function.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:1\nmsgid \"Start continuously moving all submobjects along the vector field.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:29:<autosummary>:1\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.stop_submobject_movement:1\nmsgid \"Stops the continuous movement started using :meth:`start_submobject_movement`.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.VectorField.rst:31\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1:<autosummary>:1\nmsgid \"Used to animate the application of any method of :code:`self`.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1:<autosummary>:1\nmsgid \"The depth of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1:<autosummary>:1\nmsgid \"If there are multiple colors (for gradient) this returns the first one\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1:<autosummary>:1\nmsgid \"The height of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:1:<autosummary>:1\nmsgid \"The width of the mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:3\nmsgid \"This method is useful when the vector field is defined in a coordinate system different from the one used to display the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:6\nmsgid \"This method can only be used once because it transforms the origin of each vector.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.fit_to_coordinate_system:8\nmsgid \"The coordinate system to fit the vector field to.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:3\nmsgid \"The color at each position is calculated by passing the positing through a series of steps: Calculate the vector field function at that position, map that vector to a single value using `self.color_scheme` and finally generate a color from that value using the color gradient.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:9\nmsgid \"The stepsize at which pixels get included in the image. Lower values give more accurate results, but may take a long time to compute.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.stop_submobject_movement:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:12\nmsgid \"The vector field image.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_colored_background_image:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:0\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.stop_submobject_movement:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:3\nmsgid \"When used with :meth:`~.Mobject.add_updater`, the mobject will move along the vector field, where its speed is determined by the magnitude of the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:5\nmsgid \"At `speed=1` the distance a mobject moves per second is equal to the magnitude of the vector field along its path. The speed value scales the speed of such a mobject.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:6\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:7\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:6\nmsgid \"Whether to move the mobject along the vector field. See :meth:`nudge` for details.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_nudge_updater:8\nmsgid \"The update function.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:3\nmsgid \"start value used for inverse interpolation at :func:`~.inverse_interpolate`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:4\nmsgid \"end value used for inverse interpolation at :func:`~.inverse_interpolate`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.get_vectorized_rgba_gradient_function:5\nmsgid \"list of colors to generate the gradient\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:3\nmsgid \"The mobject to move along the vector field\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:4\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:3\nmsgid \"A scalar to the amount the mobject is moved along the vector field. The actual distance is based on the magnitude of the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:6\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:5\nmsgid \"The amount of steps the whole nudge is divided into. Higher values give more accurate approximations.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:8\nmsgid \"Whether to move the mobject along the vector field. If `False` the vector field takes effect on the center of the given :class:`~.Mobject`. If `True` the vector field takes effect on the points of the individual points of the :class:`~.Mobject`, potentially distorting it.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:14\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge_submobjects:9\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:8\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.stop_submobject_movement:3\nmsgid \"This vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.nudge:18\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:3\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:3\nmsgid \"The function defining a vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:4\nmsgid \"The scalar to be applied to the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:21\nmsgid \"The scaled vector field function.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.scale_func:22\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:7\nmsgid \"`Callable[[np.ndarray], np.ndarray]`\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:4\nmsgid \"The shift to be applied to the vector field.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.shift_func:6\nmsgid \"The shifted vector field function.\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field.VectorField.start_submobject_movement:3\nmsgid \"Calling this method multiple times will result in removing the previous updater created by this method.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.mobject.vector_field.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.mobject.vector_field.rst:2\nmsgid \"vector\\\\_field\"\nmsgstr \"\"\n\n#: ../../../manim/mobject/vector_field.py:docstring of manim.mobject.vector_field:1\nmsgid \"Mobjects representing vector fields.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.rst:24:<autosummary>:1\nmsgid \"A :class:`VectorField` represented by a set of change vectors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.mobject.vector_field.rst:24:<autosummary>:1\nmsgid \"StreamLines represent the flow of a :class:`VectorField` using the trace of moving agents.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.moving_camera_scene.MovingCameraScene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.moving_camera_scene.MovingCameraScene.rst:2\nmsgid \"MovingCameraScene\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.moving_camera_scene.MovingCameraScene.rst:4\nmsgid \"Qualified name: ``manim.scene.moving\\\\_camera\\\\_scene.MovingCameraScene``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene.MovingCameraScene:1\nmsgid \"Bases: :py:class:`manim.scene.scene.Scene`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene.MovingCameraScene:1\nmsgid \"This is a Scene, with special configurations and properties that make it suitable for cases where the camera must be moved around.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.moving_camera_scene.MovingCameraScene.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.moving_camera_scene.MovingCameraScene.rst:20:<autosummary>:1\n#: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene.MovingCameraScene.get_moving_mobjects:1\nmsgid \"This method returns a list of all of the Mobjects in the Scene that are moving, that are also in the animations passed.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.moving_camera_scene.MovingCameraScene.rst:22\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene.MovingCameraScene.get_moving_mobjects:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.moving_camera_scene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.moving_camera_scene.rst:2\nmsgid \"moving\\\\_camera\\\\_scene\"\nmsgstr \"\"\n\n#: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene:1\nmsgid \"A scene whose camera can be moved around.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/moving_camera_scene.py:docstring of manim.scene.moving_camera_scene:9\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.moving_camera_scene.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.reconfigurable_scene.ReconfigurableScene.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.reconfigurable_scene.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.sample_space_scene.SampleSpaceScene.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.sample_space_scene.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.scene.RerunSceneHandler.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.scene.RerunSceneHandler.rst:2\nmsgid \"RerunSceneHandler\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.RerunSceneHandler.rst:4\nmsgid \"Qualified name: ``manim.scene.scene.RerunSceneHandler``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.RerunSceneHandler:1\nmsgid \"Bases: :py:class:`watchdog.events.FileSystemEventHandler`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.RerunSceneHandler:1\nmsgid \"A class to handle rerunning a Scene after the input file is modified.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.RerunSceneHandler.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.RerunSceneHandler.on_modified:1:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.RerunSceneHandler.on_modified:1\nmsgid \"Called when a file or directory is modified.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.RerunSceneHandler.on_modified:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.scene.Scene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:2\nmsgid \"Scene\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:4\nmsgid \"Qualified name: ``manim.scene.scene.Scene``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:1\nmsgid \"A Scene is the canvas of your animation.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:3\nmsgid \"The primary role of :class:`Scene` is to provide the user with tools to manage mobjects and animations.  Generally speaking, a manim script consists of a class that derives from :class:`Scene` whose :meth:`Scene.construct` method is overridden by the user's code.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:8\nmsgid \"Mobjects are displayed on screen by calling :meth:`Scene.add` and removed from screen by calling :meth:`Scene.remove`.  All mobjects currently on screen are kept in :attr:`Scene.mobjects`.  Animations are played by calling :meth:`Scene.play`.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:12\nmsgid \"A :class:`Scene` is rendered internally by calling :meth:`Scene.render`.  This in turn calls :meth:`Scene.setup`, :meth:`Scene.construct`, and :meth:`Scene.tear_down`, in that order.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:16\nmsgid \"It is not recommended to override the ``__init__`` method in user Scenes.  For code that should be ran before a Scene is rendered, use :meth:`Scene.setup` instead.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:20\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:12\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:12\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:14\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene:21\nmsgid \"Override the :meth:`Scene.construct` method with your code.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:1\nmsgid \"Mobjects will be displayed, from background to foreground in the order with which they are added.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:1\nmsgid \"Adds a single mobject to the foreground, and internally to the list foreground_mobjects, and mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:1\nmsgid \"Adds mobjects to the foreground, and internally to the list foreground_mobjects, and mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:1\nmsgid \"This method is used to add a sound to the animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:1\nmsgid \"Adds an entry in the corresponding subcaption file at the current time stamp.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:1\nmsgid \"Add an update function to the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.begin_animations:1\nmsgid \"Start the animations of the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:1\nmsgid \"Removes the mobject from the scene and adds them to the back of the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:1\nmsgid \"Adds the passed mobjects to the scene again, pushing them to he front of the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.clear:1\nmsgid \"Removes all mobjects present in self.mobjects and self.foreground_mobjects from the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:1\nmsgid \"Given a list of animations, compile the corresponding static and moving mobjects, and gather the animation durations.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:1\nmsgid \"Creates _MethodAnimations from any _AnimationBuilders and updates animation kwargs with kwargs passed to play().\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:1\nmsgid \"Add content to the Scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:1\nmsgid \"Gets attributes of a scene given the attribute's identifier/name.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\nmsgid \"Returns list of family-members of all mobjects in scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:1\nmsgid \"Gets all moving mobjects in the passed animation(s).\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:1\nmsgid \"Given a list of mobjects and a list of mobjects to be removed, this filters out the removable mobjects from the list of mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:1\nmsgid \"Gets the total run time for a list of animations.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\nmsgid \"You will hardly use this when making your own animations.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_top_level_mobjects:1\nmsgid \"Returns all mobjects which are not submobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.interactive_embed:1\nmsgid \"Like embed(), but allows for screen interaction.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.is_current_animation_frozen_frame:1\nmsgid \"Returns whether the current animation produces a static frame (generally a Wait).\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\nmsgid \"Create separation here; the last section gets finished and a new one gets created.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.pause:1\nmsgid \"Pauses the scene (i.e., displays a frozen frame).\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:1\nmsgid \"Plays an animation in this scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play_internal:1\nmsgid \"This method is used to prep the animations for rendering, apply the arguments and parameters required to them, render them, and write them to the video file.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove:1\nmsgid \"Removes mobjects in the passed list of mobjects from the scene and the foreground, by removing them from \\\"mobjects\\\" and \\\"foreground_mobjects\\\"\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:1\nmsgid \"Removes a single mobject from the foreground, and internally from the list foreground_mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:1\nmsgid \"Removes mobjects from the foreground, and internally from the list foreground_mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_updater:1\nmsgid \"Remove an update function from the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.render:1\nmsgid \"Renders this Scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:4\nmsgid \"tl:wr\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.setup:1\nmsgid \"This is meant to be implemented by any scenes which are commonly subclassed, and have some common setup involved before the construct method is called.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:1\nmsgid \"Returns True if the mobjects of this scene should be updated.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.tear_down:1\nmsgid \"This is meant to be implemented by any scenes which are commonly subclassed, and have some common method to be invoked before the scene ends.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_mobjects:1\nmsgid \"Begins updating all mobjects in the Scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_self:1\nmsgid \"Run all scene updater functions.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait:1\nmsgid \"Plays a \\\"no operation\\\" animation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:74:<autosummary>:1\nmsgid \"Like a wrapper for wait().\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.Scene.rst:76\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.next_section:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.pause:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play_internal:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_updater:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.render:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_self:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait_until:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:4\nmsgid \"Mobjects to add.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.clear:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_mobject_family_members:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_top_level_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:7\nmsgid \"The same scene after adding the Mobjects in.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.begin_animations:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.clear:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_mobject_family_members:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_top_level_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.is_current_animation_frozen_frame:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.next_section:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_updater:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:0\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:4\nmsgid \"The Mobject to add to the foreground.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobject:7\nmsgid \"The Scene, with the foreground mobject added.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:4\nmsgid \"The Mobjects to add to the foreground.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_foreground_mobjects:7\nmsgid \"The Scene, with the foreground mobjects added.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:3\nmsgid \"The path to the sound file.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:5\nmsgid \"The offset in the sound file after which the sound can be played.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:8\nmsgid \"Amplification of the sound.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_sound:29\nmsgid \"Download the resource for the previous example `here <https://github.com/ManimCommunity/manim/blob/main/docs/source/_static/click.wav>`_ .\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:4\nmsgid \"The current time stamp is obtained from ``Scene.renderer.time``.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:6\nmsgid \"The subcaption content.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:7\nmsgid \"The duration (in seconds) for which the subcaption is shown.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:8\nmsgid \"This offset (in seconds) is added to the starting time stamp of the subcaption.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_subcaption:13\nmsgid \"This example illustrates both possibilities for adding subcaptions to Manimations::\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:3\nmsgid \"The scene updater functions are run every frame, and they are the last type of updaters to run.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:8\nmsgid \"When using the Cairo renderer, scene updaters that modify mobjects are not detected in the same way that mobject updaters are. To be more concrete, a mobject only modified via a scene updater will not necessarily be added to the list of *moving mobjects* and thus might not be updated every frame.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:15\nmsgid \"TL;DR: Use mobject updaters to update mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.add_updater:17\nmsgid \"The updater function. It takes a float, which is the time difference since the last update (usually equal to the frame rate).\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:4\nmsgid \"The mobject(s) to push to the back of the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_back:7\nmsgid \"The Scene, with the mobjects pushed to the back of the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:4\nmsgid \"The mobject(s) to bring to the front of the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.bring_to_front:7\nmsgid \"The Scene, with the mobjects brought to the front of the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.clear:4\nmsgid \"The Scene, with all of its mobjects in self.mobjects and self.foreground_mobjects removed.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:4\nmsgid \"This also begins the animations.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:6\nmsgid \"Whether the rendering should be skipped, by default False\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animation_data:9\nmsgid \"None if there is nothing to play, or self otherwise.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:4\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:8\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:3\nmsgid \"Animations to be played.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:6\nmsgid \"Configuration for the call to play().\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.compile_animations:9\nmsgid \"Tuple[:class:`Animation`]\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:3\nmsgid \"From within :meth:`Scene.construct`, display mobjects on screen by calling :meth:`Scene.add` and remove them from screen by calling :meth:`Scene.remove`. All mobjects currently on screen are kept in :attr:`Scene.mobjects`.  Play animations by calling :meth:`Scene.play`.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:9\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:10\nmsgid \"Initialization code should go in :meth:`Scene.setup`.  Termination code should go in :meth:`Scene.tear_down`.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.construct:15\nmsgid \"A typical manim script includes a class derived from :class:`Scene` with an overridden :meth:`Scene.contruct` method:\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:3\nmsgid \"Name(s) of the argument(s) to return the attribute of.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_attrs:6\nmsgid \"List of attributes of the passed identifiers.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_mobject_family_members:1\nmsgid \"Returns list of family-members of all mobjects in scene. If a Circle() and a VGroup(Rectangle(),Triangle()) were added, it returns not only the Circle(), Rectangle() and Triangle(), but also the VGroup() object.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_mobject_family_members:6\nmsgid \"List of mobject family members.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:3\nmsgid \"The animations to check for moving mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_moving_mobjects:6\nmsgid \"The list of mobjects that could be moving in the Animation(s)\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:4\nmsgid \"The Mobjects to check.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:6\nmsgid \"The list of mobjects to remove.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_restructured_mobject_list:9\nmsgid \"The list of mobjects with the mobjects to remove removed.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:3\nmsgid \"A list of the animations whose total ``run_time`` is to be calculated.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_run_time:7\nmsgid \"The total ``run_time`` of all of the animations in the list.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:1\nmsgid \"You will hardly use this when making your own animations. This method is for Manim's internal use.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:4\nmsgid \"Returns a CommandLine ProgressBar whose ``fill_time`` is dependent on the ``run_time`` of an animation, the iterations to perform in that animation and a bool saying whether or not to consider the skipped animations.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:10\nmsgid \"The ``run_time`` of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:12\nmsgid \"The number of iterations in the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:14\nmsgid \"Whether or not to show skipped animations in the progress bar.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_time_progression:17\nmsgid \"The CommandLine Progress Bar.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.get_top_level_mobjects:3\nmsgid \"List of top level mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.next_section:1\nmsgid \"Create separation here; the last section gets finished and a new one gets created. ``skip_animations`` skips the rendering of all animations in this section. Refer to :doc:`the documentation</tutorials/output_and_config>` on how to use sections.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.pause:3\nmsgid \"This is an alias for :meth:`.wait` with ``frozen_frame`` set to ``True``.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.pause:6\nmsgid \"The duration of the pause.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:4\nmsgid \"The content of the external subcaption that should be added during the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:6\nmsgid \"The duration for which the specified subcaption is added. If ``None`` (the default), the run time of the animation is taken.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:9\nmsgid \"An offset (in seconds) for the start time of the added subcaption.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play:11\nmsgid \"All other keywords are passed to the renderer.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play_internal:5\nmsgid \"Animation or mobject with mobject method and params\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.play_internal:6\nmsgid \"named parameters affecting what was passed in ``args``, e.g. ``run_time``, ``lag_ratio`` and so on.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove:5\nmsgid \"The mobjects to remove.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:4\nmsgid \"The mobject to remove from the foreground.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobject:7\nmsgid \"The Scene, with the foreground mobject removed.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:4\nmsgid \"The mobject(s) to remove from the foreground.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_foreground_mobjects:7\nmsgid \"The Scene, with the foreground mobjects removed.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.remove_updater:3\nmsgid \"The updater function to be removed.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.render:3\nmsgid \"If true, opens scene in a file viewer.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:2\nmsgid \"If your scene has a Group(), and you removed a mobject from the Group, this dissolves the group and puts the rest of the mobjects directly in self.mobjects or self.foreground_mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:6\nmsgid \"In cases where the scene contains a group, e.g. Group(m1, m2, m3), but one of its submobjects is removed, e.g. scene.remove(m1), the list of mobjects will be edited to contain other submobjects, but not m1, e.g. it will now insert m2 and m3 to where the group once was.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:11\nmsgid \"The Mobject to remove.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:13\nmsgid \"The list of mobjects (\\\"mobjects\\\", \\\"foreground_mobjects\\\" etc) to remove from.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:15\nmsgid \"Whether the mobject's families should be recursively extracted.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.restructure_mobjects:18\nmsgid \"The Scene mobject with restructured Mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:3\nmsgid \"In particular, this checks whether\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:5\nmsgid \"the :attr:`always_update_mobjects` attribute of :class:`.Scene` is set to ``True``,\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:7\nmsgid \"the :class:`.Scene` itself has time-based updaters attached,\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:8\nmsgid \"any mobject in this :class:`.Scene` has time-based updaters attached.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.should_update_mobjects:10\nmsgid \"This is only called when a single Wait animation is played.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_mobjects:3\nmsgid \"Change in time between updates. Defaults (mostly) to 1/frames_per_second\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_self:3\nmsgid \"Among all types of update functions (mobject updaters, mesh updaters, scene updaters), scene update functions are called last.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.update_self:6\nmsgid \"Scene time since last update.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait:3\nmsgid \"The run time of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait:4\nmsgid \"A function without positional arguments that is evaluated every time a frame is rendered. The animation only stops when the return value of the function is truthy. Overrides any value passed to ``duration``.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait:7\nmsgid \"If True, updater functions are not evaluated, and the animation outputs a frozen frame. If False, updater functions are called and frames are rendered as usual. If None (the default), the scene tries to determine whether or not the frame is frozen on its own.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait_until:1\nmsgid \"Like a wrapper for wait(). You pass a function that determines whether to continue waiting, and a max wait time if that is never fulfilled.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene.Scene.wait_until:5\nmsgid \"The function whose boolean return value determines whether to continue waiting\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.scene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.scene.rst:2\nmsgid \"scene\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene.py:docstring of manim.scene.scene:1\nmsgid \"Basic canvas for animations.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene.rst:22:<autosummary>:1\nmsgid \"A class to handle rerunning a Scene after the input file is modified.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.scene_file_writer.SceneFileWriter.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:2\nmsgid \"SceneFileWriter\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:4\nmsgid \"Qualified name: ``manim.scene.scene\\\\_file\\\\_writer.SceneFileWriter``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:1\nmsgid \"SceneFileWriter is the object that actually writes the animations played, into video files, using FFMPEG. This is mostly for Manim's internal use. You will rarely, if ever, have to use the methods for this class, unless tinkering with the very fabric of Manim's reality.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:9\nmsgid \"used to segment scene\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:0\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:11\nmsgid \"list of :class:`.Section`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:15\nmsgid \"where are section videos stored\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:17\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:23\nmsgid \"str\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:21\nmsgid \"name of movie without extension and basis for section video names\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:32\nmsgid \"Some useful attributes are:\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:26\nmsgid \"\\\"write_to_movie\\\" (bool=False)\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:27\nmsgid \"Whether or not to write the animations into a video file.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:28\nmsgid \"\\\"movie_file_extension\\\" (str=\\\".mp4\\\")\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:29\nmsgid \"The file-type extension of the outputted video.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:32\nmsgid \"\\\"partial_movie_files\\\"\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter:31\nmsgid \"List of all the partial-movie files.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_audio_segment:1\nmsgid \"This method adds an audio segment from an AudioSegment type object and suitable parameters.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\nmsgid \"Adds a new partial movie file path to `scene.partial_movie_files` and current section from a hash.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:1\nmsgid \"This method adds an audio segment from a sound file.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.begin_animation:1\nmsgid \"Used internally by manim to stream the animation to FFMPEG for displaying or writing to a file.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.clean_cache:1\nmsgid \"Will clean the cache by removing the oldest partial_movie_files.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.close_movie_pipe:1\nmsgid \"Used internally by Manim to gracefully stop writing to FFMPEG's input buffer\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.combine_to_movie:1\nmsgid \"Used internally by Manim to combine the separate partial movie files that make up a Scene into a single video file for that Scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.combine_to_section_videos:1\nmsgid \"Concatenate partial movie files for each section.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.create_audio_segment:1\nmsgid \"Creates an empty, silent, Audio Segment.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.end_animation:1\nmsgid \"Internally used by Manim to stop streaming to FFMPEG gracefully.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\nmsgid \"Finishes writing to the FFMPEG buffer or writing images to output directory.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.finish_last_section:1\nmsgid \"Delete current section if it is empty.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.flush_cache_directory:1\nmsgid \"Delete all the cached partial movie files\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:1\nmsgid \"Get the name of the resolution directory directly containing the video file.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.init_audio:1\nmsgid \"Preps the writer for adding audio to the movie.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.init_output_directories:1\nmsgid \"Initialise output directories.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:1\nmsgid \"Will check if a file named with `hash_invocation` exists.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.next_section:1\nmsgid \"Create segmentation cut here.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.open_movie_pipe:1\nmsgid \"Used internally by Manim to initialise FFMPEG and begin writing to FFMPEG's input buffer.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.print_file_ready_message:1\nmsgid \"Prints the \\\"File Ready\\\" message to STDOUT.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\nmsgid \"The name is a misnomer.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.write_frame:1\nmsgid \"Used internally by Manim to write a frame to the FFMPEG input buffer.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:46:<autosummary>:1\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.write_subcaption_file:1\nmsgid \"Writes the subcaption file.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.SceneFileWriter.rst:48\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_audio_segment:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_partial_movie_file:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.begin_animation:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.end_animation:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.next_section:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.save_final_image:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.write_frame:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_audio_segment:4\nmsgid \"The audio segment to add\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_audio_segment:6\nmsgid \"the timestamp at which the sound should be added.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_audio_segment:9\nmsgid \"The gain of the segment from the background.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_partial_movie_file:1\nmsgid \"Adds a new partial movie file path to `scene.partial_movie_files` and current section from a hash. This method will compute the path from the hash. In addition to that it adds the new animation to the current section.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_partial_movie_file:4\nmsgid \"Hash of the animation.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:3\nmsgid \"The path to the sound file.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:5\nmsgid \"The timestamp at which the audio should be added.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:7\nmsgid \"The gain of the given audio segment.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.add_sound:9\nmsgid \"This method uses add_audio_segment, so any keyword arguments used there can be referenced here.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.begin_animation:4\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.end_animation:4\nmsgid \"Whether or not to write to a video file.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.combine_to_section_videos:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.finish_last_section:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.next_section:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.finish:1\nmsgid \"Finishes writing to the FFMPEG buffer or writing images to output directory. Combines the partial movie files into the whole scene. If save_last_frame is True, saves the last frame in the default image directory.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:4\nmsgid \"This method gets the name of the directory that immediately contains the video file. This name is ``<height_in_pixels_of_video>p<frame_rate>``. For example, if you are rendering an 854x480 px animation at 15fps, the name of the directory that immediately contains the video,  file will be ``480p15``.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:10\nmsgid \"The file structure should look something like::\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:0\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.get_resolution_directory:20\nmsgid \"The name of the directory.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.init_output_directories:4\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.init_output_directories:5\nmsgid \"The directories are read from ``config``, for example ``config['media_dir']``.  If the target directories don't already exist, they will be created.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:3\nmsgid \"The hash corresponding to an invocation to either `scene.play` or `scene.wait`.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.is_already_cached:6\nmsgid \"Whether the file exists.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.save_final_image:1\nmsgid \"The name is a misnomer. This method saves the image passed to it as an in the default image directory.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer.SceneFileWriter.save_final_image:4\nmsgid \"The pixel array of the image to save.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.scene_file_writer.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.rst:2\nmsgid \"scene\\\\_file\\\\_writer\"\nmsgstr \"\"\n\n#: ../../../manim/scene/scene_file_writer.py:docstring of manim.scene.scene_file_writer:1\nmsgid \"The interface between scenes and ffmpeg.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.scene_file_writer.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.section.DefaultSectionType.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.section.DefaultSectionType.rst:2\nmsgid \"DefaultSectionType\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.section.DefaultSectionType.rst:4\nmsgid \"Qualified name: ``manim.scene.section.DefaultSectionType``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.DefaultSectionType:1\nmsgid \"Bases: :py:class:`str`, :py:class:`enum.Enum`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.DefaultSectionType:1\nmsgid \"The type of a section can be used for third party applications. A presentation system could for example use the types to created loops.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.DefaultSectionType:5\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.DefaultSectionType:6\nmsgid \"This class can be reimplemented for more types::\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.section.DefaultSectionType.rst:16\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.section.Section.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.section.Section.rst:2\nmsgid \"Section\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.section.Section.rst:4\nmsgid \"Qualified name: ``manim.scene.section.Section``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:1\nmsgid \"A :class:`.Scene` can be segmented into multiple Sections. Refer to :doc:`the documentation</tutorials/output_and_config>` for more info. It consists of multiple animations.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:0\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_dict:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:7\nmsgid \"Can be used by a third party applications to classify different types of sections.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:11\nmsgid \"Path to video file with animations belonging to section relative to sections directory. If ``None``, then the section will not be saved.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:16\nmsgid \"Human readable, non-unique name for this section.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:20\nmsgid \"Skip rendering the animations in this section when ``True``.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section:24\nmsgid \"Animations belonging to this section.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.section.Section.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_clean_partial_movie_files:1:<autosummary>:1\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_clean_partial_movie_files:1\nmsgid \"Return all partial movie files that are not ``None``.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_clean_partial_movie_files:1:<autosummary>:1\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_dict:1\nmsgid \"Get dictionary representation with metadata of output video.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_clean_partial_movie_files:1:<autosummary>:1\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.is_empty:1\nmsgid \"Check whether this section is empty.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_clean_partial_movie_files:0\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_dict:0\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.is_empty:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section.Section.get_dict:3\nmsgid \"The output from this function is used from every section to build the sections index file. The output video must have been created in the ``sections_dir`` before executing this method. This is the main part of the Segmented Video API.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.section.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.section.rst:2\nmsgid \"section\"\nmsgstr \"\"\n\n#: ../../../manim/scene/section.py:docstring of manim.scene.section:1\nmsgid \"building blocks of segmented video API\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.section.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.section.rst:22:<autosummary>:1\nmsgid \"The type of a section can be used for third party applications.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.three_d_scene.SpecialThreeDScene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:2\nmsgid \"SpecialThreeDScene\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:4\nmsgid \"Qualified name: ``manim.scene.three\\\\_d\\\\_scene.SpecialThreeDScene``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene:1\nmsgid \"Bases: :py:class:`manim.scene.three_d_scene.ThreeDScene`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene:1\nmsgid \"An extension of :class:`ThreeDScene` with more settings.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene:3\nmsgid \"It has some extra configuration for axes, spheres, and an override for low quality rendering. Further key differences are:\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene:7\nmsgid \"The camera shades applicable 3DMobjects by default, except if rendering in low quality.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene:9\nmsgid \"Some default params for Spheres and Axes have been added.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:23:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_axes:1\nmsgid \"Return a set of 3D axes.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:23:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_default_camera_position:1\nmsgid \"Returns the default_angled_camera position.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:23:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:1\nmsgid \"Returns a sphere with the passed keyword arguments as properties.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:23:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.set_camera_to_default_position:1\nmsgid \"Sets the camera to its default position.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.SpecialThreeDScene.rst:25\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_axes:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_default_camera_position:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_axes:3\nmsgid \"A set of 3D axes.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_axes:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_default_camera_position:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_default_camera_position:3\nmsgid \"Dictionary of phi, theta, focal_distance, and gamma.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:3\nmsgid \"Any valid parameter of :class:`~.Sphere` or :class:`~.Surface`.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.SpecialThreeDScene.get_sphere:5\nmsgid \"The sphere object.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.three_d_scene.ThreeDScene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:2\nmsgid \"ThreeDScene\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:4\nmsgid \"Qualified name: ``manim.scene.three\\\\_d\\\\_scene.ThreeDScene``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene:1\nmsgid \"Bases: :py:class:`manim.scene.scene.Scene`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene:1\nmsgid \"This is a Scene, with special configurations and properties that make it suitable for Three Dimensional Scenes.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\nmsgid \"This method is used to prevent the rotation and movement of mobjects as the camera moves around.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\nmsgid \"This method is used to prevent the rotation and tilting of mobjects as the camera moves around.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_3dillusion_camera_rotation:1\nmsgid \"This method creates a 3D camera rotation illusion around the current camera orientation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_ambient_camera_rotation:1\nmsgid \"This method begins an ambient rotation of the camera about the Z_AXIS, in the anticlockwise direction\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.get_moving_mobjects:1\nmsgid \"This method returns a list of all of the Mobjects in the Scene that are moving, that are also in the animations passed.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:1\nmsgid \"This method animates the movement of the camera to the given spherical coordinates.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\nmsgid \"This method undoes what add_fixed_in_frame_mobjects does.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\nmsgid \"This method \\\"unfixes\\\" the orientation of the mobjects passed, meaning they will no longer be at the same angle relative to the camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:1\nmsgid \"This method sets the orientation of the camera in the scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_to_default_angled_camera_orientation:1\nmsgid \"This method sets the default_angled_camera_orientation to the keyword arguments passed, and sets the camera to that orientation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.stop_3dillusion_camera_rotation:1\nmsgid \"This method stops all illusion camera rotations.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:31:<autosummary>:1\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.stop_ambient_camera_rotation:1\nmsgid \"This method stops all ambient camera rotation.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.ThreeDScene.rst:33\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_in_frame_mobjects:1\nmsgid \"This method is used to prevent the rotation and movement of mobjects as the camera moves around. The mobject is essentially overlaid, and is not impacted by the camera's movement in any way.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_in_frame_mobjects:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_3dillusion_camera_rotation:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_ambient_camera_rotation:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.get_moving_mobjects:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_in_frame_mobjects:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_orientation_mobjects:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:0\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_to_default_angled_camera_orientation:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_in_frame_mobjects:6\nmsgid \"The Mobjects whose orientation must be fixed.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:1\nmsgid \"This method is used to prevent the rotation and tilting of mobjects as the camera moves around. The mobject can still move in the x,y,z directions, but will always be at the angle (relative to the camera) that it was at when it was passed through this method.)\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:7\nmsgid \"The Mobject(s) whose orientation must be fixed.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:9\nmsgid \"Some valid kwargs are     use_static_center_func : bool     center_func : function\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:11\nmsgid \"Some valid kwargs are\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.add_fixed_orientation_mobjects:11\nmsgid \"use_static_center_func : bool center_func : function\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_3dillusion_camera_rotation:4\nmsgid \"The rate at which the camera rotation illusion should operate.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_3dillusion_camera_rotation:5\nmsgid \"The polar angle the camera should move around. Defaults to the current phi angle.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_3dillusion_camera_rotation:7\nmsgid \"The azimutal angle the camera should move around. Defaults to the current theta angle.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_ambient_camera_rotation:4\nmsgid \"The rate at which the camera should rotate about the Z_AXIS. Negative rate means clockwise rotation.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.begin_ambient_camera_rotation:7\nmsgid \"one of 3 options: [\\\"theta\\\", \\\"phi\\\", \\\"gamma\\\"]. defaults to theta.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.get_moving_mobjects:4\nmsgid \"The animations whose mobjects will be checked.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:4\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:3\nmsgid \"The polar angle i.e the angle between Z_AXIS and Camera through ORIGIN in radians.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:6\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:5\nmsgid \"The azimuthal angle i.e the angle that spins the camera around the Z_AXIS.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:8\nmsgid \"The radial focal_distance between ORIGIN and Camera.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:10\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:9\nmsgid \"The rotation of the camera about the vector from the ORIGIN to the Camera.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:12\nmsgid \"The zoom factor of the camera.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:14\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:13\nmsgid \"The new center of the camera frame in cartesian coordinates.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.move_camera:16\nmsgid \"Any other animations to be played at the same time.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_in_frame_mobjects:1\nmsgid \"This method undoes what add_fixed_in_frame_mobjects does. It allows the mobject to be affected by the movement of the camera.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_in_frame_mobjects:5\nmsgid \"The Mobjects whose position and orientation must be unfixed.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_orientation_mobjects:1\nmsgid \"This method \\\"unfixes\\\" the orientation of the mobjects passed, meaning they will no longer be at the same angle relative to the camera. This only makes sense if the mobject was passed through add_fixed_orientation_mobjects first.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.remove_fixed_orientation_mobjects:6\nmsgid \"The Mobjects whose orientation must be unfixed.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:7\nmsgid \"The focal_distance of the Camera.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene.ThreeDScene.set_camera_orientation:11\nmsgid \"The zoom factor of the scene.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.three_d_scene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.three_d_scene.rst:2\nmsgid \"three\\\\_d\\\\_scene\"\nmsgstr \"\"\n\n#: ../../../manim/scene/three_d_scene.py:docstring of manim.scene.three_d_scene:1\nmsgid \"A scene suitable for rendering three-dimensional objects and animations.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.three_d_scene.rst:22:<autosummary>:1\nmsgid \"An extension of :class:`ThreeDScene` with more settings.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.vector_space_scene.LinearTransformationScene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:2\nmsgid \"LinearTransformationScene\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:4\nmsgid \"Qualified name: ``manim.scene.vector\\\\_space\\\\_scene.LinearTransformationScene``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:1\nmsgid \"Bases: :py:class:`manim.scene.vector_space_scene.VectorScene`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:1\nmsgid \"This scene contains special methods that make it especially suitable for showing linear transformations.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_background_mobject:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_foreground_mobject:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_moving_mobject:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_special_mobjects:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_mobject:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_function:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse_transpose:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_matrix:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_nonlinear_transformation:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_transposed_matrix:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_matrix_transformation:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transposed_matrix_transformation:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:4\nmsgid \"Whether or not to include the background plane in the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:5\nmsgid \"Whether or not to include the foreground plane in the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:6\nmsgid \"Parameters to be passed to :class:`NumberPlane` to adjust the background plane.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:7\nmsgid \"Parameters to be passed to :class:`NumberPlane` to adjust the foreground plane.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:8\nmsgid \"Whether or not to include the coordinates for the background plane.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:9\nmsgid \"Whether to show the basis x_axis -> ``i_hat`` and y_axis -> ``j_hat`` vectors.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:10\nmsgid \"The ``stroke_width`` of the basis vectors.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:11\nmsgid \"The color of the ``i_hat`` vector.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:12\nmsgid \"The color of the ``j_hat`` vector.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:13\nmsgid \"Indicates the previous position of the basis vectors following a transformation.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene:16\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_background_mobject:1\nmsgid \"Adds the mobjects to the special list self.background_mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_foreground_mobject:1\nmsgid \"Adds the mobjects to the special list self.foreground_mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_moving_mobject:1\nmsgid \"Adds the mobject to the special list self.moving_mobject, and adds a property to the mobject called mobject.target, which keeps track of what the mobject will move to or become etc.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_special_mobjects:1\nmsgid \"Adds mobjects to a separate list that can be tracked, if these mobjects have some extra importance.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\nmsgid \"Adds a title, after scaling it, adding a background rectangle, moving it to the top and adding it to foreground_mobjects adding it as a local variable of self.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:1\nmsgid \"Method for creating, and animating the addition of a transformable label for the vector.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_mobject:1\nmsgid \"Adds the mobjects to the special list self.transformable_mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:1\nmsgid \"Adds a unit square to the scene via self.get_unit_square.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:1\nmsgid \"Adds a vector to the scene, and puts it in the special list self.moving_vectors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_function:1\nmsgid \"Applies the given function to each of the mobjects in self.transformable_mobjects, and plays the animation showing this.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse:1\nmsgid \"This method applies the linear transformation represented by the inverse of the passed matrix to the number plane, and each vector/similar mobject on it.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse_transpose:1\nmsgid \"Applies the inverse of the transformation represented by the given transposed matrix to the number plane and each vector/similar mobject on it.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_matrix:1\nmsgid \"Applies the transformation represented by the given matrix to the number plane, and each vector/similar mobject on it.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_nonlinear_transformation:1\nmsgid \"Applies the non-linear transformation represented by the given function to the number plane and each vector/similar mobject on it.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_transposed_matrix:1\nmsgid \"Applies the transformation represented by the given transposed matrix to the number plane, and each vector/similar mobject on it.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_matrix_transformation:1\nmsgid \"Returns a function corresponding to the linear transformation represented by the matrix passed.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\nmsgid \"This method returns an animation that moves a mobject in \\\"self.moving_mobjects\\\"  to its corresponding .target value.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\nmsgid \"This method returns an animation that moves an arbitrary mobject in \\\"pieces\\\" to its corresponding .target value.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transformable_label_movement:1\nmsgid \"This method returns an animation that moves all labels in \\\"self.transformable_labels\\\" to its corresponding .target .\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transposed_matrix_transformation:1\nmsgid \"Returns a function corresponding to the linear transformation represented by the transposed matrix passed.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:1\nmsgid \"Returns a unit square for the current NumberPlane.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\nmsgid \"This method returns an animation that moves a mobject in \\\"self.moving_vectors\\\"  to its corresponding .target value.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.setup:1\nmsgid \"This is meant to be implemented by any scenes which are commonly subclassed, and have some common setup involved before the construct method is called.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:44:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:1\nmsgid \"Returns a column matrix indicating the vector coordinates, after writing them to the screen, and adding them to the special list self.foreground_mobjects\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.LinearTransformationScene.rst:46\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_background_mobject:4\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_mobject:4\nmsgid \"The mobjects to add to the list.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_foreground_mobject:4\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_moving_mobject:7\nmsgid \"The mobjects to add to the list\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_moving_mobject:9\nmsgid \"What the moving_mobject goes to, etc.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_special_mobjects:4\nmsgid \"The special list to which you want to add these mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_special_mobjects:7\nmsgid \"The mobjects to add.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:1\nmsgid \"Adds a title, after scaling it, adding a background rectangle, moving it to the top and adding it to foreground_mobjects adding it as a local variable of self. Returns the Scene.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:5\nmsgid \"What the title should be.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:7\nmsgid \"How much the title should be scaled by.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:9\nmsgid \"Whether or not to animate the addition.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transformable_label_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:12\nmsgid \"The scene with the title added to it.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_title:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transformable_label_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:4\nmsgid \"The vector for which the label must be added.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:6\nmsgid \"The MathTex/string of the label.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:8\nmsgid \"The name to give the transformation as a label.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:10\nmsgid \"What the label should display after a Linear Transformation\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:12\nmsgid \"Any valid keyword argument of get_vector_label\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_transformable_label:14\nmsgid \"The MathTex of the label.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:4\nmsgid \"Whether or not to animate the addition with DrawBorderThenFill.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:6\nmsgid \"Any valid keyword arguments of self.get_unit_square()\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_unit_square:9\nmsgid \"The unit square.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:4\nmsgid \"It can be a pre-made graphical vector, or the coordinates of one.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:7\nmsgid \"The string of the hex color of the vector. This is only taken into consideration if 'vector' is not an Arrow. Defaults to YELLOW.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:11\nmsgid \"Any valid keyword argument of VectorScene.add_vector.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.add_vector:13\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:5\nmsgid \"The arrow representing the vector.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_function:5\nmsgid \"The function that affects each point of each mobject in self.transformable_mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_function:8\nmsgid \"Any other animations that need to be played simultaneously with this.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_function:11\nmsgid \"Any valid keyword argument of a self.play() call.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse:5\nmsgid \"The matrix whose inverse is to be applied.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse:7\nmsgid \"Any valid keyword argument of self.apply_matrix()\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse_transpose:5\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_matrix:5\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_transposed_matrix:5\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_matrix_transformation:4\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transposed_matrix_transformation:5\nmsgid \"The matrix.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_inverse_transpose:7\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_matrix:7\nmsgid \"Any valid keyword argument of self.apply_transposed_matrix()\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_nonlinear_transformation:5\nmsgid \"The function.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_nonlinear_transformation:7\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.apply_transposed_matrix:7\nmsgid \"Any valid keyword argument of self.apply_function()\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:1\nmsgid \"This method returns an animation that moves a mobject in \\\"self.moving_mobjects\\\"  to its corresponding .target value. func is a function that determines where the .target goes.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:5\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:5\nmsgid \"The function that determines where the .target of the moving mobject goes.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_moving_mobject_movement:9\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:9\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_transformable_label_movement:4\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:9\nmsgid \"The animation of the movement.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:1\nmsgid \"This method returns an animation that moves an arbitrary mobject in \\\"pieces\\\" to its corresponding .target value. If self.leave_ghost_vectors is True, ghosts of the original positions/mobjects are left on screen\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_piece_movement:6\nmsgid \"The pieces for which the movement must be shown.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:3\nmsgid \"The string of the hex color code of the color wanted.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:5\nmsgid \"The opacity of the square\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_unit_square:7\nmsgid \"The stroke_width in pixels of the border of the square\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.get_vector_movement:1\nmsgid \"This method returns an animation that moves a mobject in \\\"self.moving_vectors\\\"  to its corresponding .target value. func is a function that determines where the .target goes.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.LinearTransformationScene.write_vector_coordinates:7\nmsgid \"Any valid keyword arguments of VectorScene.write_vector_coordinates\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.vector_space_scene.VectorScene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:2\nmsgid \"VectorScene\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:4\nmsgid \"Qualified name: ``manim.scene.vector\\\\_space\\\\_scene.VectorScene``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene:1\nmsgid \"Bases: :py:class:`manim.scene.scene.Scene`\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_axes:1\nmsgid \"Adds a pair of Axes to the Scene.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:1\nmsgid \"Adds a NumberPlane object to the background.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:1\nmsgid \"Returns the Vector after adding it to the Plane.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\nmsgid \"This method writes the vector as a column matrix (henceforth called the label), takes the values in it one by one, and form the corresponding lines that make up the x and y components of the vector.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vector_labels:1\nmsgid \"Returns naming labels for the basis vectors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:1\nmsgid \"Returns a VGroup of the Basis Vectors (1,0) and (0,1)\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:1\nmsgid \"Returns an arrow on the Plane given an input numerical vector.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:1\nmsgid \"Returns naming labels for the passed vector.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:1\nmsgid \"Shortcut method for creating, and animating the addition of a label for the vector.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.lock_in_faded_grid:1\nmsgid \"This method freezes the NumberPlane and Axes that were already in the background, and adds new, manipulatable ones to the foreground.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\nmsgid \"This method plays an animation that partially shows the entire plane moving in the direction of a particular vector.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\nmsgid \"This method displays vector as a Vector() based vector, and then shows the corresponding lines that make up the x and y components of the vector.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:34:<autosummary>:1\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:1\nmsgid \"Returns a column matrix indicating the vector coordinates, after writing them to the screen.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.VectorScene.rst:36\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_axes:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.coords_to_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vector_labels:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.lock_in_faded_grid:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.show_ghost_movement:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.vector_to_coords:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_axes:3\nmsgid \"Whether or not to animate the addition of the axes through Create.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_axes:5\nmsgid \"The color of the axes. Defaults to WHITE.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:3\nmsgid \"Whether or not to animate the addition of the plane via Create.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:5\nmsgid \"Any valid keyword arguments accepted by NumberPlane.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:7\nmsgid \"The NumberPlane object.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_plane:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:0\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:3\nmsgid \"It can be a pre-made graphical vector, or the coordinates of one.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:6\nmsgid \"The string of the hex color of the vector. This is only taken into consideration if 'vector' is not an Arrow. Defaults to YELLOW.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:10\nmsgid \"Whether or not to animate the addition of the vector by using GrowArrow\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:13\nmsgid \"Any valid keyword argument of Arrow. These are only considered if vector is not an Arrow.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.add_vector:17\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:4\nmsgid \"The arrow representing the vector.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.coords_to_vector:1\nmsgid \"This method writes the vector as a column matrix (henceforth called the label), takes the values in it one by one, and form the corresponding lines that make up the x and y components of the vector. Then, an Vector() based vector is created between the lines on the Screen.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.coords_to_vector:6\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.vector_to_coords:6\nmsgid \"The vector to show.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.coords_to_vector:8\nmsgid \"The starting point of the location of the label of the vector that shows it numerically. Defaults to 2 * RIGHT + 2 * UP or (2,2)\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.coords_to_vector:13\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.vector_to_coords:11\nmsgid \"Whether or not to remove whatever this method did after it's done.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vector_labels:3\nmsgid \"Any valid keyword arguments of get_vector_label:     vector,     label (str,MathTex)     at_tip (bool=False),     direction (str=\\\"left\\\"),     rotate (bool),     color (str),     label_scale_factor=VECTOR_LABEL_SCALE_FACTOR (int, float),\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vector_labels:10\nmsgid \"Any valid keyword arguments of get_vector_label:\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vector_labels:5\nmsgid \"vector, label (str,MathTex) at_tip (bool=False), direction (str=\\\"left\\\"), rotate (bool), color (str), label_scale_factor=VECTOR_LABEL_SCALE_FACTOR (int, float),\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:3\nmsgid \"The hex colour to use for the basis vector in the x direction\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:5\nmsgid \"The hex colour to use for the basis vector in the y direction\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_basis_vectors:8\nmsgid \"VGroup of the Vector Mobjects representing the basis vectors.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:3\nmsgid \"The Vector to plot.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:5\nmsgid \"Any valid keyword argument of Arrow.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector:7\nmsgid \"The Arrow representing the Vector.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:3\nmsgid \"Vector Object for which to get the label.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:5\nmsgid \"Whether or not to place the label at the tip of the vector.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:7\nmsgid \"If the label should be on the \\\"left\\\" or right of the vector.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:9\nmsgid \"Whether or not to rotate it to align it with the vector.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:11\nmsgid \"The color to give the label.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:13\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:14\nmsgid \"How much to scale the label by.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.get_vector_label:16\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:12\nmsgid \"The MathTex of the label.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:4\nmsgid \"The vector for which the label must be added.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:6\nmsgid \"The MathTex/string of the label.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:8\nmsgid \"Whether or not to animate the labelling w/ Write\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.label_vector:10\nmsgid \"Any valid keyword argument of get_vector_label\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.lock_in_faded_grid:4\nmsgid \"The required dimness of the NumberPlane\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.lock_in_faded_grid:6\nmsgid \"The required dimness of the Axes.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.show_ghost_movement:1\nmsgid \"This method plays an animation that partially shows the entire plane moving in the direction of a particular vector. This is useful when you wish to convey the idea of mentally moving the entire plane in a direction, without actually moving the plane.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.show_ghost_movement:6\nmsgid \"The vector which indicates the direction of movement.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.vector_to_coords:1\nmsgid \"This method displays vector as a Vector() based vector, and then shows the corresponding lines that make up the x and y components of the vector. Then, a column matrix (henceforth called the label) is created near the head of the Vector.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.vector_to_coords:8\nmsgid \"Whether or not to round the value displayed. in the vector's label to the nearest integer\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:6\nmsgid \"Any valid keyword arguments of :meth:`~.geometry.Vector.coordinate_label`:  integer_labels : :class:`bool`     Whether or not to round the coordinates to integers. Default: ``True``. n_dim : :class:`int`     The number of dimensions of the vector. Default: ``2``. color     The color of the label. Default: ``WHITE``.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:6\nmsgid \"Any valid keyword arguments of :meth:`~.geometry.Vector.coordinate_label`:\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:8\nmsgid \"integer_labels : :class:`bool`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:7\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:9\nmsgid \"Whether or not to round the coordinates to integers. Default: ``True``.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:10\nmsgid \"n_dim : :class:`int`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:9\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:11\nmsgid \"The number of dimensions of the vector. Default: ``2``.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:13\nmsgid \"color\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:13\nmsgid \"The color of the label. Default: ``WHITE``.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene.VectorScene.write_vector_coordinates:15\nmsgid \"The column matrix representing the vector.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.vector_space_scene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.rst:2\nmsgid \"vector\\\\_space\\\\_scene\"\nmsgstr \"\"\n\n#: ../../../manim/scene/vector_space_scene.py:docstring of manim.scene.vector_space_scene:1\nmsgid \"A scene suitable for vector spaces.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.vector_space_scene.rst:22:<autosummary>:1\nmsgid \"This scene contains special methods that make it especially suitable for showing linear transformations.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.zoomed_scene.ZoomedScene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:2\nmsgid \"ZoomedScene\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:4\nmsgid \"Qualified name: ``manim.scene.zoomed\\\\_scene.ZoomedScene``\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene:1\nmsgid \"Bases: :py:class:`manim.scene.moving_camera_scene.MovingCameraScene`\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene:1\nmsgid \"This is a Scene with special configurations made for when a particular part of the scene must be zoomed in on and displayed separately.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:24:<autosummary>:1\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.activate_zooming:1\nmsgid \"This method is used to activate the zooming for the zoomed_camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:24:<autosummary>:1\nmsgid \"Returns the Zoom factor of the Zoomed camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:24:<autosummary>:1\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:1\nmsgid \"Returns the animation of camera zooming in.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:24:<autosummary>:1\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoomed_display_pop_out_animation:1\nmsgid \"This is the animation of the popping out of the mini-display that shows the content of the zoomed camera.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:24:<autosummary>:1\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.setup:1\nmsgid \"This method is used internally by Manim to setup the scene for proper use.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.ZoomedScene.rst:26\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.activate_zooming:0\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.activate_zooming:4\nmsgid \"Whether or not to animate the activation of the zoomed camera.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_factor:1\nmsgid \"Returns the Zoom factor of the Zoomed camera. Defined as the ratio between the height of the zoomed camera and the height of the zoomed mini display. :returns: The zoom factor. :rtype: float\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:3\nmsgid \"The run_time of the animation of the camera zooming in.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:5\nmsgid \"Any valid keyword arguments of ApplyMethod()\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:0\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoomed_display_pop_out_animation:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:7\nmsgid \"The animation of the camera zooming in.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoom_in_animation:0\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene.ZoomedScene.get_zoomed_display_pop_out_animation:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.scene.zoomed_scene.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.rst:2\nmsgid \"zoomed\\\\_scene\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene:1\nmsgid \"A scene supporting zooming in on a specified section.\"\nmsgstr \"\"\n\n#: ../../../manim/scene/zoomed_scene.py:docstring of manim.scene.zoomed_scene:5\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.scene.zoomed_scene.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.bezier.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.bezier.rst:2\nmsgid \"bezier\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier:1\nmsgid \"Utility functions related to Bézier curves.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.bezier.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:1\nmsgid \"Classic implementation of a bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.diag_to_matrix:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.integer_interpolate:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.interpolate:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.inverse_interpolate:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.is_closed:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.match_interpolate:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.mid:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.quadratic_bezier_remap:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.subdivide_quadratic_bezier:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:3\nmsgid \"points defining the desired bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:6\nmsgid \"function describing the bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.bezier:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.diag_to_matrix:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.integer_interpolate:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.interpolate:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.inverse_interpolate:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.is_closed:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.match_interpolate:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.mid:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.quadratic_bezier_remap:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:0\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.subdivide_quadratic_bezier:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.diag_to_matrix:1\nmsgid \"Converts array whose rows represent diagonal entries of a matrix into the matrix itself. See scipy.linalg.solve_banded\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:1\nmsgid \"Given some anchors (points), compute handles so the resulting bezier curve is smooth.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:3\nmsgid \"Anchors.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.get_smooth_handle_points:6\nmsgid \"Computed handles.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.integer_interpolate:1\nmsgid \"Alpha is a float between 0 and 1.  This returns an integer between start and end (inclusive) representing appropriate interpolation between them, along with a \\\"residue\\\" representing a new proportion between the returned integer and the next one of the list.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.integer_interpolate:8\nmsgid \"For example, if start=0, end=10, alpha=0.46, This would return (4, 0.6).\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:1\nmsgid \"Given an array of points which define bezier curve, and two numbers 0<=a<b<=1, return an array of the same size, which describes the portion of the original bezier curve on the interval [a, b].\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:4\nmsgid \"This algorithm is pretty nifty, and pretty dense.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:6\nmsgid \"set of points defining the bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:8\nmsgid \"lower bound of the desired partial bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:10\nmsgid \"upper bound of the desired partial bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.partial_bezier_points:13\nmsgid \"Set of points defining the partial bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:1\nmsgid \"Checks if a given point lies on the bezier curves with the given control points.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:3\nmsgid \"This is done by solving the bezier polynomial with the point as the constant term; if any real roots exist, the point lies on the bezier curve.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:6\nmsgid \"The Cartesian Coordinates of the point to check.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:7\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:11\nmsgid \"The Cartesian Coordinates of the ordered control points of the bezier curve on which the point may or may not lie.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:10\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:14\nmsgid \"A float whose number of decimal places all values such as coordinates of points will be rounded.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.point_lies_on_bezier:13\nmsgid \"Whether the point lies on the curve.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:1\nmsgid \"Obtains the proportion along the bezier curve corresponding to a given point given the bezier curve's control points.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:4\nmsgid \"The bezier polynomial is constructed using the coordinates of the given point as well as the bezier curve's control points. On solving the polynomial for each dimension, if there are roots common to every dimension, those roots give the proportion along the curve the point is at. If there are no real roots, the point does not lie on the curve.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:9\nmsgid \"The Cartesian Coordinates of the point whose parameter should be obtained.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:17\nmsgid \"List containing possible parameters (the proportions along the bezier curve) for the given point on the given bezier curve. This usually only contains one or zero elements, but if the point is, say, at the beginning/end of a closed loop, may return a list with more than 1 value, corresponding to the beginning and end etc. of the loop.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.proportions_along_bezier_curve_for_point:25\nmsgid \"When ``point`` and the control points have different shapes.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.quadratic_bezier_remap:1\nmsgid \"Remaps the number of curves to a higher amount by splitting bezier curves\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.quadratic_bezier_remap:3\nmsgid \"The triplets of the quadratic bezier curves to be remapped\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.quadratic_bezier_remap:4\nmsgid \"The number of curves that the output will contain. This needs to be higher than the current number.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:1\nmsgid \"Split a quadratic Bézier curve at argument ``t`` into two quadratic curves.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:3\nmsgid \"The control points of the bezier curve has shape ``[a1, h1, b1]``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:5\nmsgid \"The ``t``-value at which to split the Bézier curve\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:7\nmsgid \"* *The two Bézier curves as a list of tuples,* * has the shape ``[a1, h1, b1], [a2, h2, b2]``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:7\nmsgid \"*The two Bézier curves as a list of tuples,*\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.split_quadratic_bezier:8\nmsgid \"has the shape ``[a1, h1, b1], [a2, h2, b2]``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.subdivide_quadratic_bezier:1\nmsgid \"Subdivide a quadratic Bézier curve into ``n`` subcurves which have the same shape.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.subdivide_quadratic_bezier:3\nmsgid \"The points at which the curve is split are located at the arguments :math:`t = i/n` for :math:`i = 1, ..., n-1`.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.subdivide_quadratic_bezier:6\nmsgid \"The control points of the Bézier curve in form ``[a1, h1, b1]``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/bezier.py:docstring of manim.utils.bezier.subdivide_quadratic_bezier:7\nmsgid \"The number of curves to subdivide the Bézier curve into\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.color.Colors.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.color.Colors.rst:2\nmsgid \"Colors\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.color.Colors.rst:4\nmsgid \"Qualified name: ``manim.utils.color.Colors``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.Colors:1\nmsgid \"Bases: :py:class:`enum.Enum`\"\nmsgstr \"\"\n\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.Colors:1\nmsgid \"A list of pre-defined colors.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.Colors:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.Colors:119\nmsgid \"The preferred way of using these colors is by importing their constants from manim:\"\nmsgstr \"\"\n\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.Colors:127\nmsgid \"Note this way uses the name of the colors in UPPERCASE.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.Colors:129\nmsgid \"Alternatively, you can also import this Enum directly and use its members directly, through the use of :code:`color.value`.  Note this way uses the name of the colors in lowercase.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.Colors:141\nmsgid \"The colors of type \\\"C\\\" have an alias equal to the colorname without a letter, e.g. GREEN = GREEN_C\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.color.Colors.rst:16\nmsgid \"Attributes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.color.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.color.rst:2\nmsgid \"color\"\nmsgstr \"\"\n\n#: ../../../manim/utils/color.py:docstring of manim.utils.color:1\nmsgid \"Colors and utility functions for conversion between different color models.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.color.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.color.rst:26:<autosummary>:1\nmsgid \"A list of pre-defined colors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.color.rst:29\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.average_color:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.color_gradient:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_int_rgb:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_int_rgba:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_rgb:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_rgba:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.get_shaded_rgb:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.hex_to_rgb:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.interpolate_color:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.invert_color:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.rgb_to_color:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.rgb_to_hex:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.rgba_to_color:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.average_color:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.color_gradient:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_int_rgb:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_int_rgba:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_rgb:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.color_to_rgba:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.get_shaded_rgb:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.hex_to_rgb:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.interpolate_color:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.invert_color:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.random_bright_color:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.random_color:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.rgb_to_color:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.rgb_to_hex:0\n#: ../../../manim/utils/color.py:docstring of manim.utils.color.rgba_to_color:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.commands.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.commands.rst:2\nmsgid \"commands\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.commands.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/commands.py:docstring of manim.utils.commands.get_dir_layout:1\nmsgid \"Get list of paths relative to dirpath of all files in dir and subdirs recursively.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/commands.py:docstring of manim.utils.commands.get_dir_layout:0\n#: ../../../manim/utils/commands.py:docstring of manim.utils.commands.get_video_metadata:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.config_ops.DictAsObject.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.config_ops.DictAsObject.rst:2\nmsgid \"DictAsObject\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.config_ops.DictAsObject.rst:4\nmsgid \"Qualified name: ``manim.utils.config\\\\_ops.DictAsObject``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/config_ops.py:docstring of manim.utils.config_ops.DictAsObject:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.config_ops.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.config_ops.rst:2\nmsgid \"config\\\\_ops\"\nmsgstr \"\"\n\n#: ../../../manim/utils/config_ops.py:docstring of manim.utils.config_ops:1\nmsgid \"Utilities that might be useful for configuration dictionaries.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.config_ops.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.config_ops.rst:29\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/config_ops.py:docstring of manim.utils.config_ops.merge_dicts_recursively:1\nmsgid \"Creates a dict whose keyset is the union of all the input dictionaries.  The value for each key is based on the first dict in the list with that key.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/config_ops.py:docstring of manim.utils.config_ops.merge_dicts_recursively:5\nmsgid \"dicts later in the list have higher priority\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.debug.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.debug.rst:2\nmsgid \"debug\"\nmsgstr \"\"\n\n#: ../../../manim/utils/debug.py:docstring of manim.utils.debug:1\nmsgid \"Debugging utilities.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.debug.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:1\nmsgid \"Returns a :class:`~.VGroup` of :class:`~.Integer` mobjects that shows the index of each submobject.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:4\nmsgid \"Useful for working with parts of complicated mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:6\nmsgid \"The mobject that will have its submobjects labelled.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:7\nmsgid \"The height of the labels, by default 0.15.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:8\nmsgid \"The stroke width of the outline of the labels, by default 5.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:9\nmsgid \"The stroke color of the outline of labels.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:10\nmsgid \"Additional parameters to be passed into the :class`~.Integer` mobjects used to construct the labels.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/debug.py:docstring of manim.utils.debug.index_labels:14\nmsgid \"Examples\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.deprecation.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.deprecation.rst:2\nmsgid \"deprecation\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation:1\nmsgid \"Decorators for deprecating classes, functions and function parameters.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.deprecation.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:1\nmsgid \"Decorator to mark a callable as deprecated.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:3\nmsgid \"The decorated callable will cause a warning when used. The docstring of the deprecated callable is adjusted to indicate that this callable is deprecated.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:0\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:6\nmsgid \"The function to be decorated. Should not be set by the user.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:7\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:10\nmsgid \"The version or date since deprecation.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:8\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:11\nmsgid \"The version or date until removal of the deprecated callable.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:9\nmsgid \"The identifier of the callable replacing the deprecated one.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:10\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:12\nmsgid \"The reason for why the callable has been deprecated.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:0\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:12\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:25\nmsgid \"The decorated callable.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:0\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:16\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:32\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:17\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:33\nmsgid \"Basic usage::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:43\nmsgid \"You can specify additional information for a more precise warning::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated:59\nmsgid \"You may also use dates instead of versions::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:1\nmsgid \"Decorator to mark parameters of a callable as deprecated.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:3\nmsgid \"It can also be used to automatically redirect deprecated parameter values to their replacements.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:6\nmsgid \"The parameters to be deprecated. Can consist of:  * An iterable of strings, with each element representing a parameter to deprecate * A single string, with parameter names separated by commas or spaces.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:6\nmsgid \"The parameters to be deprecated. Can consist of:\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:8\nmsgid \"An iterable of strings, with each element representing a parameter to deprecate\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:9\nmsgid \"A single string, with parameter names separated by commas or spaces.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:13\nmsgid \"A list of parameter redirections. Each redirection can be one of the following:  * A tuple of two strings. The first string defines the name of the deprecated   parameter; the second string defines the name of the parameter to redirect to,   when attempting to use the first string.  * A function performing the mapping operation. The parameter names of the   function determine which parameters are used as input. The function must   return a dictionary which contains the redirected arguments.  Redirected parameters are also implicitly deprecated.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:13\nmsgid \"A list of parameter redirections. Each redirection can be one of the following:\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:15\nmsgid \"A tuple of two strings. The first string defines the name of the deprecated parameter; the second string defines the name of the parameter to redirect to, when attempting to use the first string.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:19\nmsgid \"A function performing the mapping operation. The parameter names of the function determine which parameters are used as input. The function must return a dictionary which contains the redirected arguments.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:23\nmsgid \"Redirected parameters are also implicitly deprecated.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:28\nmsgid \"If no parameters are defined (neither explicitly nor implicitly).\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:29\nmsgid \"If defined parameters are invalid python identifiers.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:47\nmsgid \"You can also specify additional information for a more precise warning::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:63\nmsgid \"Basic parameter redirection::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:79\nmsgid \"Redirecting using a calculated value::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/deprecation.py:docstring of manim.utils.deprecation.deprecated_params:93\nmsgid \"Redirecting multiple parameter values to one::\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.docbuild.manim_directive.ManimDirective.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.docbuild.manim_directive.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.docbuild.manim_directive.skip_manim_node.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.docbuild.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.hashing.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.hashing.rst:2\nmsgid \"hashing\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing:1\nmsgid \"Utilities for scene caching.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.hashing.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:1\nmsgid \"Take the list of animations and a list of mobjects and output their hashes. This is meant to be used for `scene.play` function.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:0\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_json:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:3\nmsgid \"The scene object.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:5\nmsgid \"The camera object used in the scene.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:7\nmsgid \"The list of animations.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:9\nmsgid \"The list of mobjects.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:0\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_json:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:12\nmsgid \"A string concatenation of the respective hashes of `camera_object`, `animations_list` and `current_mobjects_list`, separated by `_`.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_hash_from_play_call:0\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_json:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_json:1\nmsgid \"Recursively serialize `object` to JSON using the :class:`CustomEncoder` class.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/hashing.py:docstring of manim.utils.hashing.get_json:3\nmsgid \"The dict to flatten\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.images.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.images.rst:2\nmsgid \"images\"\nmsgstr \"\"\n\n#: ../../../manim/utils/images.py:docstring of manim.utils.images:1\nmsgid \"Image manipulation utilities.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.images.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/images.py:docstring of manim.utils.images.change_to_rgba_array:1\nmsgid \"Converts an RGB array into RGBA with the alpha value opacity maxed.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/images.py:docstring of manim.utils.images.drag_pixels:0\n#: ../../../manim/utils/images.py:docstring of manim.utils.images.get_full_raster_image_path:0\n#: ../../../manim/utils/images.py:docstring of manim.utils.images.invert_image:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.ipython_magic.ManimMagic.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.ipython_magic.ManimMagic.rst:2\nmsgid \"ManimMagic\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.ipython_magic.ManimMagic.rst:4\nmsgid \"Qualified name: ``manim.utils.ipython\\\\_magic.ManimMagic``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:1\nmsgid \"Bases: :py:class:`IPython.core.magic.Magics`\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:1\nmsgid \"Create a configurable given a config config.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:0\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:3\nmsgid \"If this is empty, default values are used. If config is a :class:`Config` instance, it will be used to configure the instance.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:7\nmsgid \"The parent Configurable instance of this object.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:11\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:12\nmsgid \"Subclasses of Configurable must call the :meth:`__init__` method of :class:`Configurable` *before* doing anything else and using :func:`super`::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic:21\nmsgid \"This ensures that instances will be configured properly.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.ipython_magic.ManimMagic.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.ipython_magic.ManimMagic.rst:21:<autosummary>:1\nmsgid \"Render Manim scenes contained in IPython cells.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.ipython_magic.ManimMagic.rst:23\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:1:<autosummary>:1\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:1:<autosummary>:1\nmsgid \"A trait whose value must be an instance of a specified class.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:1:<autosummary>:1\nmsgid \"A contextmanager for running a block with our cross validation lock set to True.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:1\nmsgid \"Render Manim scenes contained in IPython cells. Works as a line or cell magic.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:6\nmsgid \"This line and cell magic works best when used in a JupyterLab environment: while all of the functionality is available for classic Jupyter notebooks as well, it is possible that videos sometimes don't update on repeated execution of the same cell if the scene name stays the same.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:12\nmsgid \"This problem does not occur when using JupyterLab.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:14\nmsgid \"Please refer to `<https://jupyter.org/>`_ for more information about JupyterLab and Jupyter notebooks.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:17\nmsgid \"Usage in line mode::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:21\nmsgid \"Usage in cell mode::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:29\nmsgid \"Run ``%manim --help`` and ``%manim render --help`` for possible command line interface options.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:33\nmsgid \"The maximal width of the rendered videos that are displayed in the notebook can be configured via the ``media_width`` configuration option. The default is set to ``25vw``, which is 25% of your current viewport width. To allow the output to become as large as possible, set ``config.media_width = \\\"100%\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:38\nmsgid \"The ``media_embed`` option will embed the image/video output in the notebook. This is generally undesirable as it makes the notebooks very large, but is required on some platforms (notably Google's CoLab, where it is automatically enabled unless suppressed by ``config.embed = False``) and needed in cases when the notebook (or converted HTML file) will be moved relative to the video locations. Use-cases include building documentation with Sphinx and JupyterBook. See also the :mod:`manim directive for Sphinx <manim.utils.docbuild.manim_directive>`.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:47\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:48\nmsgid \"First make sure to put ``import manim``, or even ``from manim import *`` in a cell and evaluate it. Then, a typical Jupyter notebook cell for Manim could look as follows::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:64\nmsgid \"Evaluating this cell will render and display the ``BannerExample`` scene defined in the body of the cell.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic.ManimMagic.manim:68\nmsgid \"In case you want to hide the red box containing the output progress bar, the ``progress_bar`` config option should be set to ``None``. This can also be done by passing ``--progress_bar None`` as a CLI flag.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.ipython_magic.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.ipython_magic.rst:2\nmsgid \"ipython\\\\_magic\"\nmsgstr \"\"\n\n#: ../../../manim/utils/ipython_magic.py:docstring of manim.utils.ipython_magic:1\nmsgid \"Utilities for using Manim with IPython (in particular: Jupyter notebooks)\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.ipython_magic.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.iterables.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.iterables.rst:2\nmsgid \"iterables\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables:1\nmsgid \"Operations on iterables.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.iterables.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:1\nmsgid \"Returns the Sequence objects cyclically split into n length tuples.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:6\nmsgid \"alias with n=2\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:9\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_pairs:6\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.batch_by_property:8\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.concatenate_lists:4\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_difference_update:4\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:6\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.listify:4\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:10\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:10\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_nones:4\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:13\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:16\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:16\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.tuplify:4\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.uniq_chain:5\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:10\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_pairs:7\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.batch_by_property:9\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.concatenate_lists:5\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_difference_update:5\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:7\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.listify:5\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:11\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:11\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_nones:5\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:14\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:17\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:17\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.tuplify:5\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.uniq_chain:6\nmsgid \"Normal usage::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_pairs:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.all_elements_are_instances:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.batch_by_property:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.concatenate_lists:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_difference_update:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_list_redundancies:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_nones:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.stretch_array_to_length:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.uniq_chain:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_n_tuples:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_pairs:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.all_elements_are_instances:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.batch_by_property:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.concatenate_lists:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_difference_update:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.listify:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_list_redundancies:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_nones:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.stretch_array_to_length:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.tuplify:0\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.uniq_chain:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.adjacent_pairs:1\nmsgid \"Alias for ``adjacent_n_tuples(objects, 2)``.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.all_elements_are_instances:1\nmsgid \"Returns ``True`` if all elements of iterable are instances of Class. False otherwise.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.batch_by_property:1\nmsgid \"Takes in a Sequence, and returns a list of tuples, (batch, prop) such that all items in a batch have the same output when put into the Callable property_func, and such that chaining all these batches together would give the original Sequence (i.e. order is preserved).\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.concatenate_lists:1\nmsgid \"Combines the Iterables provided as arguments into one list.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_difference_update:1\nmsgid \"Returns a list containing all the elements of l1 not in l2.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:3\nmsgid \"Used instead of ``set.update()`` to maintain order,\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.list_update:2\nmsgid \"making sure duplicates are removed from l1, not l2. Removes overlap of l1 and l2 and then concatenates l2 unchanged.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.listify:1\nmsgid \"Converts obj to a list intelligently.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:2\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:2\nmsgid \"Extends the shorter of the two iterables with duplicate values until its\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:2\nmsgid \"length is equal to the longer iterable (favours earlier elements).\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even:7\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:10\nmsgid \"cycles elements instead of favouring earlier ones\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:2\nmsgid \"length is equal to the longer iterable (cycles over shorter iterable).\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.make_even_by_cycling:7\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:7\nmsgid \"favours earlier elements instead of cycling them\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_list_redundancies:1\nmsgid \"Used instead of ``list(set(l))`` to maintain order. Keeps the last occurrence of each element.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.remove_nones:1\nmsgid \"Removes elements where bool(x) evaluates to False.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:2\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:5\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:5\nmsgid \"Extends/truncates nparray so that ``len(result) == length``.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:2\nmsgid \"The elements of nparray are cycled to achieve the desired length.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_array:10\nmsgid \"similar cycling behaviour for balancing 2 iterables\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:2\nmsgid \"The elements of nparray are duplicated to achieve the desired length (favours earlier elements).\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:5\nmsgid \"Constructs a zeroes array of length if nparray is empty.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_preserving_order:13\nmsgid \"similar earlier-favouring behaviour for balancing 2 iterables\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:2\nmsgid \"New elements are interpolated to achieve the desired length.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:4\nmsgid \"Note that if nparray's length changes, its dtype may too (e.g. int -> float: see Examples)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:10\nmsgid \"cycles elements instead of interpolating\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.resize_with_interpolation:13\nmsgid \"favours earlier elements instead of interpolating\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.tuplify:1\nmsgid \"Converts obj to a tuple intelligently.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/iterables.py:docstring of manim.utils.iterables.uniq_chain:2\nmsgid \"Returns a generator that yields all unique elements of the Iterables\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.paths.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.paths.rst:2\nmsgid \"paths\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths:1\nmsgid \"Functions determining transformation paths between sets of points.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.paths.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.clockwise_path:1\nmsgid \"This function transforms each point by moving clockwise around a half circle.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.clockwise_path:4\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.counterclockwise_path:4\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:7\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:10\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:7\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.straight_path:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.clockwise_path:0\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.counterclockwise_path:0\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:0\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:0\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:0\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.straight_path:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.counterclockwise_path:1\nmsgid \"This function transforms each point by moving counterclockwise around a half circle.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:1\nmsgid \"This function transforms each point by moving it along a circular arc.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:0\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:0\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:3\nmsgid \"The angle each point traverses around a circular arc.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_arc:4\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:7\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:4\nmsgid \"The axis of rotation.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:1\nmsgid \"This function transforms each point by moving it roughly along a circle, each with its own specified center.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:3\nmsgid \"The path may be seen as each point smoothly changing its orbit from its starting position to its destination.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:5\nmsgid \"The angle each point traverses around the quasicircle.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.path_along_circles:6\nmsgid \"The centers of each point's quasicircle to rotate around.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:1\nmsgid \"This function transforms each point by moving along a spiral to its destination.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/paths.py:docstring of manim.utils.paths.spiral_path:3\nmsgid \"The angle each point traverses around a spiral.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.rate_functions.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.rate_functions.rst:2\nmsgid \"rate\\\\_functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:1\nmsgid \"A selection of rate functions, i.e., *speed curves* for animations. Please find a standard list at https://easings.net/. Here is a picture for the non-standard ones\"\nmsgstr \"\"\n\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:46\nmsgid \"There are primarily 3 kinds of standard easing functions:\"\nmsgstr \"\"\n\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:48\nmsgid \"Ease In - The animation has a smooth start.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:49\nmsgid \"Ease Out - The animation has a smooth end.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:50\nmsgid \"Ease In Out - The animation has a smooth start as well as smooth end.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions:52\nmsgid \"The standard functions are not exported, so to use them you do something like this: rate_func=rate_functions.ease_in_sine On the other hand, the non-standard functions, which are used more commonly, are exported and can be used directly.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.rate_functions.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.double_smooth:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_back:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_bounce:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_circ:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_cubic:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_elastic:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_expo:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_back:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_bounce:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_circ:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_cubic:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_elastic:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_expo:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_quad:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_quart:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_quint:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_out_sine:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_quad:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_quart:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_quint:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_in_sine:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_back:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_bounce:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_circ:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_cubic:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_elastic:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_expo:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_quad:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_quart:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_quint:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.ease_out_sine:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.exponential_decay:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.linear:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.lingering:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.not_quite_there:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.running_start:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.rush_from:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.rush_into:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.slow_into:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.smooth:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.squish_rate_func:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.there_and_back:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.there_and_back_with_pause:0\n#: ../../../manim/utils/rate_functions.py:docstring of manim.utils.rate_functions.wiggle:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.scale.LinearBase.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.scale.LogBase.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.scale.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.simple_functions.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.simple_functions.rst:2\nmsgid \"simple\\\\_functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions:1\nmsgid \"A collection of simple functions.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.simple_functions.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:1\nmsgid \"Searches for a value in a range by repeatedly dividing the range in half.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:3\nmsgid \"To be more precise, performs numerical binary search to determine the input to ``function``, between the bounds given, that outputs ``target`` to within ``tolerance`` (default of 0.0001). Returns ``None`` if no input can be found within the bounds.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:9\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.clip:8\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.get_parameters:5\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:10\nmsgid \"Consider the polynomial :math:`x^2 + 3x + 1` where we search for a target value of :math:`11`. An exact solution is :math:`x = 2`.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:22\nmsgid \"Searching in the interval :math:`[0, 5]` for a target value of :math:`71` does not yield a solution::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:0\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:0\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.get_parameters:0\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.binary_search:0\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:0\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.get_parameters:0\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:1\nmsgid \"The binomial coefficient n choose k.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:3\nmsgid \":math:`\\\\binom{n}{k}` describes the number of possible choices of :math:`k` elements from a set of :math:`n` elements.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:7\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:7\nmsgid \"References\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:8\nmsgid \"https://en.wikipedia.org/wiki/Combination\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.choose:9\nmsgid \"https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.comb.html\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.clip:1\nmsgid \"Clips ``a`` to the interval [``min_a``, ``max_a``].\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.clip:3\nmsgid \"Accepts any comparable objects (i.e. those that support <, >). Returns ``a`` if it is between ``min_a`` and ``max_a``. Otherwise, whichever of ``min_a`` and ``max_a`` is closest.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.get_parameters:1\nmsgid \"Return the parameters of ``function`` as an ordered mapping of parameters' names to their corresponding ``Parameter`` objects.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:1\nmsgid \"Returns the output of the logistic function.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:3\nmsgid \"The logistic function, a common example of a sigmoid function, is defined as :math:`\\\\frac{1}{1 + e^{-x}}`.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/simple_functions.py:docstring of manim.utils.simple_functions.sigmoid:8\nmsgid \"https://en.wikipedia.org/wiki/Sigmoid_function\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.sounds.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.sounds.rst:2\nmsgid \"sounds\"\nmsgstr \"\"\n\n#: ../../../manim/utils/sounds.py:docstring of manim.utils.sounds:1\nmsgid \"Sound-related utility functions.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.space_ops.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.space_ops.rst:2\nmsgid \"space\\\\_ops\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops:1\nmsgid \"Utility functions for two- and three-dimensional vectors.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.space_ops.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.R3_to_complex:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.cartesian_to_spherical:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.complex_to_R3:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.find_intersection:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_winding_number:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.norm_squared:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_mult:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_from_quaternion:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace_direction:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.thick_diagonal:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.z_to_vector:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.R3_to_complex:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.cartesian_to_spherical:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.complex_to_R3:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.find_intersection:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_winding_number:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.norm_squared:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_mult:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_from_quaternion:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace_direction:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.thick_diagonal:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.z_to_vector:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:1\nmsgid \"Gets angle and axis from a quaternion.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:3\nmsgid \"The quaternion from which we get the angle and axis.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_mult:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace_direction:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_axis_from_quaternion:5\nmsgid \"Gives the angle and axis\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:1\nmsgid \"Returns the angle between two vectors. This angle will always be between 0 and pi\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:4\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:3\nmsgid \"The first vector.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:5\nmsgid \"The second vector.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_between_vectors:7\nmsgid \"The angle between the vectors.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:1\nmsgid \"Returns polar coordinate theta when vector is projected on xy plane.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:3\nmsgid \"The vector to find the angle for.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.angle_of_vector:5\nmsgid \"The angle of the vector projected.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.cartesian_to_spherical:1\nmsgid \"Returns an array of numbers corresponding to each polar coordinate value (distance, phi, theta).\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.cartesian_to_spherical:4\nmsgid \"A numpy array ``[x, y, z]``.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:1\nmsgid \"Gets the center of mass of the points in space.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:3\nmsgid \"The points to find the center of mass from.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.center_of_mass:5\nmsgid \"The center of mass of the points.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:1\nmsgid \"Finds the cardinal directions using tau.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:3\nmsgid \"The amount to be rotated, by default 4\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:4\nmsgid \"The direction for the angle to start with, by default RIGHT\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.compass_directions:6\nmsgid \"The angle which has been rotated.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:1\nmsgid \"Returns a list of indices giving a triangulation of a polygon, potentially with holes.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:4\nmsgid \"verts is a numpy array of points.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:5\nmsgid \"ring_ends is a list of indices indicating where\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.earclip_triangulation:8\nmsgid \"A list of indices giving a triangulation of a polygon.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.find_intersection:1\nmsgid \"Return the intersection of a line passing through p0 in direction v0 with one passing through p1 in direction v1 (or array of intersections from arrays of such points/directions). For 3d values, it returns the point on the ray p0 + v0 * t closest to the ray p1 + v1 * t\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:1\nmsgid \"Gets the unit normal of the vectors.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:4\nmsgid \"The second vector\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:5\nmsgid \"[description], by default 1e-6\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.get_unit_normal:7\nmsgid \"The normal of the two vectors.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:1\nmsgid \"Returns the intersection point of two lines, each defined by a pair of distinct points lying on the line.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:4\nmsgid \"A list of two points that determine the first line.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:5\nmsgid \"A list of two points that determine the second line.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:7\nmsgid \"The intersection points of the two lines which are intersecting.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:0\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:0\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.line_intersection:10\nmsgid \"Error is produced if the two lines don't intersect with each other     or if the coordinates don't lie on the xy-plane.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:1\nmsgid \"Gets the midpoint of two points.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:3\nmsgid \"The first point.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:4\nmsgid \"The second point.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.midpoint:6\nmsgid \"The midpoint of the points\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:1\nmsgid \"Normalizes an array with the provided axis.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:3\nmsgid \"The array which has to be normalized.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:4\nmsgid \"The axis to be normalized to.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.normalize_along_axis:6\nmsgid \"Array which has been normalized according to the axis.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:1\nmsgid \"Returns a list of two points that correspond to the ends of the perpendicular bisector of the two points given.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:5\nmsgid \"a list of two numpy array points (corresponding to the ends of a line).\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:7\nmsgid \"the vector perpendicular to both the line given and the perpendicular bisector.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.perpendicular_bisector:10\nmsgid \"A list of two numpy array points that correspond to the ends of the perpendicular bisector\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:1\nmsgid \"Used for finding the conjugate of the quaternion\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:3\nmsgid \"The quaternion for which you want to find the conjugate for.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_conjugate:5\nmsgid \"The conjugate of the quaternion.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:1\nmsgid \"Gets a quaternion from an angle and an axis. For more information, check `this Wikipedia page <https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles>`__.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:5\nmsgid \"The angle for the quaternion.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:6\nmsgid \"The axis for the quaternion\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:7\nmsgid \"Checks whether the axis is normalized, by default False\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_from_angle_axis:10\nmsgid \"Gives back a quaternion from the angle and axis\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_mult:1\nmsgid \"Gets the Hamilton product of the quaternions provided. For more information, check `this Wikipedia page <https://en.wikipedia.org/wiki/Quaternion>`__.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.quaternion_mult:5\nmsgid \"Returns a list of product of two quaternions.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:1\nmsgid \"Generates regularly spaced vertices around a circle centered at the origin.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:3\nmsgid \"The number of vertices\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:4\nmsgid \"The radius of the circle that the vertices are placed on.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:5\nmsgid \"The angle the vertices start at.  If unspecified, for even ``n`` values, ``0`` will be used. For odd ``n`` values, 90 degrees is used.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:5\nmsgid \"The angle the vertices start at.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:7\nmsgid \"If unspecified, for even ``n`` values, ``0`` will be used. For odd ``n`` values, 90 degrees is used.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:10\nmsgid \"* **vertices** (:class:`numpy.ndarray`) -- The regularly spaced vertices. * **start_angle** (:class:`float`) -- The angle the vertices start at.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:10\nmsgid \"**vertices** (:class:`numpy.ndarray`) -- The regularly spaced vertices.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.regular_vertices:11\nmsgid \"**start_angle** (:class:`float`) -- The angle the vertices start at.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:1\nmsgid \"Function for rotating a vector.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:3\nmsgid \"The vector to be rotated.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:4\nmsgid \"The angle to be rotated by.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:5\nmsgid \"The axis to be rotated, by default OUT\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:7\nmsgid \"The rotated vector with provided angle and axis.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotate_vector:10\nmsgid \"If vector is not of dimension 2 or 3.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:1\nmsgid \"Returns a rotation matrix for a given angle.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:3\nmsgid \"Angle for the rotation matrix.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_about_z:6\nmsgid \"Gives back the rotated matrix.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix:1\nmsgid \"Rotation in R^3 about a specified axis of rotation.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:1\nmsgid \"Converts the quaternion, quat, to an equivalent rotation matrix representation. For more information, check `this page <https://in.mathworks.com/help/driving/ref/quaternion.rotmat.html>`_.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:5\nmsgid \"The quaternion which is to be converted.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.rotation_matrix_transpose_from_quaternion:7\nmsgid \"Gives back the Rotation matrix representation, returned as a 3-by-3 matrix or 3-by-3-by-N multidimensional array.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace:1\nmsgid \"2D implementation of the shoelace formula.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace:3\nmsgid \"Returns signed area.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace_direction:1\nmsgid \"Uses the area determined by the shoelace method to determine whether the input set of points is directed clockwise or counterclockwise.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.shoelace_direction:4\nmsgid \"Either ``\\\"CW\\\"`` or ``\\\"CCW\\\"``.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:1\nmsgid \"Returns a numpy array ``[x, y, z]`` based on the spherical coordinates given.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:4\nmsgid \"A list of three floats that correspond to the following:  r - The distance between the point and the origin.  theta - The azimuthal angle of the point to the positive x-axis.  phi - The vertical angle of the point to the positive z-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:4\nmsgid \"A list of three floats that correspond to the following:\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:6\nmsgid \"r - The distance between the point and the origin.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:8\nmsgid \"theta - The azimuthal angle of the point to the positive x-axis.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/space_ops.py:docstring of manim.utils.space_ops.spherical_to_cartesian:10\nmsgid \"phi - The vertical angle of the point to the positive z-axis.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.strings.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.tex.TexTemplate.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplate.rst:2\nmsgid \"TexTemplate\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplate.rst:4\nmsgid \"Qualified name: ``manim.utils.tex.TexTemplate``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:1\nmsgid \"TeX templates are used for creating Tex() and MathTex() objects.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_document:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_preamble:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:3\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:18\nmsgid \"The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:5\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:24\nmsgid \"The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:7\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:30\nmsgid \"The command defining the documentclass, e.g. ``\\\\documentclass[preview]{standalone}``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:9\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:36\nmsgid \"The document's preamble, i.e. the part between ``\\\\documentclass`` and ``\\\\begin{document}``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:11\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:42\nmsgid \"Text in the document that will be replaced by the expression to be rendered\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:13\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:48\nmsgid \"Text (definitions, commands) to be inserted at right after ``\\\\begin{document}``, e.g. ``\\\\boldmath``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate:0\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplate.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplate.rst:24:<autosummary>:1\nmsgid \"Adds txt to the TeX template just after \\\\begin{document}, e.g.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplate.rst:24:<autosummary>:1\nmsgid \"Adds stuff to the TeX template's preamble (e.g.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplate.rst:24:<autosummary>:1\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:1\nmsgid \"Inserts expression verbatim into TeX template.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplate.rst:24:<autosummary>:1\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:1\nmsgid \"Inserts expression into TeX template wrapped in \\\\begin{environment} and \\\\end{environment}\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplate.rst:26\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_document:1\nmsgid \"Adds txt to the TeX template just after \\\\begin{document}, e.g. ``\\\\boldmath``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_document:3\nmsgid \"String containing the text to be added.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_preamble:1\nmsgid \"Adds stuff to the TeX template's preamble (e.g. definitions, packages). Text can be inserted at the beginning or at the end of the preamble.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_preamble:3\nmsgid \"String containing the text to be added, e.g. ``\\\\usepackage{hyperref}``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.add_to_preamble:5\nmsgid \"Whether the text should be added at the beginning of the preamble, i.e. right after ``\\\\documentclass``. Default is to add it at the end of the preamble, i.e. right before ``\\\\begin{document}``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:3\nmsgid \"The string containing the expression to be typeset, e.g. ``$\\\\sqrt{2}$``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:6\nmsgid \"LaTeX code based on current template, containing the given ``expression`` and ready for typesetting\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:3\nmsgid \"The string containing the expression to be typeset, e.g. ``$\\\\\\\\sqrt{2}$``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplate.get_texcode_for_expression_in_env:5\nmsgid \"The string containing the environment in which the expression should be typeset, e.g. ``align*``\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.tex.TexTemplateFromFile.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:2\nmsgid \"TexTemplateFromFile\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:4\nmsgid \"Qualified name: ``manim.utils.tex.TexTemplateFromFile``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:1\nmsgid \"Bases: :py:class:`manim.utils.tex.TexTemplate`\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:1\nmsgid \"A TexTemplate object created from a template file (default: tex_template.tex)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_document:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_preamble:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:3\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:35\nmsgid \"The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:5\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:41\nmsgid \"The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:7\nmsgid \"The command defining the documentclass, e.g. ``\\\\documentclass[preview]{standalone}``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:9\nmsgid \"The document's preamble, i.e. the part between ``\\\\documentclass`` and ``\\\\begin{document}``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:11\nmsgid \"Text in the document that will be replaced by the expression to be rendered\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:13\nmsgid \"Text (definitions, commands) to be inserted at right after ``\\\\begin{document}``, e.g. ``\\\\boldmath``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:15\nmsgid \"The kwargs specified can only be strings.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:18\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:23\nmsgid \"Path to a valid TeX template file\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:0\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:0\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile:29\nmsgid \"Content of the TeX template file\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:22:<autosummary>:1\nmsgid \"Adds txt to the TeX template just after \\\\begin{document}, e.g.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:22:<autosummary>:1\nmsgid \"Adds stuff to the TeX template's preamble (e.g.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.TexTemplateFromFile.rst:24\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_document:1\nmsgid \"Adds txt to the TeX template just after \\\\begin{document}, e.g. ``\\\\boldmath``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_document:3\nmsgid \"String containing the text to be added.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_preamble:1\nmsgid \"Adds stuff to the TeX template's preamble (e.g. definitions, packages). Text can be inserted at the beginning or at the end of the preamble.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex.TexTemplateFromFile.add_to_preamble:3\nmsgid \"String containing the text to be added, e.g. ``\\\\usepackage{hyperref}``\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.tex.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.tex.rst:2\nmsgid \"tex\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex.py:docstring of manim.utils.tex:1\nmsgid \"Utilities for processing LaTeX templates.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex.rst:22:<autosummary>:1\nmsgid \"TeX templates are used for creating Tex() and MathTex() objects.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.tex_file_writing.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.tex_file_writing.rst:2\nmsgid \"tex\\\\_file\\\\_writing\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing:1\nmsgid \"Interface for writing, compiling, and converting ``.tex`` files.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex_file_writing.rst:20\nmsgid \"Functions\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:1\nmsgid \"Compiles a tex_file into a .dvi or a .xdv or a .pdf\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:0\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:3\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:7\nmsgid \"File name of TeX file to be typeset.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:5\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:3\nmsgid \"String containing the compiler to be used, e.g. ``pdflatex`` or ``lualatex``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:7\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:5\nmsgid \"String containing the output format generated by the compiler, e.g. ``.dvi`` or ``.pdf``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:0\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:10\nmsgid \"Path to generated output file in desired format (DVI, XDV or PDF).\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.compile_tex:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:0\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:0\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:1\nmsgid \"Converts a .dvi, .xdv, or .pdf file into an svg using dvisvgm.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:3\nmsgid \"File name of the input file to be converted.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:5\nmsgid \"String containing the file extension and thus indicating the file type, e.g. ``.dvi`` or ``.pdf``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:7\nmsgid \"Page to be converted if input file is multi-page.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.convert_to_svg:10\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:10\nmsgid \"Path to generated SVG file.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:1\nmsgid \"Takes a tex expression (and an optional tex environment), and returns a fully formed tex file ready for compilation.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:4\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:3\nmsgid \"String containing the TeX expression to be rendered, e.g. ``\\\\sqrt{2}`` or ``foo``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:6\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:5\nmsgid \"The string containing the environment in which the expression should be typeset, e.g. ``align*``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:8\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_to_svg_file:7\nmsgid \"Template class used to typesetting. If not set, use default template set via `config[\\\"tex_template\\\"]`\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.generate_tex_file:11\nmsgid \"Path to generated TeX file\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:1\nmsgid \"Prepares the tex compilation command with all necessary cli flags\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:9\nmsgid \"Path to the directory where compiler output will be stored.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_file_writing.py:docstring of manim.utils.tex_file_writing.tex_compilation_command:12\nmsgid \"Compilation command according to given parameters\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.tex_templates.TexFontTemplates.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.tex_templates.TexFontTemplates.rst:2\nmsgid \"TexFontTemplates\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex_templates.TexFontTemplates.rst:4\nmsgid \"Qualified name: ``manim.utils.tex\\\\_templates.TexFontTemplates``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:1\nmsgid \"A collection of TeX templates for the fonts described at http://jf.burnol.free.fr/showcase.html\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:3\nmsgid \"These templates are specifically designed to allow you to typeset formulae and mathematics using different fonts. They are based on the mathastext LaTeX package.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:7\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:8\nmsgid \"Normal usage as a value for the keyword argument tex_template of Tex() and MathTex() mobjects::\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:13\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:14\nmsgid \"Many of these templates require that specific fonts are installed on your local machine. For example, choosing the template TexFontTemplates.comic_sans will not compile if the Comic Sans Microsoft font is not installed.\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:20\nmsgid \"To experiment, try to render the TexFontTemplateLibrary example scene:\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates:20\nmsgid \"``manim path/to/manim/example_scenes/advanced_tex_fonts.py TexFontTemplateLibrary -p -ql``\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex_templates.TexFontTemplates.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex_templates.TexFontTemplates.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1\nmsgid \"American Typewriter\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.antykwa:1\nmsgid \"Antykwa Półtawskiego (TX Fonts for Greek and math symbols)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.apple_chancery:1\nmsgid \"Apple Chancery\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.auriocus_kalligraphicus:1\nmsgid \"Auriocus Kalligraphicus (Symbol Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.baskervald_adf_fourier:1\nmsgid \"Baskervald ADF with Fourier\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.baskerville_it:1\nmsgid \"Baskerville (Italic)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.biolinum:1\nmsgid \"Biolinum\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.brushscriptx:1\nmsgid \"BrushScriptX-Italic (PX math and Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.chalkboard_se:1\nmsgid \"Chalkboard SE\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.chalkduster:1\nmsgid \"Chalkduster\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.comfortaa:1\nmsgid \"Comfortaa\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.comic_sans:1\nmsgid \"Comic Sans MS\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.droid_sans:1\nmsgid \"Droid Sans\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.droid_sans_it:1\nmsgid \"Droid Sans (Italic)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.droid_serif:1\nmsgid \"Droid Serif\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.droid_serif_px_it:1\nmsgid \"Droid Serif (PX math symbols) (Italic)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.ecf_augie:1\nmsgid \"ECF Augie (Euler Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.ecf_jd:1\nmsgid \"ECF JD (with TX fonts)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.ecf_skeetch:1\nmsgid \"ECF Skeetch (CM Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.ecf_tall_paul:1\nmsgid \"ECF Tall Paul (with Symbol font)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.ecf_webster:1\nmsgid \"ECF Webster (with TX fonts)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.electrum_adf:1\nmsgid \"Electrum ADF (CM Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.epigrafica:1\nmsgid \"Epigrafica\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.fourier_utopia:1\nmsgid \"Fourier Utopia (Fourier upright Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.french_cursive:1\nmsgid \"French Cursive (Euler Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.gfs_bodoni:1\nmsgid \"GFS Bodoni\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.gfs_didot:1\nmsgid \"GFS Didot (Italic)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.gfs_neoHellenic:1\nmsgid \"GFS NeoHellenic\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.gnu_freesans_tx:1\nmsgid \"GNU FreeSerif (and TX fonts symbols)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.gnu_freeserif_freesans:1\nmsgid \"GNU FreeSerif and FreeSans\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.helvetica_fourier_it:1\nmsgid \"Helvetica with Fourier (Italic)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.latin_modern_tw:1\nmsgid \"Latin Modern Typewriter Proportional\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.latin_modern_tw_it:1\nmsgid \"Latin Modern Typewriter Proportional (CM Greek) (Italic)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.libertine:1\nmsgid \"Libertine\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.libris_adf_fourier:1\nmsgid \"Libris ADF with Fourier\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.minion_pro_myriad_pro:1\nmsgid \"Minion Pro and Myriad Pro (and TX fonts symbols)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.minion_pro_tx:1\nmsgid \"Minion Pro (and TX fonts symbols)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.new_century_schoolbook:1\nmsgid \"New Century Schoolbook (Symbol Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.new_century_schoolbook_px:1\nmsgid \"New Century Schoolbook (Symbol Greek, PX math symbols)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.noteworthy_light:1\nmsgid \"Noteworthy Light\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.palatino:1\nmsgid \"Palatino (Symbol Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.papyrus:1\nmsgid \"Papyrus\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.romande_adf_fourier_it:1\nmsgid \"Romande ADF with Fourier (Italic)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.slitex:1\nmsgid \"SliTeX (Euler Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.times_fourier_it:1\nmsgid \"Times with Fourier (Italic)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.urw_avant_garde:1\nmsgid \"URW Avant Garde (Symbol Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.urw_zapf_chancery:1\nmsgid \"URW Zapf Chancery (CM Greek)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.venturis_adf_fourier_it:1\nmsgid \"Venturis ADF with Fourier (Italic)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.verdana_it:1\nmsgid \"Verdana (Italic)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.vollkorn:1\nmsgid \"Vollkorn (TX fonts for Greek and math symbols)\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexFontTemplates.american_typewriter:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexFontTemplates.vollkorn_fourier_it:1\nmsgid \"Vollkorn with Fourier (Italic)\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.tex_templates.TexTemplateLibrary.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.tex_templates.TexTemplateLibrary.rst:2\nmsgid \"TexTemplateLibrary\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex_templates.TexTemplateLibrary.rst:4\nmsgid \"Qualified name: ``manim.utils.tex\\\\_templates.TexTemplateLibrary``\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary:1\nmsgid \"Bases: :py:class:`object`\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary:1\nmsgid \"A collection of basic TeX template objects\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary:4\nmsgid \"Examples\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary:5\nmsgid \"Normal usage as a value for the keyword argument tex_template of Tex() and MathTex() mobjects::\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex_templates.TexTemplateLibrary.rst:14\nmsgid \"Methods\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex_templates.TexTemplateLibrary.rst:21\nmsgid \"Attributes\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary.ctex:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexTemplateLibrary.ctex:1\nmsgid \"An instance of the TeX template used by 3b1b when using the use_ctex flag\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary.ctex:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexTemplateLibrary.default:1\nmsgid \"An instance of the default TeX template in manim\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates.TexTemplateLibrary.ctex:1:<autosummary>:1\n#: ../../source/docstring of manim.utils.tex_templates.TexTemplateLibrary.simple:1\nmsgid \"An instance of a simple TeX template with only basic AMS packages loaded\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim.utils.tex_templates.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference/manim.utils.tex_templates.rst:2\nmsgid \"tex\\\\_templates\"\nmsgstr \"\"\n\n#: ../../../manim/utils/tex_templates.py:docstring of manim.utils.tex_templates:1\nmsgid \"A library of LaTeX templates.\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex_templates.rst:15\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../source/reference/manim.utils.tex_templates.rst:22:<autosummary>:1\nmsgid \"A collection of TeX templates for the fonts described at http://jf.burnol.free.fr/showcase.html\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim_directive.ManimDirective.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim_directive.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference/manim_directive.skip_manim_node.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/reference.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference.rst:2\nmsgid \"Reference Manual\"\nmsgstr \"\"\n\n#: ../../source/reference.rst:4\nmsgid \"This reference manual details modules, functions, and variables included in Manim, describing what they are and what they do.  For learning how to use Manim, see :doc:`tutorials/index`.  For a list of changes since the last release, see the :doc:`changelog`.\"\nmsgstr \"\"\n\n#: ../../source/reference.rst:9\nmsgid \"The pages linked to here are currently a work in progress.\"\nmsgstr \"\"\n\n#: ../../source/reference.rst:12\nmsgid \"Inheritance Graphs\"\nmsgstr \"\"\n\n#: ../../source/reference.rst:15\nmsgid \"Animations\"\nmsgstr \"\"\n\n#: ../../source/reference.rst:38\nmsgid \"Cameras\"\nmsgstr \"\"\n\n#: ../../source/reference.rst:50\nmsgid \"Mobjects\"\nmsgstr \"\"\n\n#: ../../source/reference.rst:88\nmsgid \"Scenes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference_index/animations.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference_index/animations.rst:2\nmsgid \"Animations\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Animate mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Animation of a mobject boundary and tracing of points.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Tools for displaying multiple animations at once.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Animate the display or removal of a mobject from a scene.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Fading in and out of view.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Animations that introduce mobjects to scene by growing them from points.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Animations drawing attention to particular mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Animations related to movement.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Animations for changing numbers.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Animations related to rotation.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Utilities for modifying the speed at which animations are played.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Animations transforming one mobject into another.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/animations.rst:23:<autosummary>:1\nmsgid \"Animations that try to transform Mobjects while keeping track of identical parts.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference_index/cameras.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference_index/cameras.rst:2\nmsgid \"Cameras\"\nmsgstr \"\"\n\n#: ../../source/reference_index/cameras.rst:13:<autosummary>:1\nmsgid \"A camera converts the mobjects contained in a Scene into an array of pixels.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/cameras.rst:13:<autosummary>:1\nmsgid \"A camera that allows mapping between objects.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/cameras.rst:13:<autosummary>:1\nmsgid \"A camera able to move through a scene.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/cameras.rst:13:<autosummary>:1\nmsgid \"A camera supporting multiple perspectives.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference_index/configuration.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference_index/configuration.rst:2\nmsgid \"Configuration\"\nmsgstr \"\"\n\n#: ../../source/reference_index/configuration.rst:5\nmsgid \"Module Index\"\nmsgstr \"\"\n\n#: ../../source/reference_index/configuration.rst:14:<autosummary>:1\nmsgid \"Set the global config and logger.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/configuration.rst:14:<autosummary>:1\nmsgid \"Utilities to create and set the config.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference_index/mobjects.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference_index/mobjects.rst:2\nmsgid \"Mobjects\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Special rectangles.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Various geometric Mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Mobjects used to represent mathematical graphs (think graph theory, not plotting).\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Coordinate systems and function graphing related mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Utilities for Manim's logo and banner.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Mobjects representing matrices.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Base classes for objects that can be displayed.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Mobjects related to SVG images.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Mobjects representing tables.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Mobjects used to display Text using Pango or LaTeX.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Three-dimensional mobjects.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Specialized mobject base classes.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/mobjects.rst:22:<autosummary>:1\nmsgid \"Simple mobjects that can be used for storing (and updating) a value.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference_index/scenes.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference_index/scenes.rst:2\nmsgid \"Scenes\"\nmsgstr \"\"\n\n#: ../../source/reference_index/scenes.rst:15:<autosummary>:1\nmsgid \"A scene whose camera can be moved around.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/scenes.rst:15:<autosummary>:1\nmsgid \"building blocks of segmented video API\"\nmsgstr \"\"\n\n#: ../../source/reference_index/scenes.rst:15:<autosummary>:1\nmsgid \"Basic canvas for animations.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/scenes.rst:15:<autosummary>:1\nmsgid \"The interface between scenes and ffmpeg.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/scenes.rst:15:<autosummary>:1\nmsgid \"A scene suitable for rendering three-dimensional objects and animations.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/scenes.rst:15:<autosummary>:1\nmsgid \"A scene suitable for vector spaces.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reference_index/utilities_misc.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/reference_index/utilities_misc.rst:2\nmsgid \"Utilities and other modules\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:5\nmsgid \"Module Index\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Constant definitions.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Utility functions related to Bézier curves.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Colors and utility functions for conversion between different color models.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Utilities that might be useful for configuration dictionaries.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Decorators for deprecating classes, functions and function parameters.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Debugging utilities.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Utilities for scene caching.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Utilities for using Manim with IPython (in particular: Jupyter notebooks)\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Image manipulation utilities.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Operations on iterables.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Functions determining transformation paths between sets of points.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"A selection of rate functions, i.e., *speed curves* for animations.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"A collection of simple functions.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Sound-related utility functions.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Utility functions for two- and three-dimensional vectors.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"Utilities for processing LaTeX templates.\"\nmsgstr \"\"\n\n#: ../../source/reference_index/utilities_misc.rst:31:<autosummary>:1\nmsgid \"A library of LaTeX templates.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/reporting_bugs.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/tutorials/a_deeper_look.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/tutorials/building_blocks.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/tutorials/building_blocks.rst:3\nmsgid \"Manim's building blocks\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:5\nmsgid \"This document explains the building blocks of manim and will give you all the necessary tools to start producing your own videos.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:8\nmsgid \"Essentially, manim puts at your disposal three different concepts that you can orchestrate together to produce mathematical animations: the **mathematical object** (or **mobject** for short), the **animation**, and the **scene**.  As we will see in the following sections, each of these three concepts is implemented in manim as a separate class: the :class:`.Mobject`, :class:`.Animation`, and :class:`.Scene` classes.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:15\nmsgid \"It is recommended that you read the tutorials :doc:`quickstart` and :doc:`output_and_config` before reading this page.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:21\nmsgid \"Mobjects\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:23\nmsgid \"Mobjects are the basic building blocks for all manim animations.  Each class that derives from :class:`.Mobject` represents an object that can be displayed on the screen.  For example, simple shapes such as :class:`.Circle`, :class:`.Arrow`, and :class:`.Rectangle` are all mobjects.  More complicated constructs such as :class:`.Axes`, :class:`.FunctionGraph`, or :class:`.BarChart` are mobjects as well.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:30\nmsgid \"If you try to display an instance of :class:`.Mobject` on the screen, you will only see an empty frame.  The reason is that the :class:`.Mobject` class is an abstract base class of all other mobjects, i.e. it does not have any pre-determined visual shape that can be displayed on the screen.  It is only the skeleton of a thing that *could* be displayed.  Therefore, you will rarely need to use plain instances of :class:`.Mobject`; instead, you will most likely create instances of its derived classes.  One of these derived classes is :class:`.VMobject`.  The ``V`` stands for Vectorized Mobject.  In essence, a vmobject is a mobject that uses `vector graphics <https://en.wikipedia.org/wiki/Vector_graphics>`_ to be displayed.  Most of the time, you will be dealing with vmobjects, though we will continue to use the term \\\"mobject\\\" to refer to the class of shapes that can be displayed on the screen, as it is more general.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:44\nmsgid \"Any object that can be displayed on the screen is a ``mobject``, even if it is not necessarily *mathematical* in nature.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:47\nmsgid \"To see examples of classes derived from :class:`.Mobject`, see the :mod:`.geometry` module.  Most of these are in fact derived from :class:`.VMobject` as well.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:53\nmsgid \"Creating and displaying mobjects\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:55\nmsgid \"As explained in :doc:`quickstart`, usually all of the code in a manim script is put inside the :meth:`.construct` method of a :class:`.Scene` class. To display a mobject on the screen, call the :meth:`~.Scene.add` method of the containing :class:`.Scene`.  This is the principal way of displaying a mobject on the screen when it is not being animated.  To remove a mobject from the screen, simply call the :meth:`~.Scene.remove` method from the containing :class:`.Scene`.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:75\nmsgid \"Placing mobjects\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:77\nmsgid \"Let's define a new :class:`.Scene` called ``Shapes`` and :meth:`~.Scene.add` some mobjects to it.  This script generates a static picture that displays a circle, a square, and a triangle:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:96\nmsgid \"By default, mobjects are placed at the center of coordinates, or *origin*, when they are first created.  They are also given some default colors.  Further, the ``Shapes`` scene places the mobjects by using the :meth:`.shift` method.  The square is shifted one unit in the ``UP`` direction from the origin, while the circle and triangle are shifted one unit ``LEFT`` and ``RIGHT``, respectively.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:102\nmsgid \"Unlike other graphics software, manim places the center of coordinates at the center of the screen.  The positive vertical direction is up, and the positive horizontal direction is right. See also the constants ``ORIGIN``, ``UP``, ``DOWN``, ``LEFT``, ``RIGHT``, and others, defined in the :mod:`.constants` module.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:108\nmsgid \"There are many other possible ways to place mobjects on the screen, for example :meth:`.move_to`, :meth:`.next_to`, and :meth:`.align_to`.  The next scene ``MobjectPlacement`` uses all three.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:130\nmsgid \"The :meth:`.move_to` method uses absolute units (measured relative to the ``ORIGIN``), while :meth:`.next_to` uses relative units (measured from the mobject passed as the first argument).  :meth:`align_to` uses ``LEFT`` not as measuring units but as a way to determine the border to use for alignment.  The coordinates of the borders of a mobject are determined using an imaginary bounding box around it.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:137\nmsgid \"Many methods in manim can be chained together.  For example the two lines\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:145\nmsgid \"can be replaced by\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:151\nmsgid \"Technically, this is possible because most methods calls return the modified mobject.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:155\nmsgid \"Styling mobjects\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:157\nmsgid \"The following scene changes the default aesthetics of the mobjects.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:174\nmsgid \"This scene uses two of the main functions that change the visual style of a mobject: :meth:`.set_stroke` and :meth:`.set_fill`.  The former changes the visual style of the mobject's border while the latter changes the style of the interior.  By default, most mobjects have a fully transparent interior so you must specify the ``opacity`` parameter to display the color.  An opacity of ``1.0`` means fully opaque, while ``0.0`` means fully transparent.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:181\nmsgid \"Only instances of :class:`.VMobject` implement :meth:`.set_stroke` and :meth:`.set_fill`.  Instances of :class:`.Mobject` implement :meth:`.~Mobject.set_color` instead.  The vast majority of pre-defined classes are derived from :class:`.VMobject` so it is usually safe to assume that you have access to :meth:`.set_stroke` and :meth:`.set_fill`.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:189\nmsgid \"Mobject on-screen order\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:191\nmsgid \"The next scene is exactly the same as the ``MobjectStyling`` scene from the previous section, except for exactly one line.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:209\nmsgid \"The only difference here (besides the scene name) is the order in which the mobjects are added to the scene.  In ``MobjectStyling``, we added them as ``add(circle, square, triangle)``, whereas in ``MobjectZOrder`` we add them as ``add(triangle, square, circle)``.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:214\nmsgid \"As you can see, the order of the arguments of :meth:`~.Scene.add` determines the order that the mobjects are displayed on the screen, with the left-most arguments being put in the back.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:221\nmsgid \"Animations\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:223\nmsgid \"At the heart of manim is animation.  Generally, you can add an animation to your scene by calling the :meth:`~.Scene.play` method.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:243\nmsgid \"Put simply, animations are procedures that interpolate between two mobjects. For example, :code:`FadeIn(square)` starts with a fully transparent version of :code:`square` and ends with a fully opaque version, interpolating between them by gradually increasing the opacity.  :class:`.FadeOut` works in the opposite way: it interpolates from fully opaque to fully transparent.  As another example, :class:`.Rotate` starts with the mobject passed to it as argument, and ends with the same object but rotated by a certain amount, this time interpolating the mobject's angle instead of its opacity.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:254\nmsgid \"Animating methods\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:256\nmsgid \"Any property of a mobject that can be changed can be animated.  In fact, any method that changes a mobject's property can be used as an animation, through the use of :meth:`.animate`.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:276\nmsgid \":meth:`.animate` is a property of all mobjects that animates the methods that come afterward. For example, :code:`square.set_fill(WHITE)` sets the fill color of the square, while :code:`square.animate.set_fill(WHITE)` animates this action.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:281\nmsgid \"Animation run time\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:283\nmsgid \"By default, any animation passed to :meth:`play` lasts for exactly one second. Use the :code:`run_time` argument to control the duration.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:296\nmsgid \"Creating a custom animation\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:298\nmsgid \"Even though Manim has many built-in animations, you will find times when you need to smoothly animate from one state of a :class:`~.Mobject` to another. If you find yourself in that situation, then you can define your own custom animation. You start by extending the :class:`~.Animation` class and overriding its :meth:`~.Animation.interpolate_mobject`. The :meth:`~.Animation.interpolate_mobject` method receives alpha as a parameter that starts at 0 and changes throughout the animation. So, you just have to manipulate self.mobject inside Animation according to the alpha value in its interpolate_mobject method. Then you get all the benefits of :class:`~.Animation` such as playing it for different run times or using different rate functions.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:305\nmsgid \"Let's say you start with a number and want to create a :class:`~.Transform` animation that transforms it to a target number. You can do it using :class:`~.FadeTransform`, which will fade out the starting number and fade in the target number. But when we think about transforming a number from one to another, an intuitive way of doing it is by incrementing or decrementing it smoothly. Manim has a feature that allows you to customize this behavior by defining your own custom animation.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:310\nmsgid \"You can start by creating your own ``Count`` class that extends :class:`~.Animation`. The class can have a constructor with three arguments, a :class:`~.DecimalNumber` Mobject, start, and end. The constructor will pass the :class:`~.DecimalNumber` Mobject to the super constructor (in this case, the :class:`~.Animation` constructor) and will set start and end.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:314\nmsgid \"The only thing that you need to do is to define how you want it to look at every step of the animation. Manim provides you with the alpha value in the :meth:`~.Animation.interpolate_mobject` method based on frame rate of video, rate function, and run time of animation played. The alpha parameter holds a value between 0 and 1 representing the step of the currently playing animation. For example, 0 means the beginning of the animation, 0.5 means halfway through the animation, and 1 means the end of the animation.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:319\nmsgid \"In the case of the ``Count`` animation, you just have to figure out a way to determine the number to display at the given alpha value and then set that value in the :meth:`~.Animation.interpolate_mobject` method of the ``Count`` animation. Suppose you are starting at 50 and incrementing until the :class:`~.DecimalNumber` reaches 100 at the end of the animation.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:322\nmsgid \"If alpha is 0, you want the value to be 50.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:323\nmsgid \"If alpha is 0.5, you want the value to be 75.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:324\nmsgid \"If alpha is 1, you want the value to be 100.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:326\nmsgid \"Generally, you start with the starting number and add only some part of the value to be increment according to the alpha value. So, the logic of calculating the number to display at each step will be ``50 + alpha * (100 - 50)``. Once you set the calculated value for the :class:`~.DecimalNumber`, you are done.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:330\nmsgid \"Once you have defined your ``Count`` animation, you can play it in your :class:`~.Scene` for any duration you want for any :class:`~.DecimalNumber` with any rate function.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:367\nmsgid \"Using coordinates of a mobject\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:369\nmsgid \"Mobjects contain points that define their boundaries. These points can be used to add other mobjects respectively to each other, e.g. by methods like :meth:`~.Mobject.get_center` , :meth:`~.Mobject.get_top` and :meth:`~.Mobject.get_start`. Here is an example of some important coordinates:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:401\nmsgid \"Transforming mobjects into other mobjects\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:402\nmsgid \"It is also possible to transform a mobject into another mobject like this:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:413\nmsgid \"The Transform function maps points of the previous mobject to the points of the next mobject. This might result in strange behaviour, e.g. when the dots of one mobject are arranged clockwise and the other points are arranged counterclockwise. Here it might help to use the `flip` function and reposition the points via the `roll <https://numpy.org/doc/stable/reference/generated/numpy.roll.html>`_ function of numpy:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/building_blocks.rst:439\nmsgid \"Scenes\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/tutorials/configuration.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/tutorials/index.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/tutorials/index.rst:4\n#: ../../source/tutorials/index.rst:4\nmsgid \"Table of Contents\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/tutorials/output_and_config.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/tutorials/output_and_config.rst:2\nmsgid \"Manim's Output Settings\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:4\nmsgid \"This document will focus on understanding manim's output files and some of the main command-line flags available.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:7\nmsgid \"This tutorial picks up where :doc:`quickstart` left off, so please read that document before starting this one.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:11\nmsgid \"Manim output folders\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:13\nmsgid \"At this point, you have just executed the following command.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:19\nmsgid \"Let's dissect what just happened step by step.  First, this command executes manim on the file ``scene.py``, which contains our animation code.  Further, this command tells manim exactly which ``Scene`` is to be rendered, in this case, it is ``SquareToCircle``.  This is necessary because a single scene file may contain more than one scene.  Next, the flag `-p` tells manim to play the scene once it's rendered, and the `-ql` flag tells manim to render the scene in low quality.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:27\nmsgid \"After the video is rendered, you will see that manim has generated some new files and the project folder will look as follows.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:44\nmsgid \"There are quite a few new files.  The main output is in ``media/videos/scene/480p15/SquareToCircle.mp4``.  By default, the ``media`` folder will contain all of manim's output files.  The ``media/videos`` subfolder contains the rendered videos.  Inside of it, you will find one folder for each different video quality.  In our case, since we used the ``-l`` flag, the video was generated at 480 resolution at 15 frames per second from the ``scene.py`` file.  Therefore, the output can be found inside ``media/videos/scene/480p15``.  The additional folders ``media/videos/scene/480p15/partial_movie_files`` as well as ``media/text`` and ``media/Tex`` contain files that are used by manim internally.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:55\nmsgid \"You can see how manim makes use of the generated folder structure by executing the following command,\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:62\nmsgid \"The ``-ql`` flag (for low quality) has been replaced by the ``-qh`` flag, for high quality.  Manim will take considerably longer to render this file, and it will play it once it's done since we are using the ``-p`` flag.  The output should look like this:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:84\nmsgid \"And the folder structure should look as follows.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:102\nmsgid \"Manim has created a new folder ``media/videos/1080p60``, which corresponds to the high resolution and the 60 frames per second.  Inside of it, you can find the new ``SquareToCircle.mp4``, as well as the corresponding ``partial_movie_files``.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:107\nmsgid \"When working on a project with multiple scenes, and trying out multiple resolutions, the structure of the output directories will keep all your videos organized.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:111\nmsgid \"Further, manim has the option to output the last frame of a scene, when adding the flag ``-s``. This is the fastest option to quickly get a preview of a scene. The corresponding folder structure looks like this:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:134\nmsgid \"Saving the last frame with ``-s`` can be combined with the flags for different resolutions, e.g. ``-s -ql``, ``-s -qh``\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:141\nmsgid \"Sections\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:143\nmsgid \"In addition to the movie output file one can use sections. Each section produces its own output video. The cuts between two sections can be set like this:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:157\nmsgid \"All the animations between two of these cuts get concatenated into a single output video file. Be aware that you need at least one animation in each section. For example this wouldn't create an output video:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:171\nmsgid \"One way of fixing this is to wait a little:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:182\nmsgid \"For videos to be created for each section you have to add the ``--save_sections`` flag to the Manim call like this:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:188\nmsgid \"If you do this, the ``media`` folder will look like this:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:214\nmsgid \"As you can see each section receives their own output video in the ``sections`` directory. The JSON file in here contains some useful information for each section:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:255\nmsgid \"This data can be used by third party applications, like a presentation system or automated video editing tool.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:257\nmsgid \"You can also skip rendering all animations belonging to a section like this:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:271\nmsgid \"Some command line flags\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:273\nmsgid \"When executing the command\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:279\nmsgid \"it was necessary to specify which ``Scene`` class to render.  This is because a single file can contain more than one ``Scene`` class.  If your file contains multiple ``Scene`` classes, and you want to render them all, you can use the ``-a`` flag.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:284\nmsgid \"As discussed previously, the ``-ql`` specifies low render quality.  This does not look very good, but is very useful for rapid prototyping and testing.  The other options that specify render quality are ``-qm``, ``-qh``, and ``-qk`` for medium, high, and 4k quality, respectively.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:289\nmsgid \"The ``-p`` flag plays the animation once it is rendered.  If you want to open the file browser at the location of the animation instead of playing it, you can use the ``-f`` flag.  You can also omit these two flags.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/output_and_config.rst:293\nmsgid \"Finally, by default manim will output .mp4 files.  If you want your animations in .gif format instead, use the ``-i`` flag.  The output files will be in the same folder as the .mp4 files, and with the same name, but a different file extension.\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/tutorials/quickstart.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/tutorials/quickstart.rst:3\nmsgid \"Quickstart\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:6\nmsgid \"Before proceeding, install Manim and make sure it's running properly by following the steps in :doc:`../installation`. For information on using Manim with Jupyterlab or Jupyter notebook, go to the documentation for the :meth:`IPython magic command <manim.utils.ipython_magic.ManimMagic.manim>`, ``%%manim``.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:14\nmsgid \"Overview\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:16\nmsgid \"This quickstart guide will lead you through creating a sample project using Manim: an animation engine for precise programmatic animations.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:19\nmsgid \"First, you will use a command line interface to create a ``Scene``, the class through which Manim generates videos. In the ``Scene`` you will animate a circle. Then you will add another ``Scene`` showing a square transforming into a circle. This will be your introduction to Manim's animation ability. Afterwards, you will position multiple mathematical objects (``Mobject``\\\\s). Finally, you will learn the ``.animate`` syntax, a powerful feature that animates the methods you use to modify ``Mobject``\\\\s.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:29\nmsgid \"Starting a new project\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:31\nmsgid \"Start by creating a new folder. For the purposes of this guide, name the folder ``project``:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:37\nmsgid \"This folder is the root folder for your project. It contains all the files that Manim needs to function, as well as any output that your project produces.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:42\nmsgid \"Animating a circle\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:44\nmsgid \"Open a text editor, such as Notepad. Copy the following code snippet into the window:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:57\nmsgid \"Save the code snippet into your project folder with the name ``scene.py``.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:64\nmsgid \"3. Open the command line, navigate to your project folder, and execute the following command:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:71\nmsgid \"Manim will output rendering information, then create an MP4 file. Your default movie player will play the MP4 file, displaying the following animation.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:83\nmsgid \"If you see an animation of a pink circle being drawn, congratulations! You just wrote your first Manim scene from scratch.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:86\nmsgid \"If you get an error message instead, you do not see a video, or if the video output does not look like the preceding animation, it is likely that Manim has not been installed correctly. Please refer to our :doc:`FAQ section </faq/index>` for help with the most common issues.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:95\nmsgid \"Explanation\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:97\nmsgid \"Let's go over the script you just executed line by line to see how Manim was able to draw the circle.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:100\nmsgid \"The first line imports all of the contents of the library:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:106\nmsgid \"This is the recommended way of using Manim, as a single script often uses multiple names from the Manim namespace. In your script, you imported and used ``Scene``, ``Circle``, ``PINK`` and ``Create``.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:110\nmsgid \"Now let's look at the next two lines:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:118\nmsgid \"Most of the time, the code for scripting an animation is entirely contained within the :meth:`~.Scene.construct` method of a :class:`.Scene` class. Inside :meth:`~.Scene.construct`, you can create objects, display them on screen, and animate them.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:122\nmsgid \"The next two lines create a circle and set its color and opacity:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:129\nmsgid \"Finally, the last line uses the animation :class:`.Create` to display the circle on your screen:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:136\nmsgid \"All animations must reside within the :meth:`~.Scene.construct` method of a class derived from :class:`.Scene`.  Other code, such as auxiliary or mathematical functions, may reside outside the class.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:142\nmsgid \"Transforming a square into a circle\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:144\nmsgid \"With our circle animation complete, let's move on to something a little more complicated.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:146\nmsgid \"Open ``scene.py``, and add the following code snippet below the ``CreateCircle`` class:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:162\nmsgid \"Render ``SquareToCircle`` by running the following command in the command line:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:168\n#: ../../source/tutorials/quickstart.rst:216\n#: ../../source/tutorials/quickstart.rst:284\n#: ../../source/tutorials/quickstart.rst:326\nmsgid \"The following animation will render:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:185\nmsgid \"This example shows one of the primary features of Manim: the ability to implement complicated and mathematically intensive animations (such as cleanly interpolating between two geometric shapes) with just a few lines of code.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:191\nmsgid \"Positioning ``Mobject``\\\\s\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:193\nmsgid \"Next, let's go over some basic techniques for positioning ``Mobject``\\\\s.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:195\nmsgid \"Open ``scene.py``, and add the following code snippet below the ``SquareToCircle`` method:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:210\nmsgid \"Render ``SquareAndCircle`` by running the following command in the command line:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:232\nmsgid \"``next_to`` is a ``Mobject`` method for positioning ``Mobject``\\\\s.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:234\nmsgid \"We first specified the pink circle as the square's reference point by passing ``circle`` as the method's first argument. The second argument is used to specify the direction the ``Mobject`` is placed relative to the reference point. In this case, we set the direction to ``RIGHT``, telling Manim to position the square to the right of the circle. Finally, ``buff=0.5`` applied a small distance buffer between the two objects.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:240\nmsgid \"Try changing ``RIGHT`` to ``LEFT``, ``UP``, or ``DOWN`` instead, and see how that changes the position of the square.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:242\nmsgid \"Using positioning methods, you can render a scene with multiple ``Mobject``\\\\s, setting their locations in the scene using coordinates or positioning them relative to each other.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:246\nmsgid \"For more information on ``next_to`` and other positioning methods, check out the list of :class:`.Mobject` methods in our reference manual.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:251\nmsgid \"Using ``.animate`` syntax to animate methods\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:253\nmsgid \"The final lesson in this tutorial is using ``.animate``, a ``Mobject`` method which animates changes you make to a ``Mobject``. When you prepend ``.animate`` to any method call that modifies a ``Mobject``, the method becomes an animation which can be played using ``self.play``. Let's return to ``SquareToCircle`` to see the differences between using methods when creating a ``Mobject``, and animating those method calls with ``.animate``.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:260\nmsgid \"Open ``scene.py``, and add the following code snippet below the ``SquareAndCircle`` class:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:278\nmsgid \"Render ``AnimatedSquareToCircle`` by running the following command in the command line:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:299\nmsgid \"The first ``self.play`` creates the square. The second animates rotating it 45 degrees. The third transforms the square into a circle, and the last colors the circle pink. Although the end result is the same as that of ``SquareToCircle``, ``.animate`` shows ``rotate`` and ``set_fill`` being applied to the ``Mobject`` dynamically, instead of creating them with the changes already applied.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:305\nmsgid \"Try other methods, like ``flip`` or ``shift``, and see what happens.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:307\nmsgid \"Open ``scene.py``, and add the following code snippet below the ``AnimatedSquareToCircle`` class:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:320\nmsgid \"Render ``DifferentRotations`` by running the following command in the command line:\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:338\nmsgid \"This ``Scene`` illustrates the quirks of ``.animate``. When using ``.animate``, Manim actually takes a ``Mobject``'s starting state and its ending state and interpolates the two. In the ``AnimatedSquareToCircle`` class, you can observe this when the square rotates: the corners of the square appear to contract slightly as they move into the positions required for the first square to transform into the second one.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:344\nmsgid \"In ``DifferentRotations``, the difference between ``.animate``'s interpretation of rotation and the ``Rotate`` method is far more apparent. The starting and ending states of a ``Mobject`` rotated 180 degrees are the same, so ``.animate`` tries to interpolate two identical objects and the result is the left square. If you find that your own usage of ``.animate`` is causing similar unwanted behavior, consider using conventional animation methods like the right square, which uses ``Rotate``.\"\nmsgstr \"\"\n\n#: ../../source/tutorials/quickstart.rst:353\nmsgid \"You're done!\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/gettext/tutorials/using_text.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/tutorials.pot",
    "content": "\n"
  },
  {
    "path": "docs/i18n/gettext/tutorials_guides.pot",
    "content": "\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Manim \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: ../../source/tutorials_guides.rst:4\n#: ../../source/tutorials_guides.rst:4\nmsgid \"Table of Contents\"\nmsgstr \"\"\n\n\n"
  },
  {
    "path": "docs/i18n/hi/LC_MESSAGES/index.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: hi\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/index.pot\\n\"\n\"X-Crowdin-File-ID: 5163\\n\"\n\"Language-Team: Hindi\\n\"\n\"Language: hi_IN\\n\"\n\"PO-Revision-Date: 2021-11-06 12:29\\n\"\n\n#: ../../source/index.rst:7\nmsgid \"Manim Community Overview\"\nmsgstr \"Manim Community की समीक्षा\"\n\n#: ../../source/index.rst:9\nmsgid \"Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. ``Manim`` uses Python to generate animations programmatically, making it possible to specify exactly how each one should run.\"\nmsgstr \"पारंपरिक तौर पर तकनीकी विषयों को अनुप्राणित करना अत्यंत जटिल होता है क्योंकि अनुप्राणनों को इतना सटीक बनाना कि उन्हें सही रूप में दर्शाया जाए, यह कठिन हो सकता है। ``Manim`` Python का उपयोग करके अनुप्राणन क्रमादेशित रूप में उत्पादित करता है, जिससे हर एक किस प्रकार चलना चाहिए, यह स्पष्ट करना संभव हो जाता है।\"\n\n#: ../../source/index.rst:14\nmsgid \"This project is still very much a work in progress, but we hope that the information here will make it easier for newcomers to get started using ``Manim``.\"\nmsgstr \"इस परियोजना पर कार्य अभी भी काफ़ी हद तक प्रगति पर है, पर हमें आशा है की यहाँ दी गई जानकारी नए उपयोगकर्ताओं के लिए ``Manim`` का प्रयोग आरंभ करना सरल बनाएगी।\"\n\n#: ../../source/index.rst:20\nmsgid \"All content of the docs is licensed under the MIT license. Especially for the examples you encounter: Feel free to use this code in your own projects!\"\nmsgstr \"प्रलेखन का सभी विषय-वस्तु MIT अनुज्ञापत्र के तहत अनुज्ञापित किया गया है। विशेष रूप से वह सभी उदाहरण जिनका आप सामना करेंगे: अपने कार्यों एवं परियोजनाओं में इस कोड का उपयोग निसंकोच कीजिए!\"\n\n#: ../../source/index.rst:23\nmsgid \"We are curious to see the awesome projects you build using this library, feel free to share your projects with us `on Twitter <https://twitter.com/manim_community>`_, `Reddit <https://www.reddit.com/r/manim/>`_, or via `Discord <https://www.manim.community/discord/>`_.\"\nmsgstr \"हम आपके द्वारा इस संग्रह का प्रयोग करके बनाए गए अद्भुत परियोजनाओं को देखने के लिए उत्सुक हैं, निसंकोच हमारे साथ `Twitter पर <https://twitter.com/manim_community>`_, `Reddit पर <https://www.reddit.com/r/manim/>`_, अन्यथा `Discord <https://www.manim.community/discord/>`_ द्वारा अपनी परियोजनाएँ हमारे साथ साझा करें।\"\n\n#: ../../source/index.rst:27\nmsgid \"In case you publish your work made with Manim, we would appreciate if you add a link to `our homepage <https://www.manim.community>`_ or `our GitHub repository <https://github.com/ManimCommunity/manim>`_. If you use Manim in a scientific context, instructions on how to cite a particular release can be found `in our README <https://github.com/ManimCommunity/manim/blob/main/README.md>`_.\"\nmsgstr \"यदि आप अपना Manim द्वारा बनाए गए कार्य को प्रकाशित करते हैं, हमें प्रसन्नता होगी यदि आप `हमारे मुखपृष्ट <https://www.manim.community>`_ या `हमारे GitHub कोष (रिपाॅज़िटोरी)<https://github.com/ManimCommunity/manim>`_ की कड़ी जोड़ें। अगर आप Manim का प्रयोग वैज्ञानिक संदर्भ में करते हैं, किसी विशेष अवतरण को उद्धृत करने के निर्देश `हमारे README <https://github.com/ManimCommunity/manim/blob/main/README.md>`_ में पाए जा सकते हैं।\"\n\n#: ../../source/index.rst:36\nmsgid \"As a quick reference, here are some often used modules, classes and methods:\"\nmsgstr \"तत्काल संगर्भ के रूप में, कुछ प्रायः उपयोग किए जाने वाले प्रतिरूपक (माॅड्यूल), वर्ग (क्लासेस) एवं प्रणालियाँ प्रस्तुत हैं:\"\n\n#: ../../source/index.rst:38\nmsgid \"Modules: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`,\"\nmsgstr \"प्रतिरूपक: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`,\"\n\n#: ../../source/index.rst:43\nmsgid \"Classes: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`,\"\nmsgstr \"वर्ग: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`,\"\n\n"
  },
  {
    "path": "docs/i18n/pt/LC_MESSAGES/index.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: pt-BR\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/index.pot\\n\"\n\"X-Crowdin-File-ID: 5163\\n\"\n\"Language-Team: Portuguese, Brazilian\\n\"\n\"Language: pt_BR\\n\"\n\"PO-Revision-Date: 2021-11-06 12:29\\n\"\n\n#: ../../source/index.rst:7\nmsgid \"Manim Community Overview\"\nmsgstr \"Visão geral da comunidade\"\n\n#: ../../source/index.rst:9\nmsgid \"Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. ``Manim`` uses Python to generate animations programmatically, making it possible to specify exactly how each one should run.\"\nmsgstr \"Animar conceitos técnicos é tradicionalmente bastante tedioso, já que pode ser difícil tornar as animações suficientemente precisas para transmiti-las com precisão. ``Manim`` usa Python para gerar animações programáticas, tornando possível especificar exatamente como cada uma deve ser executada.\"\n\n#: ../../source/index.rst:14\nmsgid \"This project is still very much a work in progress, but we hope that the information here will make it easier for newcomers to get started using ``Manim``.\"\nmsgstr \"Este projecto continua a ser, em grande medida, um trabalho em progresso. mas esperamos que a informação aqui torne mais fácil para iniciantes começarem a usar ``Manim``.\"\n\n#: ../../source/index.rst:20\nmsgid \"All content of the docs is licensed under the MIT license. Especially for the examples you encounter: Feel free to use this code in your own projects!\"\nmsgstr \"Todo o conteúdo da documentação está licenciado sob a licença MIT. Especialmente para os exemplos que você encontrou: Sinta-se à vontade para usar esse código em seus próprios projetos!\"\n\n#: ../../source/index.rst:23\nmsgid \"We are curious to see the awesome projects you build using this library, feel free to share your projects with us `on Twitter <https://twitter.com/manim_community>`_, `Reddit <https://www.reddit.com/r/manim/>`_, or via `Discord <https://www.manim.community/discord/>`_.\"\nmsgstr \"Estamos curiosos para ver os projetos incríveis que você cria usando esta biblioteca, sinta-se livre para compartilhar seus projetos conosco `no Twitter <https://twitter.com/manim_community>`_, `Reddit <https://www.reddit.com/r/manim/>`_, ou via `Discord <https://www.manim.community/discord/>`_.\"\n\n#: ../../source/index.rst:27\nmsgid \"In case you publish your work made with Manim, we would appreciate if you add a link to `our homepage <https://www.manim.community>`_ or `our GitHub repository <https://github.com/ManimCommunity/manim>`_. If you use Manim in a scientific context, instructions on how to cite a particular release can be found `in our README <https://github.com/ManimCommunity/manim/blob/main/README.md>`_.\"\nmsgstr \"No caso de publicar seu trabalho feito com Manim, Gostaríamos que você adicionasse um link `nossa página inicial <https://www.manim.community>`_ ou `nosso repositório no GitHub <https://github.com/ManimCommunity/manim>`_. Se você usar Manim em um contexto científico, instruções sobre como citar uma versão em particular podem ser encontradas `em nosso README <https://github.com/ManimCommunity/manim/blob/main/README.md>`_.\"\n\n#: ../../source/index.rst:36\nmsgid \"As a quick reference, here are some often used modules, classes and methods:\"\nmsgstr \"Como referência rápida, aqui estão alguns módulos, classes e métodos frequentemente usados:\"\n\n#: ../../source/index.rst:38\nmsgid \"Modules: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`,\"\nmsgstr \"Módulos: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`,\"\n\n#: ../../source/index.rst:43\nmsgid \"Classes: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`,\"\nmsgstr \"Classe: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`,\"\n\n"
  },
  {
    "path": "docs/i18n/readyForTranslation",
    "content": "changelog.po\nindex.po\ncontributing.po\ninstallation/linux.po\ninstallation/troubleshooting.po\nreporting_bugs.po\ninstallation.po\nexamples.po\nreference.po\ntutorials.po\ntutorials/building_blocks.po\ntutorials/quickstart.po\nguides/output_and_config.po\nguides/configuration.po\nguides/deep_dive.po\nguides/using_text.po\nfaq/general.po\nfaq/help.po\nfaq/installation.po\nfaq/opengl.po\n"
  },
  {
    "path": "docs/i18n/stripUntranslatable.awk",
    "content": "BEGIN {\n\t# The current state of the parser:\n\t# -1 -> haven't read the first line of the new block\n\t# 0  -> reading the pre-comment\n\t# 1  -> reading the msgid\n\t# 2  -> reading the msgstr\n\tstate=-1\n\t# The comment preceding the block\n\tprecomment=\"\"\n\t# The same string, but with a space after the sharp to avoid a comment\n\tsharpedprecomment=\"\"\n\t# The msgid section, containing the string to be translated\n\tmsgidstr=\"\"\n\t# The same string, but with a sharp before every newline (commented  out)\n\tsharpedmsgidstr=\"\"\n\t# The msgstr section, containing the destination string\n\tmsgstrstr=\"\"\n\t# The same string, but with a sharp before every newline (commented out)\n\tsharpedmsgstrstr=\"\"\n\t# Whether the block being read should be kept\n\t# -1 -> should keep, overridable\n\t# 0  -> should not keep, overridable\n\t# 1  -> should keep, not overridable\n\tacceptable=1\n\t# The file location of where to put everything\n\t# that has been stripped out\n\tuntranslatablefile=\"./untranslatable.po\"\n\t# Whether we are still reading the licence text\n\tlicencetext=1\n}\n\n# Detecting the end of licence\n$0~/^#, fuzzy$/ {licencetext=0; next; next}\n\n# If we are reading the licence, skip text and dont print it.\n$0~// {if (licencetext==1) {next}}\n\n# We pass on the wrong metadata\n$0~/\"Report-Msgid-Bugs-To:/ {next}\n$0~/\"PO-Revision-Date:/ {next}\n$0~/\"Last-Translator:/ {next}\n$0~/\"Language-Team:/ {next}\n\n# This pattern matches empty lines\n# The code flushes the data stored, and save\n# it only if acceptable!=1\n$0~/^$/ {\n\tif (state<=0){\n\t\tif(acceptable!=1){\n\t\t\tprint precomment\n\t\t}else{\n\t\t\t#print \"#  Detected untranslatable text:\"\n\t\t\t#print sharpedprecomment\n\t\t}\n\t\tprecomment=\"\"\n\t}else{\n\t\tif(acceptable==1){\n\t\t\tprint precomment\n\t\t\tprint msgidstr\n\t\t\tprint msgstrstr\n\t\t\tprint \"\"\n\t\t}else{\n\t\t\t#print \"#  Detected untranslatable text:\"\n\t\t\t#print sharpedprecomment\n\t\t\t#print sharpedmsgidstr\n\t\t\t#print sharpedmsgstrstr\n\t\t\tprint precomment>>untranslatablefile\n\t\t\tprint msgidstr>>untranslatablefile\n\t\t\tprint msgstrstr>>untranslatablefile\n\t\t}\n\t\t# Add the newline currently parsed\n\t\t# Re-initialisation of the variables.\n\t\tstate=-1\n\t\tacceptable=-1\n\t\tprecomment=\"\"\n\t\tmsgidstr=\"\"\n\t\tmsgstrstr=\"\"\n\t}\n}\n# If the line is commented out\n$0~/^#/ {\n\tprecomment=(state==-1)?$0:precomment\"\\n\"$0\n\tsharpedprecomment=(state==-1)?\"#  \"$0:sharpedprecomment\"\\n#  \"$0\n\tstate=0\n}\n# If the line starts with \"msgid\"\n$0~/^msgid/ {\n\tstate=1\n\tmsgidstr=$0\n\tsharpedmsgidstr=\"#  \"$0\n}\n# If the line starts with msgstr\n$0~/^msgstr/ {\n\tstate=2\n\tmsgstrstr=$0\n\tsharpedmsgstrstr=\"#  \"$0\n}\n# If the line starts with a '\"'\n$0~/^\\\"/ {\n\tif(state==1){\n\t\tmsgidstr=msgidstr\"\\n\"$0\n\t\tsharpedmsgidstr=sharpedmsgidstr\"\\n#  \"$0\n\t}else{\n\t\tmsgstrstr=msgstrstr\"\\n\"$0\n\t\tsharpedmsgstrstr=sharpedmsgstrstr\"\\n#  \"$0\n\t}\n}\n# ----------------------------------------------------------------\n\n\n# This code is now the part that actually selects lines to be stripped out.\n\nstate==1 {\n\tacceptable=1\n}\n$0~/^msgid \":ref:`[a-zA-Z]*`\"/ {\n\tacceptable=0\n}\n$0~/^msgid \":obj:/ {\n\tacceptable=0\n}\n$0~/^msgid \"manim.([a-z._\\\\]+)\"$/ {\n\tacceptable=0\n}\n$0~/^(msgid )?\"((:(mod|class|func):`~\\.[a-zA-Z0-9.]+)`| )+\"/ {\n\tacceptable=0\n}\n$0~/^msgid \":py:obj:`[a-zA-Z0-9_.<> ]+`(\\\\\\\\)?\"/ {\n\tacceptable=0\n}\n$0~/^msgid \"(:(mod|class|meth|func|attr):`[~A-Za-z_.()]+`(, )?)+\"/ {\n\tacceptable=0\n}\n# When the parsing is ended, print the last missing endline\nEND {\nprint \"\"\n}\n"
  },
  {
    "path": "docs/i18n/stripUntranslatable.sh",
    "content": "#!/bin/bash\nrm -f translatable.po\nrm -f untranslatable.po\npot_dir_prefix=\"gettext/\"\necho \"\"\nfor srcFile in `find $pot_dir_prefix -name \"*.pot\" -type f`\ndo\n\tprintf \"\\r\\033[KCleaning file \\e[32m$srcFile\\e[0m\"\n\tdstFile=\"$srcFile.bld\"\n\tawk -f stripUntranslatable.awk $srcFile | sed '/POT-Creation-Date/d'> $dstFile\n\tcat $dstFile >> translatable.po\n\tmv $dstFile $srcFile\ndone\necho \"\"\n"
  },
  {
    "path": "docs/i18n/sv/LC_MESSAGES/contributing.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: sv\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/contributing.pot\\n\"\n\"X-Crowdin-File-ID: 5143\\n\"\n\"Language-Team: Swedish\\n\"\n\"Language: sv_SE\\n\"\n\"PO-Revision-Date: 2021-11-06 12:29\\n\"\n\n#: ../../source/contributing.rst:3\nmsgid \"Contributing\"\nmsgstr \"Bidragande\"\n\n#: ../../source/contributing.rst:5\nmsgid \"Thank you for your interest in contributing to Manim! However you have decided to contribute or interact with the community, please always be civil and respect other members of the community. If you haven't read our :doc:`code of conduct<conduct>`, do so here. Manim is Free and Open Source Software (FOSS) for mathematical animations. As such, **we welcome everyone** who is interested in mathematics, pedagogy, computer animations, open-source, software development, and beyond. Manim accepts many kinds of contributions, some are detailed below:\"\nmsgstr \"Tack för ditt intresse för att bidra till Manim! Oavsett hur du bestämt dig för att bidra eller interagera med communityn, kom ihåg att alltid vara civiliserad och respektera andra medlemmar i communityn. Om du inte redan har gjort det, läs vår :doc:`uppförandekod<conduct>`. Manim är en gratis programvara med öppen källkod (FOSS) för matematiska animationer. På grund av detta, **välkomnar vi alla** som är intresserade av matematik, pedagogik, datoranimationer, öppen källkod, mjukvaruutveckling och vidare. Manim tar emot många typer av bidrag, några exempel beskrivs nedan:\"\n\n#: ../../source/contributing.rst:14\nmsgid \"Code maintenance and development\"\nmsgstr \"Underhåll och utveckling av kod\"\n\n#: ../../source/contributing.rst:15\nmsgid \"DevOps\"\nmsgstr \"DevOps\"\n\n#: ../../source/contributing.rst:16\nmsgid \"Documentation\"\nmsgstr \"Dokumentation\"\n\n#: ../../source/contributing.rst:17\nmsgid \"Developing educational content & narrative documentation\"\nmsgstr \"Utveckla pedagogiskt innehåll & berättande dokumentation\"\n\n#: ../../source/contributing.rst:18\nmsgid \"Plugins to extend Manim functionality\"\nmsgstr \"Plugins för att utöka Manims funktionalitet\"\n\n#: ../../source/contributing.rst:19\nmsgid \"Testing (graphical, unit & video)\"\nmsgstr \"Testning (grafik, enhetstester & video)\"\n\n#: ../../source/contributing.rst:20\nmsgid \"Website design and development\"\nmsgstr \"Webbplatsdesign och -utveckling\"\n\n#: ../../source/contributing.rst:21\nmsgid \"Translating documentation and docstrings\"\nmsgstr \"Översätta dokumentation och docsträngar\"\n\n#: ../../source/contributing.rst:24\nmsgid \"Please ensure that you are reading the latest version of this guide by ensuring that \\\"latest\\\" is selected in the version switcher.\"\nmsgstr \"Se till att du läser den senaste versionen av denna guide genom att se till att \\\"senaste\\\" väljs i versionshanteraren.\"\n\n"
  },
  {
    "path": "docs/i18n/sv/LC_MESSAGES/examples.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: sv\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/examples.pot\\n\"\n\"X-Crowdin-File-ID: 5161\\n\"\n\"Language-Team: Swedish\\n\"\n\"Language: sv_SE\\n\"\n\"PO-Revision-Date: 2021-11-06 12:29\\n\"\n\n#: ../../source/examples.rst:3\nmsgid \"Example Gallery\"\nmsgstr \"Exempelgalleri\"\n\n#: ../../source/examples.rst:5\nmsgid \"This gallery contains a collection of best practice code snippets together with their corresponding video/image output, illustrating different functionalities all across the library. These are all under the MIT license, so feel free to copy & paste them to your projects. Enjoy this taste of Manim!\"\nmsgstr \"Detta galleri innehåller en samling av kodstycken och de motsvarande videor/bilder som de producerar. Dessa kodstycken ses som exempel på bästa praxis och illustrerar flera olika funktioner som finns tillgängliga inom programbiblioteket. De är alla utgivna med MIT licens så varsågod att kopiera och klistra in dem i olika projekt. Vi hoppas ni njuter av denna försmak av Manims funktioner!\"\n\n#: ../../source/examples.rst:13\nmsgid \"This gallery is not the only place in our documentation where you can see explicit code and video examples: there are many more in our :doc:`reference manual </reference>` -- see, for example, our documentation for the modules :mod:`~.tex_mobject`, :mod:`~.geometry`, :mod:`~.moving_camera_scene`, and many more.\"\nmsgstr \"Detta galleri är inte den enda platsen i vår dokumentation där du kan se explicit kod och videoexempel. Det finns många andra platser i vår :doc:`reference manual </reference>` -- se till exempel vår dokumentation för modulerna :mod:`~.tex_mobject`, :mod:`~.geometry`, :mod:`~.moving_camera_scene` och många andra.\"\n\n#: ../../source/examples.rst:19\nmsgid \"Check out our `interactive Jupyter environment <https://mybinder.org/v2/gh/ManimCommunity/jupyter_examples/HEAD?filepath=basic_example_scenes.ipynb>`_ which allows running the examples online, without requiring a local installation.\"\nmsgstr \"Kolla in vår `interaktiva Jupyter-miljö <https://mybinder.org/v2/gh/ManimCommunity/jupyter_examples/HEAD?filepath=basic_example_scenes.ipynb>`_ som gör det möjligt att köra exemplen online utan att det krävs en lokal installation.\"\n\n#: ../../source/examples.rst:23\nmsgid \"Also, visit our `Twitter <https://twitter.com/manim_community/>`_ for more *manimations*!\"\nmsgstr \"Besök även vår `Twitter <https://twitter.com/manim_community/>`_ för fler *manimationer*!\"\n\n#: ../../source/examples.rst:29\nmsgid \"Basic Concepts\"\nmsgstr \"Grundläggande Begrepp\"\n\n#: ../../source/examples.rst:98\nmsgid \"Animations\"\nmsgstr \"Animationer\"\n\n#: ../../source/examples.rst:180\nmsgid \"You can use multiple ValueTrackers simultaneously.\"\nmsgstr \"Du kan använda flera ValueTrackers samtidigt.\"\n\n#: ../../source/examples.rst:274\nmsgid \"Plotting with Manim\"\nmsgstr \"Plottar med Manim\"\n\n#: ../../source/examples.rst:402\nmsgid \"Special Camera Settings\"\nmsgstr \"Speciella kamerainställningar\"\n\n"
  },
  {
    "path": "docs/i18n/sv/LC_MESSAGES/index.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: sv\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/index.pot\\n\"\n\"X-Crowdin-File-ID: 5163\\n\"\n\"Language-Team: Swedish\\n\"\n\"Language: sv_SE\\n\"\n\"PO-Revision-Date: 2021-11-06 12:29\\n\"\n\n#: ../../source/index.rst:7\nmsgid \"Manim Community Overview\"\nmsgstr \"Manim Community Översikt\"\n\n#: ../../source/index.rst:9\nmsgid \"Animating technical concepts is traditionally pretty tedious since it can be difficult to make the animations precise enough to convey them accurately. ``Manim`` uses Python to generate animations programmatically, making it possible to specify exactly how each one should run.\"\nmsgstr \"Traditionellt så har det varit jobbigt att animera tekniska begrepp eftersom det är svårt att skapa animationer som är tillräckligt exakta för att förklara dem korrekt. ``Manim`` använder sig av Python för att generera animationer på ett programmatiskt sätt vilket gör det möjligt att ange exakt hur varje animation ska köras.\"\n\n#: ../../source/index.rst:14\nmsgid \"This project is still very much a work in progress, but we hope that the information here will make it easier for newcomers to get started using ``Manim``.\"\nmsgstr \"Detta projekt är fortfarande i hög grad ett pågående arbete, men vi hoppas att informationen här kommer att göra det lättare för nykomlingar att komma igång med ``Manim``.\"\n\n#: ../../source/index.rst:20\nmsgid \"All content of the docs is licensed under the MIT license. Especially for the examples you encounter: Feel free to use this code in your own projects!\"\nmsgstr \"Allt innehåll i dokumentationen är licensierat under MIT-licensen. Detta gäller även för alla exempel som du möter på. Använd gärna koden i dina egna projekt!\"\n\n#: ../../source/index.rst:23\nmsgid \"We are curious to see the awesome projects you build using this library, feel free to share your projects with us `on Twitter <https://twitter.com/manim_community>`_, `Reddit <https://www.reddit.com/r/manim/>`_, or via `Discord <https://www.manim.community/discord/>`_.\"\nmsgstr \"Vi är nyfikna på att se de fantastiska projekt du skapar med hjälp av detta bibliotek! Dela gärna dina projekt med oss på Twitter <https://twitter.com/manim_community>`_, `Reddit <https://www.reddit.com/r/manim/>`_ eller via `Discord <https://www.manim.community/discord/>`_.\"\n\n#: ../../source/index.rst:27\nmsgid \"In case you publish your work made with Manim, we would appreciate if you add a link to `our homepage <https://www.manim.community>`_ or `our GitHub repository <https://github.com/ManimCommunity/manim>`_. If you use Manim in a scientific context, instructions on how to cite a particular release can be found `in our README <https://github.com/ManimCommunity/manim/blob/main/README.md>`_.\"\nmsgstr \"Om du publicerar ett projekt du skapad med Manim så skulle vi uppskatta om du lägger till en länk till `vår hemsida <https://www.manim.community>`_ eller `vårt GitHub-arkiv <https://github.com/ManimCommunity/manim>`_. Om du använder Manim i ett vetenskapligt sammanhang så finns instruktioner om hur man citerar en viss version av Manim `i vår README <https://github.com/ManimCommunity/manim/blob/main/README.md>`_.\"\n\n#: ../../source/index.rst:36\nmsgid \"As a quick reference, here are some often used modules, classes and methods:\"\nmsgstr \"Som snabbreferens ges här några av de oftast använda modulerna, klasserna och metoderna:\"\n\n#: ../../source/index.rst:38\nmsgid \"Modules: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`,\"\nmsgstr \"Moduler: :mod:`~.moving_camera_scene`, :mod:`~.tex_mobject`, :mod:`~.geometry`,\"\n\n#: ../../source/index.rst:43\nmsgid \"Classes: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`,\"\nmsgstr \"Klasser: :class:`~.Mobject` , :class:`~.VMobject`, :class:`~.ValueTracker`, :class:`~.MathTex`, :class:`~.Angle`, :class:`~.Tex`, :class:`~.Text`,\"\n\n"
  },
  {
    "path": "docs/i18n/sv/LC_MESSAGES/installation.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: sv\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/installation.pot\\n\"\n\"X-Crowdin-File-ID: 5165\\n\"\n\"Language-Team: Swedish\\n\"\n\"Language: sv_SE\\n\"\n\"PO-Revision-Date: 2021-11-06 12:29\\n\"\n\n#: ../../source/installation.rst:2\nmsgid \"Installation\"\nmsgstr \"Installering\"\n\n#: ../../source/installation.rst:4\nmsgid \"Depending on your use case, different installation options are recommended: if you just want to play around with Manim for a bit, interactive in-browser notebooks are a really simple way of exploring the library as they require no local installation. Head over to https://try.manim.community to give our interactive tutorial a try.\"\nmsgstr \"Beroende på ditt användningsfall rekommenderas olika installationsalternativ: om du bara vill testa Manim först så är interaktiva notebooks lätta att utforska biblioteket med. De kan dessutom öppnas i din webbläsare utan att installera Manim lokalt vilket gör dem enkla att använda. Ta gärna en titt https://try.manim.community för en interaktiv nybörjarkurs.\"\n\n#: ../../source/installation.rst:10\nmsgid \"Otherwise, if you intend to use Manim to work on an animation project, we recommend installing the library locally (either to your system's Python, or via Docker).\"\nmsgstr \"Annars, om du har för avsikt att använda Manim för att jobba på ett animationsprojekt, så rekommenderar vi att du installerar biblioteket lokalt (antingen till ditt systems Python, eller via Docker).\"\n\n#: ../../source/installation.rst:16\nmsgid \"Note that there are several different versions of Manim. The instructions on this website are **only** for the *community edition*. Find out more about the :doc:`differences between Manim versions <installation/versions>` if you are unsure which version you should install.\"\nmsgstr \"Observera att det finns flera olika versioner av Manim. Instruktionerna på denna webbsida är **endast** för *community-utgåvan*. Läs mer om :doc:`skillnader mellan Manim versioner <installation/versions>` om du är osäker på vilken version du bör installera.\"\n\n#: ../../source/installation.rst:22\nmsgid \":ref:`Installing Manim to your system's Python <local-installation>`\"\nmsgstr \":ref:`Installera Manim till ditt systems Python <local-installation>`\"\n\n#: ../../source/installation.rst:23\nmsgid \":ref:`Using Manim via Docker <docker-installation>`\"\nmsgstr \":ref:`Använda Manim via Docker <docker-installation>`\"\n\n#: ../../source/installation.rst:24\nmsgid \":ref:`Interactive Jupyter notebooks via Binder / Google Colab <interactive-online>`\"\nmsgstr \":ref:`Interaktiva Jupyter notebooks via Binder / Google Colab <interactive-online>`\"\n\n#: ../../source/installation.rst:31\nmsgid \"Installing Manim locally\"\nmsgstr \"Installering av Manim lokalt\"\n\n#: ../../source/installation.rst:33\nmsgid \"Manim is a Python library, and it can be `installed via pip <https://pypi.org/project/manim/>`__. However, in order for Manim to work properly, some additional system dependencies need to be installed first. The following pages have operating system specific instructions for you to follow.\"\nmsgstr \"Manim är ett Pythonbibliotek, och det kan `installeras via pip <https://pypi.org/project/manim/>`__. För att Manim ska fungera ordentligt måste dock ytterligare systemberoenden installeras först. Följande sidor har operativsystemsspecifika instruktioner för dig att följa.\"\n\n#: ../../source/installation.rst:41\nmsgid \"Depending on your particular setup, the installation process might be slightly different. Make sure that you have tried to follow the steps on the following pages carefully, but in case you hit a wall we are happy to help: either `join our Discord <https://www.manim.community/discord/>`__, or start a new Discussion `directly on GitHub <https://github.com/ManimCommunity/manim/discussions>`__.\"\nmsgstr \"Beroende på ditt specifika system så kan installationsprocessen vara något annorlunda. Se till att du har försökt att följa stegen på följande sidor noga, men om du träffar en vägg så hjälper vi gärna till: du kan antingen `gå med i vår Discord <https://www.manim.community/discord/>`__, eller starta en ny diskussion `direkt på GitHub <https://github.com/ManimCommunity/manim/discussions>`__.\"\n\n#: ../../source/installation.rst:57\nmsgid \"Once Manim is installed locally, you can proceed to our :doc:`quickstart guide <tutorials/quickstart>` which walks you through rendering a first simple scene.\"\nmsgstr \"När Manim väl installerats lokalt så kan du fortsätta till vår :doc:`snabbstartsguide <tutorials/quickstart>` som visar dig hur du renderar din första enkla scen.\"\n\n#: ../../source/installation.rst:61\nmsgid \"As mentioned above, do not worry if there are errors or other problems: consult our :doc:`troubleshooting guide <installation/troubleshooting>` for help, or get in touch with the community via `GitHub discussions <https://github.com/ManimCommunity/manim/discussions>`__ or `Discord <https://www.manim.community/discord/>`__.\"\nmsgstr \"Som nämnts ovan så behöver du inte oroa dig om det finns fel eller andra problem: läs vår :doc:`felsökningsguide <installation/troubleshooting>` för att få hjälp, eller ta kontakt med communityn via `GitHub-diskussioner <https://github.com/ManimCommunity/manim/discussions>`__ eller `Discord <https://www.manim.community/discord/>`__.\"\n\n#: ../../source/installation.rst:73\nmsgid \"Using Manim via Docker\"\nmsgstr \"Användning av Manim via Docker\"\n\n#: ../../source/installation.rst:75\nmsgid \"`Docker <https://www.docker.com>`__ is a virtualization tool that allows the distribution of encapsulated software environments (containers).\"\nmsgstr \"`Docker <https://www.docker.com>`__ är ett virtualiseringsverktyg som gör det möjligt att distribuera inkapslade mjukvarumiljöer (containers).\"\n\n#: ../../source/installation.rst:78\nmsgid \"The following pages contain more information about the docker image maintained by the community, ``manimcommunity/manim``:\"\nmsgstr \"Följande sidor innehåller mer information om den Docker Image som underhålls av communityn, ``manimcommunity/manim``:\"\n\n#: ../../source/installation.rst:89\nmsgid \"Interactive Jupyter notebooks for your browser\"\nmsgstr \"Interaktiva Jupyter notebooks för din webbläsare\"\n\n#: ../../source/installation.rst:91\nmsgid \"Manim ships with a built-in ``%%manim`` IPython magic command designed for the use within `Jupyter notebooks <https://jupyter.org>`__. Our interactive tutorial over at https://try.manim.community illustrates how Manim can be used from within a Jupyter notebook.\"\nmsgstr \"Manim ges ut med ett inbyggt ``%%manim`` IPython magic command som är utformat för användning inuti `Jupyter notebooks <https://jupyter.org>`__. Vår interaktiva nybörjarkurs på https://try.manim.community illustrerar hur Manim kan användas inuti en Jupyter notebook.\"\n\n#: ../../source/installation.rst:96\nmsgid \"The following pages explain how you can setup interactive environments like that yourself:\"\nmsgstr \"Följande sidor förklarar hur du kan skapa sådana interaktiva miljöer själv:\"\n\n#: ../../source/installation.rst:105\nmsgid \"Installation for developers\"\nmsgstr \"Installering för utvecklare\"\n\n"
  },
  {
    "path": "docs/i18n/sv/LC_MESSAGES/plugins.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: sv\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/plugins.pot\\n\"\n\"X-Crowdin-File-ID: 5181\\n\"\n\"Language-Team: Swedish\\n\"\n\"Language: sv_SE\\n\"\n\"PO-Revision-Date: 2021-11-06 12:30\\n\"\n\n#: ../../source/plugins.rst:5\nmsgid \"Plugins\"\nmsgstr \"Plugins\"\n\n#: ../../source/plugins.rst:7\nmsgid \"Plugins are features that extend Manim's core functionality. Since Manim is extensible and not everything belongs in its core, we'll go over how to install, use, and create your own plugins.\"\nmsgstr \"Plugins är tillägg som utökar Manims kärnfunktionalitet. Eftersom Manim är utökningsbart, och inte allt hör hemma dess kärna, så kommer vi gå över hur man kan installera, använda och skapa egna plugins.\"\n\n#: ../../source/plugins.rst:13\nmsgid \"The standard naming convention for plugins is to prefix the plugin with ``manim-``. This makes them easy for users to find on package repositories such as PyPI.\"\nmsgstr \"Den namnkonvention som används som standard för plugins är att sätta prefixet ``manim-`` i början pluginens namn. Detta gör det enkelt för andra användare att hitta plugins via paketarkiv (repositories) som exempel PyPI.\"\n\n#: ../../source/plugins.rst:19\nmsgid \"The plugin feature is new and under active development. Expect updates for the best practices on installing, using, and creating plugins; as well as new subcommands/flags for ``manim plugins``\"\nmsgstr \"Pluginfunktionen är ny och under aktiv utveckling. Räkna med att de bästa metoderna att installera, använda och skapa plugins, samt nya underkommandon/flaggor för ``manim-plugins``, kommer uppdateras\"\n\n#: ../../source/plugins.rst:25\nmsgid \"See https://plugins.manim.community/ for the list of plugins available.\"\nmsgstr \"Se https://plugins.manim.community/ för listan över tillgängliga plugins.\"\n\n#: ../../source/plugins.rst:28\nmsgid \"Installing Plugins\"\nmsgstr \"Installering av Plugins\"\n\n#: ../../source/plugins.rst:29\nmsgid \"Plugins can be easily installed via the ``pip`` command:\"\nmsgstr \"Plugins kan enkelt installeras via ``pip`` kommandot:\"\n\n#: ../../source/plugins.rst:36\nmsgid \"After installing a plugin, you may use the ``manim plugins`` command to list your available plugins, see the following help output:\"\nmsgstr \"Efter att du har installerat en plugin kan du använda kommandot ``manim plugins`` för att lista dina tillgängliga plugins, se följande hjälpmeddelande:\"\n\n#: ../../source/plugins.rst:52\nmsgid \"You can list plugins as such:\"\nmsgstr \"Du kan få en lista av plugins på detta sätt:\"\n\n#: ../../source/plugins.rst:61\nmsgid \"Using Plugins in Projects\"\nmsgstr \"Användning av Plugins i Projekt\"\n\n#: ../../source/plugins.rst:62\nmsgid \"For enabling a plugin ``manim.cfg`` or command line parameters should be used.\"\nmsgstr \"För att aktivera en plugin bör ``manim.cfg`` eller command line parametrar användas.\"\n\n#: ../../source/plugins.rst:66\nmsgid \"The plugins should be module name of the plugin and not PyPi name.\"\nmsgstr \"Pluginerna bör vara namnet på modulen, inte dess PyPI namn.\"\n\n#: ../../source/plugins.rst:68\nmsgid \"Enabling plugins through ``manim.cfg``\"\nmsgstr \"Aktivering av plugins via ``manim.cfg``\"\n\n#: ../../source/plugins.rst:75\nmsgid \"For specifying multiple plugins, command separated values must be used.\"\nmsgstr \"För att ange flera plugins så måste kommandoseparerade värden användas.\"\n\n#: ../../source/plugins.rst:83\nmsgid \"Creating Plugins\"\nmsgstr \"Skapa Plugins\"\n\n#: ../../source/plugins.rst:84\nmsgid \"Plugins are intended to extend Manim's core functionality. If you aren't sure whether a feature should be included in Manim's core, feel free to ask over on the `Discord server <https://www.manim.community/discord/>`_. Visit `manim-plugintemplate <https://pypi.org/project/manim-plugintemplate/>`_ on PyPI.org which serves as an in-depth tutorial for creating plugins.\"\nmsgstr \"Plugins är avsedda att utöka Manims kärnfunktionalitet. Om du inte är säker på om en funktion ska inkluderas i Manims kärna, fråga gärna på `Discord-servern <https://www.manim.community/discord/>`_. Besök även `manim-plugintemplate <https://pypi.org/project/manim-plugintemplate/>`_ på PyPI.org eftersom det fungerar som en fördjupad handledning för att skapa plugins.\"\n\n#: ../../source/plugins.rst:94\nmsgid \"The only requirement of manim plugins is that they specify an entry point with the group, ``\\\"manim.plugins\\\"``. This allows Manim to discover plugins available in the user's environment. Everything regarding the plugin's directory structure, build system, and naming are completely up to your discretion as an author. The aforementioned template plugin is only a model using Poetry since this is the build system Manim uses. The plugin's `entry point <https://packaging.python.org/specifications/entry-points/>`_ can be specified in poetry as:\"\nmsgstr \"Det enda kravet på manim plugins är att de anger en ingångspunkt genom gruppen, ``\\\"manim.plugins\\\"``. Detta gör det möjligt för Manim att upptäcka plugins som finns i användarens arbetsmiljö. Allt om pluginens katalogstruktur, byggsystem och namngivning är helt upp till din dina egna val som författare. Den ovannämnda mallpluginen är bara en modell med Poesi eftersom detta är byggsystemet som Manim använder. Pluginens `ingångspunkt <https://packaging.python.org/specifications/entry-points/>`_ kan anges i poesi som:\"\n\n#: ../../source/plugins.rst:108\nmsgid \"Here ``name`` is the name of the module of the plugin.\"\nmsgstr \"Här är ``name`` namnet på pluginens modul.\"\n\n#: ../../source/plugins.rst:110\nmsgid \"Here ``object_reference`` can point to either a function in a module or a module itself. For example,\"\nmsgstr \"Här kan ``object_reference`` peka mot antingen en funktion i en modul eller en modul själv. Till exempel,\"\n\n#: ../../source/plugins.rst:118\nmsgid \"Here a module is used as ``object_reference``, and when this plugin is enabled, Manim will look for ``__all__`` keyword defined in ``manim_plugintemplate`` and everything as a global variable one by one.\"\nmsgstr \"Här används en modul som ``object_reference``. När denna modul aktiveras så kommer Manim att leta efter nyckelordet ``__all__`` som definierats i ``manim_plugintemplate`` och allt som en global variabel en efter en.\"\n\n#: ../../source/plugins.rst:122\nmsgid \"If ``object_reference`` is a function, Manim calls the function and expects the function to return a list of modules or functions that need to be defined globally.\"\nmsgstr \"Om ``object_reference`` är en funktion så kommer Manim anropa funktionen och förväntar sig att funktionen returnerar en lista över moduler eller funktioner som behöver definieras globalt.\"\n\n#: ../../source/plugins.rst:125\nmsgid \"For example,\"\nmsgstr \"Till exempel,\"\n\n"
  },
  {
    "path": "docs/i18n/sv/LC_MESSAGES/reference.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: sv\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/reference.pot\\n\"\n\"X-Crowdin-File-ID: 5183\\n\"\n\"Language-Team: Swedish\\n\"\n\"Language: sv_SE\\n\"\n\"PO-Revision-Date: 2021-11-06 12:30\\n\"\n\n#: ../../source/reference.rst:2\nmsgid \"Reference Manual\"\nmsgstr \"Referensmanual\"\n\n#: ../../source/reference.rst:4\nmsgid \"This reference manual details modules, functions, and variables included in Manim, describing what they are and what they do.  For learning how to use Manim, see :doc:`tutorials`.  For a list of changes since the last release, see the :doc:`changelog`.\"\nmsgstr \"Denna referensmanual innehåller moduler, funktioner och variabler som inkluderas in Manim och beskriver de är och vad de gör. For att lära dig hur man använder Manim, se :doc:`tutorials`. For en lista över förändringar sedan den senaste utgåvan, se :doc:`förändringsrapporten`.\"\n\n#: ../../source/reference.rst:9\nmsgid \"The pages linked to here are currently a work in progress.\"\nmsgstr \"De sidor som dessa länkar leder till är fortfarande under aktiv påbyggnad.\"\n\n#: ../../source/reference.rst:12\nmsgid \"Inheritance Graphs\"\nmsgstr \"Grafer för arv\"\n\n#: ../../source/reference.rst:15\nmsgid \"Animations\"\nmsgstr \"Animationer\"\n\n#: ../../source/reference.rst:35\nmsgid \"Cameras\"\nmsgstr \"Kameror\"\n\n#: ../../source/reference.rst:47\nmsgid \"Mobjects\"\nmsgstr \"Mobjekt\"\n\n#: ../../source/reference.rst:84\nmsgid \"Scenes\"\nmsgstr \"Scener\"\n\n"
  },
  {
    "path": "docs/i18n/sv/LC_MESSAGES/reporting_bugs.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: sv\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/reporting_bugs.pot\\n\"\n\"X-Crowdin-File-ID: 5833\\n\"\n\"Language-Team: Swedish\\n\"\n\"Language: sv_SE\\n\"\n\"PO-Revision-Date: 2021-11-06 12:30\\n\"\n\n#: ../../source/reporting_bugs.rst:2\nmsgid \"Reporting bugs\"\nmsgstr \"Rapportering av buggar\"\n\n#: ../../source/reporting_bugs.rst:4\nmsgid \"One of the best ways of contributing to Manim is by reporting bugs.  If you have encountered something that you believe is a bug, please follow these steps:\"\nmsgstr \"Ett av de bästa sätten att bidra till Manim är genom att rapportera buggar. Om du har stött på något som du tror är en bugg, följ dessa steg:\"\n\n#: ../../source/reporting_bugs.rst:8\nmsgid \"First of all, make sure you are running the latest version of manim.  If not, update your version and try again.\"\nmsgstr \"Först och främst, se till att du kör den senaste versionen av manim. Om inte, uppdatera din version och försök igen.\"\n\n#: ../../source/reporting_bugs.rst:11\nmsgid \"Search for other users who may have had similar issues in the past. Search the repository's `issues page <https://github.com/ManimCommunity/manim/issues>`_ (don't forget to search closed issues), bring it up on our `Discord server <https://www.manim.community/discord/>`_, use sites like StackOverflow, and exercise your best Google practices.  If you can't find anything helpful, then go to the next step.\"\nmsgstr \"Sök efter andra användare som kan ha haft liknande problem tidigare. Sök i arkivets (repository) `issues page <https://github.com/ManimCommunity/manim/issues>`_ (glöm inte att söka även bland slutna ärenden), ta upp det i vår `Discord-server <https://www.manim.community/discord/>`_, använd webbplatser som StackOverflow och använd dig av dina bästa Google-metoder. Om du inte kan hitta något hjälpsamt, gå sedan till nästa steg.\"\n\n#: ../../source/reporting_bugs.rst:17\nmsgid \"Can reproduce the issue, i.e. that you have some code that illustrates the bug **every time** (or at least most of the time) it is executed.\"\nmsgstr \"Kan reproducera problemet, dvs att du har en kod som illustrerar felet **varje gång** (eller åtminstone de flesta gångerna) det körs.\"\n\n#: ../../source/reporting_bugs.rst:21\nmsgid \"Clarify what behavior you expected, and how the actual behavior differs from your expectation.\"\nmsgstr \"Klargör vilket beteende du förväntade dig och hur det faktiska beteendet skiljer sig från dina förväntningar.\"\n\n#: ../../source/reporting_bugs.rst:24\nmsgid \"Gather information about your environment, such as your operating system, python version, and any stack traces that the code may have generated (if applicable).\"\nmsgstr \"Samla information om din miljö, såsom ditt operativsystem, python-version, och eventuella stackspår som koden kan ha genererat (om möjligt).\"\n\n#: ../../source/reporting_bugs.rst:28\nmsgid \"Please open an issue only after you have gathered this information. When submitting an issue, make sure to follow the template (this is the default text you are shown when first opening the 'New Issue' page).  A community member will (hopefully) respond and start a conversation to address the issue.\"\nmsgstr \"Vänligen öppna ett problem först efter att du har samlat in denna information. När du skickar in ett ärende, se till att följa mallen (detta är standardtexten du visas när du först öppnar sidan 'Nytt ärende'. En medlem i communityn kommer (förhoppningsvis) att svara och starta en konversation för att ta itu med problemet.\"\n\n"
  },
  {
    "path": "docs/i18n/sv/LC_MESSAGES/tutorials/building_blocks.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: sv\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/tutorials/building_blocks.pot\\n\"\n\"X-Crowdin-File-ID: 5839\\n\"\n\"Language-Team: Swedish\\n\"\n\"Language: sv_SE\\n\"\n\"PO-Revision-Date: 2021-11-06 12:29\\n\"\n\n#: ../../source/tutorials/building_blocks.rst:3\nmsgid \"Manim's building blocks\"\nmsgstr \"Manims byggstenar\"\n\n#: ../../source/tutorials/building_blocks.rst:5\nmsgid \"This document explains the building blocks of manim and will give you all the necessary tools to start producing your own videos.\"\nmsgstr \"Detta dokument går igenom Manims byggstenar och ger dig alla verktyg som behövs för att börja producera dina egna videor.\"\n\n#: ../../source/tutorials/building_blocks.rst:8\nmsgid \"Essentially, manim puts at your disposal three different concepts that you can orchestrate together to produce mathematical animations: the **mathematical object** (or **mobject** for short) the **animation**, and the **scene**.  As we will see in the following sections, each of these three concepts is implemented in manim as a separate class: the :class:`.Mobject`, :class:`.Animation`, and :class:`.Scene` classes.\"\nmsgstr \"I huvudsak ställer Manim tre olika begrepp till ditt förfogande som du kan använda tillsammans med varandra för att producera matematiska animationer: det **matematiska objektet** (eller kortfattat **mobject**), **animationen** och **scenen**. Som vi kommer att se i följande avsnitt så implementeras var och ett av dessa i Manim som enskilda klasser: :class:`.Mobject`, :class:`.Animation`, och :class:`.Scene` klasserna.\"\n\n#: ../../source/tutorials/building_blocks.rst:15\nmsgid \"It is recommended that you read the tutorials :doc:`quickstart` and :doc:`a_deeper_look` before reading this page.\"\nmsgstr \"Det rekommenderas att du först läser följande tutorials, :doc:`quickstart` och :doc:`a_deeper_look`, före du läser vidare på denna sidan.\"\n\n#: ../../source/tutorials/building_blocks.rst:21\nmsgid \"Mobjects\"\nmsgstr \"Mobjekt\"\n\n#: ../../source/tutorials/building_blocks.rst:23\nmsgid \"Mobjects are the basic building block for all manim animations.  Each class that derives from :class:`.Mobject` represents an object that can be displayed on the screen.  For example, simple shapes such as :class:`.Circle`, :class:`.Arrow`, and :class:`.Rectangle` are all mobjects.  More complicated constructs such as :class:`.Axes`, :class:`.FunctionGraph`, or :class:`.BarChart` are mobjects as well.\"\nmsgstr \"Mobject är den grundläggande byggstenen för alla animationer som görs i manim. Varje klass som ärver från :class:`.Mobject` representerar ett objekt som kan visas på skärmen. Som exempel är  :class:`.Circle`, :class:`.Arrow`, och :class:`.Rectangle` allihopa Mobjekt. Andra mer komplicerade exempel är exempelvis  :class:`.Axes`, :class:`.FunctionGraph`, och :class:`.BarChart`.\"\n\n#: ../../source/tutorials/building_blocks.rst:30\nmsgid \"If you try to display an instance of :class:`.Mobject` on the screen, you will only see an empty frame.  The reason is that the :class:`.Mobject` class is an abstract base class of all other mobjects, i.e. it does not have any pre-determined visual shape that can be displayed on the screen.  It is only the skeleton of a thing that *could* be displayed.  Therefore, you will rarely need to use plain instances of :class:`.Mobject`; instead, you will most likely create instances of its derived classes.  One of these derived classes is :class:`.VMobject`.  The ``V`` stands for Vectorized Mobject.  In essence, a vmobject is a mobject that uses `vector graphics <https://en.wikipedia.org/wiki/Vector_graphics>`_ to be displayed.  Most of the time, you will be dealing with vmobjects, though we will continue to use the term \\\"mobject\\\" to refer to the class of shapes that can be displayed on the screen, as it is more general.\"\nmsgstr \"Om du försöker visa en instans av :class:`.Mobject` på skärmen kommer du bara att se en tom ram. Anledningen är att klassen :class:`.Mobject` är en abstrakt basklass för alla andra mobjects, dvs den har inte någon förutbestämd visuell form som kan visas på skärmen. Den är bara en skelettstruktur av en sak som *kunde* ha visats. Därför behöver du sällan använda vanliga instanser av :class:`.Mobject`; istället kommer du sannolikt att skapa instanser av dess härledda klasser. En av dessa härledda klasser är :class:`.VMobject`. ``V`` står för Vectorized Mobject. I grund och botten är ett vmobject ett mobject som använder `vektorgrafik <https://en.wikipedia.org/wiki/Vector_graphics>`_ för att visas. För det mesta kommer du egentligen att hantera vmobjects men vi kommer att fortsätta att använda termen \\\"mobject\\\" för att hänvisa till klasser av former som kan visas på skärmen. Det gör vi eftersom \\\"mobject\\\" är mer allmänt.\"\n\n#: ../../source/tutorials/building_blocks.rst:44\nmsgid \"Any object that can be displayed on the screen is a ``mobject``, even if it is not necessarily *mathematical* in nature.\"\nmsgstr \"Varje objekt som kan visas på skärmen är ett ``mobject`` även om det inte nödvändigtvis har en *matematisk* natur.\"\n\n#: ../../source/tutorials/building_blocks.rst:47\nmsgid \"To see examples of classes derived from :class:`.Mobject`, see the :mod:`.geometry` module.  Most of these are in fact derived from :class:`.VMobject` as well.\"\nmsgstr \"För att se exempel på klasser härledda från :class:`.Mobject`, se :mod:`.geometry`-modulen. De flesta av dessa härrör i själva verket från :class:`.VMobject` också.\"\n\n#: ../../source/tutorials/building_blocks.rst:53\nmsgid \"Creating and displaying mobjects\"\nmsgstr \"Skapa och visa mobjects\"\n\n#: ../../source/tutorials/building_blocks.rst:55\nmsgid \"As explained in :doc:`quickstart`, usually all of the code in a manim script is put inside the :meth:`.construct` method of a :class:`.Scene` class. To display a mobject on the screen, call the :meth:`~.Scene.add` method of the containing :class:`.Scene`.  This is the principal way of displaying a mobject on the screen when it is not being animated.  To remove a mobject from the screen, simply call the :meth:`~.Scene.remove` method from the containing :class:`.Scene`.\"\nmsgstr \"Som det förklaras i :doc:`quickstart` brukar all kod i ett manim-skript placeras i :meth:`.construct` metoden av en :class:`.Scene` klass. För att visa ett mobject på skärmen, anropa :meth:`~.Scene.add` metoden som finns i klassen :class:`.Scene`. Detta är det huvudsakliga sättet att visa ett mobject på skärmen när det inte animeras. För att ta bort ett mobject från skärmen anropa helt enkelt :meth:`~.Scene.remove`-metoden från klassen :class:`.Scene`.\"\n\n#: ../../source/tutorials/building_blocks.rst:75\nmsgid \"Placing mobjects\"\nmsgstr \"Placering av mobject\"\n\n#: ../../source/tutorials/building_blocks.rst:77\nmsgid \"Let's define a new :class:`.Scene` called ``Shapes`` and :meth:`~.Scene.add` some mobjects to it.  This script generates a static picture that displays a circle, a square, and a triangle:\"\nmsgstr \"Vi definierar nu en ny :class:`.Scene` som heter ``Shapes`` och lägger till några mobject till den med hjälp av metoden :meth:`~.Scene.add`. Detta skript genererar en orörlig bild som visar en cirkel, en kvadrat, och en triangel:\"\n\n#: ../../source/tutorials/building_blocks.rst:96\nmsgid \"By default, mobjects are placed at the center of coordinates, or *origin*, when they are first created.  They are also given some default colors.  Further, the ``Shapes`` scene places the mobjects by using the :meth:`.shift` method.  The square is shifted one unit in the ``UP`` direction from the origin, while the circle and triangle are shifted one unit ``LEFT`` and ``RIGHT``, respectively.\"\nmsgstr \"Som standard placeras mobjects i mitten av koordinatsystemet, eller *origin* (sv. origo), när de först skapas. De får också några standardfärger. Vidare placerar scenen ``Shapes`` mobject genom att använda :meth:`.shift` metoden. Kvadraten flyttas en enhet i ``UP`` riktningen från origo, medan cirkeln och triangeln respektive skiftas en enhet ``LEFT`` och ``RIGHT``.\"\n\n#: ../../source/tutorials/building_blocks.rst:102\nmsgid \"Unlike other graphics software, manim places the center of coordinates at the center of the screen.  The positive vertical direction is up, and the positive horizontal direction is right. See also the constants ``ORIGIN``, ``UP``, ``DOWN``, ``LEFT``, ``RIGHT``, and others, defined in the :mod:`.constants` module.\"\nmsgstr \"Till skillnad från andra grafikprogram placerar manim centrum av koordinatsystemet i mitten av skärmen. Den positiva vertikala riktningen är uppåt, och den positiva horisontella riktningen är åt höger. Se även konstanterna ``ORIGIN``, ``UP``, ``DOWN``, ``LEFT``, ``RIGHT`` och andra konstanter som definieras i :mod:`.constants`-modulen.\"\n\n#: ../../source/tutorials/building_blocks.rst:108\nmsgid \"There are many other possible ways to place mobjects on the screen, for example :meth:`.move_to`, :meth:`.next_to`, and :meth:`.align_to`.  The next scene ``MobjectPlacement`` uses all three.\"\nmsgstr \"Det finns många andra sätt att placera mobjekt på skärmen, till exempel genom metoderna :meth:`. move_to`, :meth:`.next_to` och :meth:`.align_to`. Nästa scen ``MobjectPlacement`` använder sig av alla tre.\"\n\n#: ../../source/tutorials/building_blocks.rst:130\nmsgid \"The :meth:`.move_to` method uses absolute units (measured relative to the ``ORIGIN``), while :meth:`.next_to` uses relative units (measured from the mobject passed as the first argument).  :meth:`align_to` uses ``LEFT`` not as measuring units but as a way to determine the border to use for alignment.  The coordinates of the borders of a mobject are determined using an imaginary bounding box around it.\"\nmsgstr \"Metoden :meth:`.move_to` använder sig av absoluta enheter (alltså, givet i förhållande till ``ORIGIN``), medan :meth:`.next_to` använder sig av relativa enheter (alltså, givet i förhållande till det mobject som ges i första argumentet).  :meth:`align_to` använder ``LEFT`` inte som en mätenhet utan som ett sätt att bestämma vilket gränssnitt som mobjectet ska justeras till. Koordinaterna för ett mobjects gränser bestäms med hjälp av en icke-visuell begränsningsruta runt den.\"\n\n#: ../../source/tutorials/building_blocks.rst:137\nmsgid \"Many methods in manim can be chained together.  For example the two lines\"\nmsgstr \"Många metoder i manim kan kedjas ihop. Till exempel de två raderna\"\n\n#: ../../source/tutorials/building_blocks.rst:145\nmsgid \"can be replaced by\"\nmsgstr \"kan ersättas med\"\n\n#: ../../source/tutorials/building_blocks.rst:151\nmsgid \"Technically, this is possible because most methods calls return the modified mobject.\"\nmsgstr \"Tekniskt sett är detta möjligt eftersom de flesta metodanrop returnerar det modifierade mobjectet.\"\n\n#: ../../source/tutorials/building_blocks.rst:155\nmsgid \"Styling mobjects\"\nmsgstr \"Styla mobject\"\n\n#: ../../source/tutorials/building_blocks.rst:157\nmsgid \"The following scene changes the default aesthetics of the mobjects.\"\nmsgstr \"Följande scen ändrar mobjektens standardutseende.\"\n\n#: ../../source/tutorials/building_blocks.rst:174\nmsgid \"This scene uses two of the main functions that change the visual style of a mobject: :meth:`.set_stroke` and :meth:`.set_fill`.  The former changes the visual style of the mobject's border while the latter changes the style of the interior.  By default, most mobjects have a fully transparent interior so you must specify the ``opacity`` parameter to display the color.  An opacity of ``1.0`` means fully opaque, while ``0.0`` means fully transparent.\"\nmsgstr \"Denna scen använder två huvudfunktioner som ändrar den visuella stilen på ett mobject: :meth:`.set_stroke` och :meth:`.set_fill`. Den första ändrar den visuella stilen på mobjectets rand medan den andra ändrar stilen på interiören. Som standard har de flesta mobjects en helt genomskinlig interiör så du måste ange parametern ``opacity`` för att visa färgen. Ett opacitetsvärde på ``1.0`` betyder helt ogenomskinlig, medan ``0.0`` betyder helt genomskinlig.\"\n\n#: ../../source/tutorials/building_blocks.rst:181\nmsgid \"Only instances of :class:`.VMobject` implement :meth:`.set_stroke` and :meth:`.set_fill`.  Instances of :class:`.Mobject` implement :meth:`.~Mobject.set_color` instead.  The vast majority of pre-defined classes are derived from :class:`.VMobject` so it is usually safe to assume that you have access to :meth:`.set_stroke` and :meth:`.set_fill`.\"\nmsgstr \"Endast instanser av :class:`.VMobject` implementerar :meth:`.set_stroke` och :meth:`.set_fill`. Instanser av :class:`.Mobject` implementerar :meth:`.~Mobject.set_color` istället. De allra flesta fördefinierade klasser härstammar från :class:`.VMobject` så det är vanligtvis säkert att anta att du har tillgång till :meth:`.set_stroke` och :meth:`.set_fill`.\"\n\n#: ../../source/tutorials/building_blocks.rst:189\nmsgid \"Mobject on-screen order\"\nmsgstr \"Ordningen av Mobject på skärmen\"\n\n#: ../../source/tutorials/building_blocks.rst:191\nmsgid \"The next scene is exactly the same as the ``MobjectStyling`` scene from the previous section, except for exactly one line.\"\nmsgstr \"Nästa scen är exakt samma som ``MobjectStyling`` scenen från föregående avsnitt, med undantag för exakt en rad.\"\n\n#: ../../source/tutorials/building_blocks.rst:209\nmsgid \"The only difference here (besides the scene name) is the order in which the mobjects are added to the scene.  In ``MobjectStyling``, we added them as ``add(circle, square, triangle)``, whereas in ``MobjectZOrder`` we add them as ``add(triangle, square, circle)``.\"\nmsgstr \"Den enda skillnaden här (förutom scennamnet) är den ordning i vilken mobjects läggs till i scenen. I ``MobjectStyling``, lade vi till dem som ``add(circle, square, triangle)``, medan vi i ``MobjectZOrder`` lägger till dem som ``add(triangle, square, circle)``.\"\n\n#: ../../source/tutorials/building_blocks.rst:214\nmsgid \"As you can see, the order of the arguments of :meth:`~.Scene.add` determines the order that the mobjects are displayed on the screen, with the left-most arguments being put in the back.\"\nmsgstr \"Som du kan se så bestämmer ordningen på argumenten i :meth:`~.Scene.add` den ordning som mobjects visas på skärmen, så att argumentet längst till vänster hamnar längst bak.\"\n\n#: ../../source/tutorials/building_blocks.rst:221\nmsgid \"Animations\"\nmsgstr \"Animationer\"\n\n#: ../../source/tutorials/building_blocks.rst:223\nmsgid \"At the heart of manim is animation.  Generally, you can add an animation to your scene by calling the :meth:`~.Scene.play` method.\"\nmsgstr \"Manims största syfte är att animera. Allmänt så kan du lägga till en animation till din scen genom att anropa :meth:`~.Scene.play`-metoden.\"\n\n#: ../../source/tutorials/building_blocks.rst:244\nmsgid \"Put simply, animations are procedures that interpolate between two mobjects. For example, :code:`FadeIn(square)` starts with a fully transparent version of :code:`square` and ends with a fully opaque version, interpolating between them by gradually increasing the opacity.  :class:`.FadeOut` works in the opposite way: it interpolates from fully opaque to fully transparent.  As another example, :class:`.Rotate` starts with the mobject passed to it as argument, and ends with the same object but rotated by a certain amount, this time interpolating the mobject's angle instead of its opacity.\"\nmsgstr \"Enkelt uttryckt är animationer procedurer som interpolerar mellan två mobjects. Till exempel börjar :code:`FadeIn(square)` med en helt genomskinlig version av :code:`square` och avslutas med en helt ogenomskinlig version, och detta sker genom att interpolera mellan dem genom att gradvis öka opaciteten.  :class:`.FadeOut` fungerar på motsatt sätt: den interpolerar från helt ogenomskinlig till helt genomskinlig. Som ett annat exempel :class:`.Rotate` börjar med mobjectet som skickats till det som argument, och slutar med samma objekt men roterat med ett visst belopp, genom att denna gångenn interpolera mobjektets vinkel istället för dess opacitet.\"\n\n#: ../../source/tutorials/building_blocks.rst:255\nmsgid \"Animating methods\"\nmsgstr \"Animeringsmetoder\"\n\n#: ../../source/tutorials/building_blocks.rst:257\nmsgid \"Any property of a mobject that can be changed can be animated.  In fact, any method that changes a mobject's property can be used as an animation, through the use of :meth:`.animate`.\"\nmsgstr \"Varje egenskap hos ett mobject som kan ändras kan även animeras. Faktum är att alla metoder som ändrar ett mobjects egenskaper kan användas som en animation genom att använda :meth:`.animate`.\"\n\n#: ../../source/tutorials/building_blocks.rst:277\nmsgid \":meth:`.animate` is a property of all mobjects that animates the methods that come afterward. For example, :code:`square.set_fill(WHITE)` sets the fill color of the square, while :code:`sqaure.animate.set_fill(WHITE)` animates this action.\"\nmsgstr \":meth:`.animate` är en egenskap hos alla mobjekt som animerar metoderna som kommer efteråt. Till exempel anger :code:`square.set_fill(WHITE)` fyllnadsfärgen på fyrkanten, medan :code:`square.animate.set_fill(WHITE)` animerar detta.\"\n\n#: ../../source/tutorials/building_blocks.rst:282\nmsgid \"Animation run time\"\nmsgstr \"Animationens körtid\"\n\n#: ../../source/tutorials/building_blocks.rst:284\nmsgid \"By default, any animation passed to :meth:`play` lasts for exactly one second. Use the :code:`run_time` argument to control the duration.\"\nmsgstr \"Som standard varar varje animation som skickats till :meth:`play` i exakt en sekund. Använd argumentet :code:`run_time` för att kontrollera varaktigheten.\"\n\n#: ../../source/tutorials/building_blocks.rst:297\nmsgid \"Creating a custom animation\"\nmsgstr \"Skapa en egen animation\"\n\n#: ../../source/tutorials/building_blocks.rst:299\nmsgid \"Even though Manim has many built-in animations, you will find times when you need to smoothly animate from one state of a :class:`~.Mobject` to another. If you find yourself in that situation, then you can define your own custom animation. You start by extending the :class:`~.Animation` class and overriding its :meth:`~.Animation.interpolate_mobject`. The :meth:`~.Animation.interpolate_mobject` method receives alpha as a parameter that starts at 0 and changes throughout the animation. So, you just have to manipulate self.mobject inside Animation according to the alpha value in its interpolate_mobject method. Then you get all the benefits of :class:`~.Animation` such as playing it for different run times or using different rate functions.\"\nmsgstr \"Även om Manim har många inbyggda animationer, kommer det vara stunder när du behöver animera smidigt från ett tillstånd av ett :class:`~.Mobject` till ett annat. Om du befinner dig i den situationen kan du definiera en egen animation. Du börjar med att utöka :class:`~.Animation`-klassen och åsidosätter dess :meth:`~.Animation.interpolate_mobject`. :meth:`~.Animation.interpolate_mobject` -metoden får alfa som en parameter som startar vid 0 och ändras under hela animationen. Så du behöver bara manipulera self.mobject inuti Animation enligt alfa värdet i dess interpolate_mobject-metod. Då får du alla fördelar med :class:`~.Animation` såsom att spela det under olika körtider eller använda olika hastighetsfunktioner.\"\n\n#: ../../source/tutorials/building_blocks.rst:306\nmsgid \"Let's say you start with a number and want to create a :class:`~.Transform` animation that transforms it to a target number. You can do it using :class:`~.FadeTransform`, which will fade out the starting number and fade in the target number. But when we think about transforming a number from one to another, an intuitive way of doing it is by incrementing or decrementing it smoothly. Manim has a feature that allows you to customize this behavior by defining your own custom animation.\"\nmsgstr \"Låt oss säga att du börjar med ett tal och vill skapa en :class:`~.Transform`-animation som omvandlar talet till ett annat givet tal. Du kan göra det med :class:`~.FadeTransform`, vilket kommer att tona bort det första talet och tona in det andra talet. Men när vi tänker på att omvandla ett tal till ett annat, är ett intuitivt sätt att göra det genom att inkrementera eller dekrementera det på ett smidigt sätt. Manim har en funktion som gör att du kan anpassa detta beteende genom att definiera din egen animation.\"\n\n#: ../../source/tutorials/building_blocks.rst:311\nmsgid \"You can start by creating your own ``Count`` class that extends :class:`~.Animation`. The class can have a constructor with three arguments, a :class:`~.DecimalNumber` Mobject, start, and end. The constructor will pass the :class:`~.DecimalNumber` Mobject to the super constructor (in this case, the :class:`~.Animation` constructor) and will set start and end.\"\nmsgstr \"Du kan börja med att skapa din egen ``Count`` klass som utökar klassen :class:`~.Animation`. Klassen kan ha en konstruktor med tre argument, ett :class:`~.DecimalNumber` Mobject, start and end. Konstruktorn kommer att skicka :class:`~.DecimalNumber` Mobject till superkonstruktorn (i detta fall konstruktorn i :class:`~.Animation`) och kommer att ställa in start och slut.\"\n\n#: ../../source/tutorials/building_blocks.rst:315\nmsgid \"The only thing that you need to do is to define how you want it to look at every step of the animation. Manim provides you with the alpha value in the :meth:`~.Animation.interpolate_mobject` method based on frame rate of video, rate function, and run time of animation played. The alpha parameter holds a value between 0 and 1 representing the step of the currently playing animation. For example, 0 means the beginning of the animation, 0.5 means halfway through the animation, and 1 means the end of the animation.\"\nmsgstr \"Det enda du behöver göra är att definiera hur du vill att det ska se ut för varje steg i animationen. Manim ger dig alfavärdet i :meth:`~. nimation.interpolate_mobject' metoden baserat på bildhastigheten av videon, hastighetsfunktionen och körtiden för den animation som spelas. Alfaparametern har ett värde mellan 0 och 1 som representerar steget i den aktuella animationen. Till exempel betyder 0 början av animationen, 0,5 betyder halvvägs genom animationen och 1 betyder slutet av animationen.\"\n\n#: ../../source/tutorials/building_blocks.rst:320\nmsgid \"In the case of the ``Count`` animation, you just have to figure out a way to determine the number to display at the given alpha value and then set that value in the :meth:`~.Animation.interpolate_mobject` method of the ``Count`` animation. Suppose you are starting at 50 and incrementing until the :class:`~.DecimalNumber` reaches 100 at the end of the animation.\"\nmsgstr \"I fallet med ``Count`` animationen, behöver du bara hitta ett sätt att bestämma talet som ska visas för det givna alfavärdet och sedan ange det värdet i :meth:`~.Animation.interpolate_mobject` -metoden för ``Count``-animationen. Antag att du börjar med 50 och inkrementerar värdet tills :class:`~.DecimalNumber` når 100 i slutet av animationen.\"\n\n#: ../../source/tutorials/building_blocks.rst:323\nmsgid \"If alpha is 0, you want the value to be 50.\"\nmsgstr \"Om alfa är 0, vill du att värdet ska vara 50.\"\n\n#: ../../source/tutorials/building_blocks.rst:324\nmsgid \"If alpha is 0.5, you want the value to be 75.\"\nmsgstr \"Om alfa är 0,5, vill du att värdet ska vara 75.\"\n\n#: ../../source/tutorials/building_blocks.rst:325\nmsgid \"If alpha is 1, you want the value to be 100.\"\nmsgstr \"Om alfa är 1, vill du att värdet ska vara 100.\"\n\n#: ../../source/tutorials/building_blocks.rst:327\nmsgid \"Generally, you start with the starting number and add only some part of the value to be increment according to the alpha value. So, the logic of calculating the number to display at each step will be - 50 + alpha * (100 - 50). Once you set the calculated value for the :class:`~.DecimalNumber`, you are done.\"\nmsgstr \"Allmänt så börjar du med startnumret och adderar bara en del av värdet som ska inkrementeras enligt vad alfavärdet är. Så den programlogik som behövs för att beräkna talet som ska visas vid varje steg kommer att vara - 50 + alfa * (100 - 50). När du satt det beräknade värdet för :class:`~.DecimalNumber`-klassen är du klar.\"\n\n#: ../../source/tutorials/building_blocks.rst:331\nmsgid \"Once you have defined your ``Count`` animation, you can play it in your :class:`~.Scene` for any duration you want for any :class:`~.DecimalNumber` with any rate function.\"\nmsgstr \"När du väl har definierat din ``Count`` animation kan du spela upp den i din :class:`~.Scene` med given varaktighet för vilken klass :class:`~.DecimalNumber` som helst, med valfri hastighetsfunktion.\"\n\n#: ../../source/tutorials/building_blocks.rst:368\nmsgid \"Using coordinates of a mobject\"\nmsgstr \"Använda ett mobjects koordinater\"\n\n#: ../../source/tutorials/building_blocks.rst:370\nmsgid \"Mobjects contain points that define their boundaries. These points can be used to add other mobjects respectively to each other, e.g. by methods like :meth:`~.Mobject.get_center` , :meth:`~.Mobject.get_top` and :meth:`~.Mobject.get_start`. Here is an example of some important coordinates:\"\nmsgstr \"Mobject innehåller punkter som definierar objektets rand. Dessa punkter kan användas för att lägga till andra mobjects gentemot varandra, t.ex. genom metoder som :meth:`~.Mobject.get_center` , :meth:`~.Mobject.get_top` och :meth:`~.Mobject.get_start`. Här är ett exempel på några viktiga koordinater:\"\n\n#: ../../source/tutorials/building_blocks.rst:402\nmsgid \"Transforming mobjects into other mobjects\"\nmsgstr \"Omvandla mobjects till andra mobjects\"\n\n#: ../../source/tutorials/building_blocks.rst:403\nmsgid \"It is also possible to transform a mobject into another mobject like this:\"\nmsgstr \"Det är också möjligt att förvandla ett mobject till ett annat mobject på detta vis:\"\n\n#: ../../source/tutorials/building_blocks.rst:414\nmsgid \"The Transform function maps points of the previous mobject to the points of the next mobject. This might result in strange behaviour, e.g. when the dots of one mobject are arranged clockwise and the other points are arranged counterclockwise. Here it might help to use the `flip` function and reposition the points via the `roll <https://numpy.org/doc/stable/reference/generated/numpy.roll.html>`_ function of numpy:\"\nmsgstr \"Transform-funktionen avbildar punkter hos det tidigare mobjectet till punkterna i nästa mobject. Detta kan resultera i konstigt beteende, t.ex. när punkter av ett mobject arrangeras medsols och det andra mobjectets punkter arrangeras motsols. Här kan det hjälpa att använda `flip`-funktionen och flytta punkterna via `roll <https://numpy.org/doc/stable/reference/generated/numpy.roll.html>`_ funktionen i numpy:\"\n\n#: ../../source/tutorials/building_blocks.rst:440\nmsgid \"Scenes\"\nmsgstr \"Scener\"\n\n"
  },
  {
    "path": "docs/i18n/sv/LC_MESSAGES/tutorials/quickstart.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: sv\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/tutorials/quickstart.pot\\n\"\n\"X-Crowdin-File-ID: 5843\\n\"\n\"Language-Team: Swedish\\n\"\n\"Language: sv_SE\\n\"\n\"PO-Revision-Date: 2021-11-06 12:29\\n\"\n\n#: ../../source/tutorials/quickstart.rst:3\nmsgid \"Quickstart\"\nmsgstr \"Snabbstart\"\n\n#: ../../source/tutorials/quickstart.rst:5\nmsgid \"This document will lead you step by step through the necessary procedure to get started with manim for the first time as soon as possible.  This tutorial assumes you have already installed manim following the steps in :doc:`../installation`.\"\nmsgstr \"Detta dokument kommer att leda dig steg för steg genom de nödvändiga stegen för att komma igång med manim för första gången. Den här övningen förutsätter att du redan har installerat manim efter stegen i :doc:`../installation`.\"\n\n#: ../../source/tutorials/quickstart.rst:12\nmsgid \"Start a new project\"\nmsgstr \"Starta ett nytt projekt\"\n\n#: ../../source/tutorials/quickstart.rst:14\nmsgid \"To start a new manim video project, all you need to do is choose a single folder where all of the files related to the video will reside.  For this example, this folder will be called ``project``,\"\nmsgstr \"För att starta ett nytt manimvideoprojekt är allt du behöver göra att välja eller skapa en enda mapp där alla filer relaterade till videon kommer sparas. Till exempel kommer den här mappen att heta ``project``,\"\n\n#: ../../source/tutorials/quickstart.rst:22\nmsgid \"Every file containing code that produces a video with manim will be stored here, as well as any output files that manim produces and configuration files that manim needs.\"\nmsgstr \"Varje fil som innehåller kod som genererar en video med manim kommer att lagras här, samt alla utdatafiler som manim producerar och konfigurationsfiler som manim behöver.\"\n\n#: ../../source/tutorials/quickstart.rst:28\nmsgid \"In case you like to work with Jupyterlab / Jupyter notebooks, there is good news: Manim ships with a ``%%manim`` IPython magic command which makes it easy to use in such a setting as well. Find out more in the :meth:`corresponding documentation <manim.utils.ipython_magic.ManimMagic.manim>`.\"\nmsgstr \"Om du föredrar att arbeta med Jupyterlab / Jupyter notebooks så finns goda nyheter: Manim utges med ett ``%%manim`` IPython magic command som gör det enkelt att använda Manim i en sådan miljö också. Läs mer i :meth:`motsvarande dokumentation <manim.utils.ipython_magic.ManimMagic.manim>`.\"\n\n#: ../../source/tutorials/quickstart.rst:35\nmsgid \"Your first Scene\"\nmsgstr \"Din första scen\"\n\n#: ../../source/tutorials/quickstart.rst:37\nmsgid \"To produce your first scene, create a new file in your project folder called ``scene.py``,\"\nmsgstr \"För att producera din första scen skapar du en ny fil i din projektmapp som heter ``scene.py``,\"\n\n#: ../../source/tutorials/quickstart.rst:45\nmsgid \"and copy the following code in it.\"\nmsgstr \"och klistra in följande kod in i den.\"\n\n#: ../../source/tutorials/quickstart.rst:58\nmsgid \"Then open your command line, navigate to your project directory, and execute the following command:\"\nmsgstr \"Öppa sedan din command line, navigera till din projectkatalog och kör följande kommando:\"\n\n#: ../../source/tutorials/quickstart.rst:65\nmsgid \"After showing some output, manim should render the scene into a .mp4 file, and open that file with the default movie player application.  You should see a video playing the following animation.\"\nmsgstr \"Efter att ha visat lite utdata bör manim göra scenen till en .mp4 fil, samt öppna filen med din standard videospelare. Du bör se en video som spelar upp följande animation.\"\n\n#: ../../source/tutorials/quickstart.rst:78\nmsgid \"If you see the video and it looks correct, congrats! You just wrote your first manim scene from scratch.  If you get an error message instead, or if do not see a video, or if the video output does not look like this, it is likely that manim has not been installed correctly. Please refer to the :doc:`../installation/troubleshooting` page for more information.\"\nmsgstr \"Om du ser videon och den ser korrekt ut, grattis! Du har precis skrivit din första manimscen från grunden. Om du får ett felmeddelande istället, om du inte kan se en video eller om den producerade videon inte ser ut så här så är det troligt att manim inte har installerats korrekt. Se sidan :doc:`../installation/troubleshooting` för mer information.\"\n\n#: ../../source/tutorials/quickstart.rst:87\nmsgid \"Explanation\"\nmsgstr \"Förklaring\"\n\n#: ../../source/tutorials/quickstart.rst:89\nmsgid \"Let's go line by line over the script we just executed to see how manim was able to generate the video.\"\nmsgstr \"Låt oss gå rad för rad genom skriptet som vi just körde för att se hur manim kunde generera videon.\"\n\n#: ../../source/tutorials/quickstart.rst:92\nmsgid \"The first line\"\nmsgstr \"Första raden\"\n\n#: ../../source/tutorials/quickstart.rst:98\nmsgid \"imports all of the contents of the library.  This is the recommended way of using manim, as usually in a single script you will be using quite a few names from the manim namespace.  In particular, this line includes all of the names used in the script: ``Scene``, ``Circle``, ``PINK`` and ``Create``.\"\nmsgstr \"importerar allt innehåll i biblioteket. Detta är det rekommenderade sättet att använda manim eftersom du vanligtvis kommer att använda en hel del namn från manims namespace  i ett enda skript. Speciellt innehåller den här raden alla namn som används i skriptet: ``Scene``, ``Circle``, ``PINK`` och ``Create``.\"\n\n#: ../../source/tutorials/quickstart.rst:103\nmsgid \"Now let's look at the next two lines.\"\nmsgstr \"Nu kan vi titta på de nästa två raderna.\"\n\n#: ../../source/tutorials/quickstart.rst:111\nmsgid \"Most of the time, the code for scripting an animation with manim will go inside the :meth:`~.Scene.construct` method of a class that derives from :class:`.Scene`.  Inside this method, you will create objects, display them on screen, and animate them.\"\nmsgstr \"Merparten av tiden, kommer koden för att skripta en animation med manim att gå in i :meth:`~.Scene. onstruct` metoden av en klass som härstammar från :class:`.Scene`. Inuti denna metod kommer du att skapa objekt, visa dem på skärmen och animera dem.\"\n\n#: ../../source/tutorials/quickstart.rst:115\nmsgid \"The next two lines create a circle and set its color and opacity.\"\nmsgstr \"De två nästkommande två raderna skapar en cirkel och anger dess färg och opacitet.\"\n\n#: ../../source/tutorials/quickstart.rst:122\nmsgid \"Finally, the last line uses the animation :class:`.Create` to display the circle on the screen.\"\nmsgstr \"Slutligen använder den sista raden animationen :class:`.Create` för att visa cirkeln på skärmen.\"\n\n#: ../../source/tutorials/quickstart.rst:129\nmsgid \"Every animation must be contained within the :meth:`~.Scene.construct` method of a class that derives from :class:`.Scene`.  Other code, for example auxiliary or mathematical functions, may reside outside the class.\"\nmsgstr \"Varje animation måste finnas i :meth:`~.Scene.construct`-metoden i en klass som härstammar från :class:`.Scene`. Annan kod, till exempel hjälpfunktioner eller matematiska funktioner, får finnas utanför klassen.\"\n\n#: ../../source/tutorials/quickstart.rst:135\nmsgid \"Some bells and whistles\"\nmsgstr \"Lite extra fint och glans\"\n\n#: ../../source/tutorials/quickstart.rst:137\nmsgid \"Our scene is a little basic, so let's add some bells and whistles.  Modify the ``scene.py`` file to contain the following:\"\nmsgstr \"Vår scen är lite platt och tråkig, så vi kan lägga till lite extra glans. Ändra filen ``scene.py`` så att den innehåller följande:\"\n\n#: ../../source/tutorials/quickstart.rst:157\nmsgid \"And render it using the following command:\"\nmsgstr \"Och rendera den genom att använda följande kommando:\"\n\n#: ../../source/tutorials/quickstart.rst:163\nmsgid \"The output should look as follows.\"\nmsgstr \"Utmatningen från skriptet bör se ut på följande sätt.\"\n\n#: ../../source/tutorials/quickstart.rst:180\nmsgid \"This example shows one of the most basic features of manim: the ability to implement complicated and mathematically intensive animations (such as cleanly interpolating between two geometric shapes) in very few lines of code.\"\nmsgstr \"Detta exempel visar en av de mest grundläggande funktionerna hos manim: förmågan att genomföra komplicerade och matematiskt intensiva animationer (såsom att snyggt interpolera mellan två geometriska former) i mycket få rader av kod.\"\n\n#: ../../source/tutorials/quickstart.rst:187\nmsgid \"You're done!\"\nmsgstr \"Du är klar!\"\n\n"
  },
  {
    "path": "docs/i18n/sv/LC_MESSAGES/tutorials.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Crowdin-Project: 031f65d9b7a2e83b265c23f1c4450271\\n\"\n\"X-Crowdin-Project-ID: 1\\n\"\n\"X-Crowdin-Language: sv\\n\"\n\"X-Crowdin-File: /[ManimCommunity.manim] main/docs/i18n/gettext/tutorials.pot\\n\"\n\"X-Crowdin-File-ID: 5835\\n\"\n\"Language-Team: Swedish\\n\"\n\"Language: sv_SE\\n\"\n\"PO-Revision-Date: 2021-11-06 12:30\\n\"\n\n#: ../../source/tutorials.rst:4\n#: ../../source/tutorials.rst:4\nmsgid \"Table of Contents\"\nmsgstr \"Innehållsförteckning\"\n\n"
  },
  {
    "path": "docs/make.bat",
    "content": "@ECHO OFF\r\n\r\npushd %~dp0\\source\r\n\r\nREM Command file for Sphinx documentation\r\n\r\nif \"%SPHINXBUILD%\" == \"\" (\r\n\tset SPHINXBUILD=sphinx-build\r\n)\r\n\r\nREM The paths are taken from the source directory\r\nset SOURCEDIR=.\r\nset BUILDDIR=..\\build\r\n\r\nif \"%1\" == \"\" goto help\r\n\r\n%SPHINXBUILD% >NUL 2>NUL\r\nif errorlevel 9009 (\r\n\techo.\r\n\techo.The 'sphinx-build' command was not found. Make sure you have Sphinx\r\n\techo.installed, then set the SPHINXBUILD environment variable to point\r\n\techo.to the full path of the 'sphinx-build' executable. Alternatively you\r\n\techo.may add the Sphinx directory to PATH.\r\n\techo.\r\n\techo.If you don't have Sphinx installed, grab it from\r\n\techo.http://sphinx-doc.org/\r\n\texit /b 1\r\n)\r\n\r\n%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%\r\ngoto end\r\n\r\n:help\r\n%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%\r\n\r\n:end\r\npopd\r\n"
  },
  {
    "path": "docs/requirements.txt",
    "content": "furo\nmyst-parser\nsphinx>=7.3\nsphinx-copybutton\nsphinxext-opengraph\nsphinx-design\nsphinx-reredirects\n"
  },
  {
    "path": "docs/rtd-requirements.txt",
    "content": "jupyterlab\nsphinxcontrib-programoutput\n"
  },
  {
    "path": "docs/skip-manim",
    "content": ""
  },
  {
    "path": "docs/source/_static/custom.css",
    "content": "@media (prefers-color-scheme: dark) {\n    span.nc {\n        text-decoration: none !important;\n    }\n}\n\n.admonition-manim-example {\n    padding: 0;\n    display: flex;\n    flex-direction: column;\n}\n\n.admonition-manim-example p.admonition-title {\n    font-weight: 600;\n    font-size: 0.925rem;\n    margin: 0;\n}\n\n.admonition-manim-example .highlight-python {\n    margin: 0;\n}\n\n.admonition-manim-example .highlight {\n    border-radius: 0;\n}\n\n.admonition-manim-example .highlight pre {\n    font-size: 15px;\n}\n\n.manim-video {\n    width: 100%;\n    padding: 8px 0;\n    outline: 0;\n}\n\n.admonition-manim-example .manim-video {\n    padding: 0;\n}\n\n.admonition-manim-example img {\n    margin-bottom: 0;\n}\n\n.admonition-manim-example p:last-child {\n    margin-top: 0;\n    padding-left: 0.5rem;\n    padding-bottom: 0.15rem;\n    font-size: 15px;\n}\n\n.admonition-manim-example .copybtn {\n    margin-right: 6px;\n    font-size: 18px;\n}\n\n.admonition-manim-example .copybtn:hover {\n    cursor: pointer;\n}\n\np.rubric{\n    text-transform: capitalize;\n    font-size: 1.25rem;\n    font-weight: bold;\n}\n\n.sig-param{\n    color: var(--color-content-foreground);\n}\n\ndl.c .field-list dt, dl.cpp .field-list dt, dl.js .field-list dt, dl.py .field-list dt {\n    text-transform: capitalize;\n    font-weight: bold;\n    font-size: var(--font-size--normal);\n}\n\nh4, h5, h6{\n    text-transform: none;\n}\n\n/* yikes-ish attempt at bugfix for navbar on some browsers */\n.sidebar-tree a.internal.reference {\n    display: table-cell;\n}\n\n.manim-binder-button {\n    text-transform: capitalize;\n    padding: 10px 20px;\n    margin: 10px 0;\n}\n\n.manim-binder-wrapper {\n    background-color: var(--color-code-background);\n    color: var(--color-code-foreground);\n}\n\n.manim-binder-title {\n    margin-top: 0;\n}\n\n.manim-binder-button-wrapper {\n    margin: 0px 10px;\n}\n"
  },
  {
    "path": "docs/source/_static/manim-binder.min.js.LICENSE.txt",
    "content": "/*!\n * is-plain-object <https://github.com/jonschlinkert/is-plain-object>\n *\n * Copyright (c) 2014-2017, Jon Schlinkert.\n * Released under the MIT License.\n */\n"
  },
  {
    "path": "docs/source/_static/responsiveSvg.js",
    "content": "\nwindow.addEventListener(\"load\", function () {\n    const styleElements = []\n    const colorSchemeQuery = window.matchMedia('(prefers-color-scheme: dark)');\n    const diagrams = document.querySelectorAll(\"object.inheritance.graphviz\");\n\n    for (let diagram of diagrams) {\n        style = document.createElement('style');\n        styleElements.push(style);\n        console.log(diagram);\n        diagram.contentDocument.firstElementChild.appendChild(style);\n    }\n\n    function setColorScheme(e) {\n        let colors, additions = \"\";\n        if (e.matches) {\n            // Dark\n            colors = {\n                text: \"#e07a5f\",\n                box: \"#383838\",\n                edge: \"#d0d0d0\",\n                background: \"#131416\"\n            };\n        } else {\n            // Light\n            colors = {\n                text: \"#e07a5f\",\n                box: \"#fff\",\n                edge: \"#413c3c\",\n                background: \"#ffffff\"\n            };\n            additions = `\n            .node polygon {\n                filter: drop-shadow(0 1px 3px #0002);\n            }\n            `\n        }\n        for (let style of styleElements) {\n            style.innerHTML = `\n                svg {\n                    background-color: ${colors.background};\n                }\n\n                .node text {\n                    fill: ${colors.text};\n                }\n\n                .node polygon {\n                    fill: ${colors.box};\n                }\n\n                .edge polygon {\n                    fill: ${colors.edge};\n                    stroke: ${colors.edge};\n                }\n\n                .edge path {\n                    stroke: ${colors.edge};\n                }\n                ${additions}\n            `;\n        }\n    }\n\n    setColorScheme(colorSchemeQuery);\n    colorSchemeQuery.addEventListener(\"change\", setColorScheme);\n});\n"
  },
  {
    "path": "docs/source/_templates/autosummary/class.rst",
    "content": "{{ name | escape | underline}}\n\nQualified name: ``{{ fullname | escape }}``\n\n.. currentmodule:: {{ module }}\n\n.. autoclass:: {{ objname }}\n   :show-inheritance:\n   :members:\n   :private-members:\n\n\n   {% block methods %}\n   {%- if methods %}\n   .. rubric:: {{ _('Methods') }}\n\n   .. autosummary::\n      :nosignatures:\n      {% for item in methods if item != '__init__' and item not in inherited_members %}\n      ~{{ name }}.{{ item }}\n      {%- endfor %}\n   {%- endif %}\n   {%- endblock %}\n\n   {% block attributes %}\n   {%- if attributes %}\n   .. rubric:: {{ _('Attributes') }}\n\n   .. autosummary::\n     {% for item in attributes %}\n     ~{{ name }}.{{ item }}\n     {%- endfor %}\n   {%- endif %}\n   {% endblock %}\n"
  },
  {
    "path": "docs/source/_templates/autosummary/module.rst",
    "content": "{{ name | escape | underline }}\n\n.. currentmodule:: {{ fullname }}\n\n.. automodule:: {{ fullname }}\n\n   {# SEE manim.utils.docbuild.autoaliasattr_directive #}\n   {# FOR INFORMATION ABOUT THE CUSTOM autoaliasattr DIRECTIVE! #}\n   .. autoaliasattr:: {{ fullname }}\n\n   {% block classes %}\n   {% if classes %}\n   .. rubric:: Classes\n\n   .. autosummary::\n      :toctree: .\n      :nosignatures:\n      {% for class in classes %}\n        {{ class }}\n      {% endfor %}\n   {% endif %}\n   {% endblock %}\n\n   {% block functions %}\n   {% if functions %}\n   .. rubric:: {{ _('Functions') }}\n\n   {% for item in functions %}\n   .. autofunction:: {{ item }}\n   {%- endfor %}\n   {% endif %}\n   {% endblock %}\n\n   {% block exceptions %}\n   {% if exceptions %}\n   .. rubric:: {{ _('Exceptions') }}\n\n   .. autosummary::\n   {% for item in exceptions %}\n      {{ item }}\n   {%- endfor %}\n   {% endif %}\n   {% endblock %}\n\n{% block modules %}\n{% if modules %}\n.. rubric:: Modules\n\n.. autosummary::\n   :toctree:\n   :recursive:\n{% for item in modules %}\n   {{ item }}\n{%- endfor %}\n{% endif %}\n{% endblock %}\n"
  },
  {
    "path": "docs/source/_templates/logo-text.html",
    "content": "<img src=\"{{ pathto('_static/manim-logo-sidebar.svg', 1) }}\" alt=\"ManimCommunity logo\" width=\"100%\">\n<a href=\"{{ homepage() }}\" class=\"text-logo\">{{ theme_project_nav_name or shorttitle }}</a>\n"
  },
  {
    "path": "docs/source/changelog/0.1.0-changelog.rst",
    "content": "******\nv0.1.0\n******\n\n:Date: October 21, 2020\n\nThis is the first release of manimce after forking from 3b1b/manim.  As such,\ndevelopers have focused on cleaning up and refactoring the codebase while still\nmaintaining backwards compatibility wherever possible.\n\n\nNew Features\n============\n\nCommand line\n------------\n\n#. Output of 'manim --help' has been improved\n#. Implement logging with the :code:`rich` library and a :code:`logger` object instead of plain ol' prints\n#. Added a flag :code:`--dry_run`, which doesn't write any media\n#. Allow for running manim with :code:`python3 -m manim`\n#. Refactored Tex Template management. You can now use custom templates with command line args using :code:`--tex_template`!\n#. Re-add :code:`--save_frames` flag, which will save each frame as a png\n#. Re-introduce manim feature that allows you to type manim code in :code:`stdin` if you pass a minus sign :code:`(-)` as filename\n#. Added the :code:`--custom_folders` flag which yields a simpler output folder structure\n#. Re-implement GIF export with the :code:`-i` flag (using this flag outputs ONLY a .gif file, and no .mp4 file)\n#. Added a :code:`--verbose` flag\n#. You can save the logs to a file by using :code:`--log_to_file`\n#. Read :code:`tex_template` from config file if not specified by :code:`--tex_template`.\n#. Add experimental javascript rendering with :code:`--use_js_renderer`\n#. Add :code:`-q/--quality [k|p|h|m|l]` flag and removed :code:`-m/-l` flags.\n#. Removed :code:`--sound` flag\n\n\nConfig system\n-------------\n\n#. Implement a :code:`manim.cfg` config file system, that consolidates the global configuration, the command line argument parsing, and some of the constants defined in :code:`constants.py`\n#. Added utilities for manipulating Manim’s :code:`.cfg` files.\n#. Added a subcommand structure for easier use of utilities managing :code:`.cfg` files\n#. Also some variables have been moved from ``constants.py`` to the new config system:\n\n    #. ``FRAME_HEIGHT`` to ``config[\"frame_width\"]``\n    #. ``TOP`` to ``config[\"frame_height\"] / 2 * UP``\n    #. ``BOTTOM`` to ``config[\"frame_height\"] / 2 * DOWN``\n    #. ``LEFT_SIDE`` to ``config[\"frame_width\"] / 2 * LEFT``\n    #. ``RIGHT_SIDE`` to ``config[\"frame_width\"] / 2 * RIGHT``\n    #. ``self.camera.frame_rate`` to ``config[\"frame_rate\"]``\n\n\n\n\nMobjects, Scenes, and Animations\n--------------------------------\n\n#. Add customizable left and right bracket for :code:`Matrix` mobject and :code:`set_row_colors` method for matrix mobject\n#. Add :code:`AddTeXLetterByLetter` animation\n#. Enhanced GraphScene\n\n    #. You can now add arrow tips to axes\n    #. extend axes a bit at the start and/or end\n    #. have invisible axes\n    #. highlight the area between two curves\n#. ThreeDScene now supports 3dillusion_camera_rotation\n#. Add :code:`z_index` for manipulating depth of Objects on scene.\n#. Add a :code:`VDict` class: a :code:`VDict` is to a :code:`VGroup` what a :code:`dict` is to a :code:`list`\n#. Added Scene-caching feature. Now, if a partial movie file is unchanged in your code, it isn’t rendered again! [HIGHLY UNSTABLE We're working on it ;)]\n#. Most :code:`get_` and :code:`set_` methods have been removed in favor of instance attributes and properties\n#. The :code:`Container` class has been made into an AbstractBaseClass, i.e. in cannot be instantiated.  Instead, use one of its children classes\n#. The ``TextMobject`` and ``TexMobject`` objects have been deprecated, due to their confusing names, in favour of ``Tex`` and ``MathTex``. You can still, however, continue to use ``TextMobject`` and ``TexMobject``, albeit with Deprecation Warnings constantly reminding you to switch.\n#. Add a :code:`Variable` class for displaying text that continuously updates to reflect the value of a python variable.\n#. The ``Tex`` and ``MathTex`` objects allow you to specify a custom TexTemplate using the ``template`` keyword argument.\n#. :code:`VGroup` now supports printing the class names of contained mobjects and :code:`VDict` supports printing the internal dict of mobjects\n#. Add all the standard easing functions\n#. :code:`Scene` now renders when :code:`Scene.render()` is called rather than upon instantiation.\n#. :code:`ValueTracker` now supports increment using the `+=` operator (in addition to the already existing `increment_value` method)\n#. Add :class:`PangoText` for rendering texts using Pango.\n\n\nDocumentation\n=============\n\n#. Added clearer installation instructions, tutorials, examples, and API reference [WIP]\n\n\nFixes\n=====\n\n#. Initialization of directories has been moved to :code:`config.py`, and a bunch of bugs associated to file structure generation have been fixed\n#. Nonfunctional file :code:`media_dir.txt` has been removed\n#. Nonfunctional :code:`if` statements in :code:`scene_file_writer.py` have been removed\n#. Fix a bug where trying to render the example scenes without specifying the scene would show all scene objects in the library\n#. Many :code:`Exceptions` have been replaced for more specific exception subclasses\n#. Fixed a couple of subtle bugs in :code:`ArcBetweenPoints`\n\n\nOf interest to developers\n=========================\n\n#. Python code formatting is now enforced by using the :code:`black` tool\n#. PRs now require two approving code reviews from community devs before they can be merged\n#. Added tests to ensure stuff doesn't break between commits (For developers) [Uses Github CI, and Pytest]\n#. Add contribution guidelines (for developers)\n#. Added autogenerated documentation with sphinx and autodoc/autosummary [WIP]\n#. Made manim internally use relative imports\n#. Since the introduction of the :code:`TexTemplate` class, the files :code:`tex_template.tex` and :code:`ctex_template.tex` have been removed\n#. Added logging tests tools.\n#. Added ability to save logs in json\n#. Move to Poetry.\n#. Colors have moved to an Enum\n\nOther Changes\n=============\n\n#. Cleanup 3b1b Specific Files\n#. Rename package from manimlib to manim\n#. Move all imports to :code:`__init__`, so :code:`from manim import *` replaces :code:`from manimlib.imports import *`\n#. Global dir variable handling has been removed. Instead :code:`initialize_directories`, if needed, overrides the values from the cfg files at runtime.\n"
  },
  {
    "path": "docs/source/changelog/0.1.1-changelog.rst",
    "content": "******\nv0.1.1\n******\n\n:Date: December 1, 2020\n\nChanges since Manim Community release v0.1.0\n\nPlugins\n=======\n\n#. Provided a standardized method for plugin discoverability, creation,\n   installation, and usage. See the :ref:`documentation <plugins>`.\n\nFixes\n=====\n\n#. JsRender is optional to install. (via :pr:`697`).\n#. Allow importing modules from the same directory as the input\n   file when using ``manim`` from the command line (via :pr:`724`).\n#. Remove some unnecessary or unpythonic methods from :class:`~.Scene`\n   (``get_mobjects``, ``add_mobjects_among``, ``get_mobject_copies``),\n   via :pr:`758`.\n#. Fix formatting of :class:`~.Code` (via :pr:`798`).\n\nConfiguration\n=============\n\n#. Removed the ``skip_animations`` config option and added the\n   ``Renderer.skip_animations`` attribute instead (via :pr:`696`).\n#. The global ``config`` dict has been replaced by a global ``config`` instance\n   of the new class :class:`~.ManimConfig`.  This class has a dict-like API, so\n   this should not break user code, only make it more robust.  See the\n   Configuration tutorial for details.\n#. Added the option to configure a directory for external assets (via :pr:`649`).\n\n\nDocumentation\n=============\n\n#. Add ``:issue:`` and ``:pr:`` directives for simplifying linking to issues and\n   pull requests on GitHub (via :pr:`685`).\n#. Add a ``skip-manim`` tag for skipping the ``.. manim::`` directive when\n   building the documentation locally (via :pr:`796`).\n\n\nMobjects, Scenes, and Animations\n================================\n\n#. The ``alignment`` attribute to Tex and MathTex has been removed in favour of ``tex_environment``.\n#. :class:`~.Text` now uses Pango for rendering. ``PangoText`` has been removed. The old implementation is still available as a fallback as :class:`~.CairoText`.\n#. Variations of :class:`~.Dot` have been added as :class:`~.AnnotationDot`\n   (a bigger dot with bolder stroke) and :class:`~.LabeledDot` (a dot containing a\n   label).\n#. Scene.set_variables_as_attrs has been removed (via :pr:`692`).\n#. Ensure that the axes for graphs (:class:`GraphScene`) always intersect (:pr:`580`).\n#. Now Mobject.add_updater does not call the newly-added updater by default\n   (use ``call_updater=True`` instead) (via :pr:`710`)\n#. VMobject now has methods to determine and change the direction of the points (via :pr:`647`).\n#. Added BraceBetweenPoints (via :pr:`693`).\n#. Added ArcPolygon and ArcPolygonFromArcs (via :pr:`707`).\n#. Added Cutout (via :pr:`760`).\n#. Added Mobject raise not implemented errors for dunder methods and implementations for VGroup dunder methods (via :pr:`790`).\n#. Added :class:`~.ManimBanner` for a animated version of our logo and banner (via :pr:`729`)\n#. The background color of a scene can now be changed reliably by setting, e.g.,\n   ``self.camera.background_color = RED`` (via :pr:`716`).\n"
  },
  {
    "path": "docs/source/changelog/0.10.0-changelog.rst",
    "content": "*******\nv0.10.0\n*******\n\n:Date: September 01, 2021\n\nContributors\n============\n\nA total of 40 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Animfysyk +\n* Benjamin Hackl\n* Christian Clauss\n* Daniel Adelodun +\n* Darigov Research\n* Darylgolden\n* Eric Biedert +\n* Harivinay\n* Jan-Hendrik Müller\n* Jephian Lin +\n* Joy Bhalla +\n* Laith Bahodi\n* Lalourche +\n* Max Stoumen\n* Naveen M K\n* Oliver\n* Partha Das +\n* Raj Dandekar +\n* Rohan Sharma +\n* Ryan McCauley\n* Václav Hlaváč +\n* asjadaugust +\n* ccn\n* icedcoffeeee\n* sparshg\n* vinnniii15 +\n* vladislav doster +\n* xia0long +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Aathish Sivasubrahmanian\n* Benjamin Hackl\n* Darylgolden\n* Devin Neal\n* Eric Biedert\n* GameDungeon\n* Harivinay\n* Hugues Devimeux\n* Jan-Hendrik Müller\n* Jason Villanueva\n* Jephian Lin\n* Joy Bhalla\n* KingWampy\n* Laith Bahodi\n* Naveen M K\n* Oliver\n* Raghav Goel\n* Raj Dandekar\n* Ryan McCauley\n* ccn\n* icedcoffeeee\n* ralphieraccoon\n* sparshg\n\nPull requests merged\n====================\n\nA total of 59 pull requests were merged for this release.\n\nBreaking changes\n----------------\n\n* :pr:`1843`: Dropped redundant OpenGL files and add metaclass support for :class:`~.Surface`\n   - ``OpenGL<x>`` classes from ``opengl_geometry.py``, ``opengl_text_mobject.py``, ``opengl_tex_mobject.py``, ``opengl_svg_path.py``, ``opengl_svg_mobject.py`` and most of ``opengl_three_dimensions.py`` have been removed.\n   - ``ParametricSurface`` has been renamed to :class:`~.Surface`\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`1941`: Added examples, tests and improved documentation for :mod:`~.coordinate_systems`\n\n\n* :pr:`1694`: Added ``font_size`` parameter for :class:`~.Tex` and :class:`~.Text`, replaced ``scale`` parameters with ``font_size``\n\n\n* :pr:`1860`: Removed :class:`~.GraphScene`, :class:`~.NumberLineOld` and parameters for :class:`~.ChangingDecimal`\n\n\nNew features\n------------\n\n* :pr:`1929`: Implementing a ``zoom`` parameter for :meth:`.ThreeDScene.move_camera`\n   Zooming into a :class:`~.ThreeDScene` can now be done by calling, for example, ``self.move_camera(zoom=2)`` in the ``construct`` method.\n\n* :pr:`1980`: Added a ``dissipating_time`` keyword argument to :class:`~.TracedPath` to allow animating a dissipating path\n\n\n* :pr:`1899`: Allow switching the renderer to OpenGL at runtime\n   Previously, the metaclass approach only changed the inheritance chain to switch between OpenGL and cairo mobjects when the class objects are initialized, i.e., at import time. This PR also triggers the changes to the inheritance chain when the value of ``config.renderer`` is changed.\n\n* :pr:`1828`: Added configuration option ``zero_pad`` for zero padding PNG file names\n\n\nEnhancements\n------------\n\n* :pr:`1882`: Added OpenGL support for :class:`~.PMobject` and its subclasses\n\n\n* :pr:`1881`: Added methods :meth:`.Angle.get_lines` and :meth:`.Angle.get_value` to :class:`~.Angle`\n\n\n* :pr:`1952`: Added the option to save last frame for OpenGL\n\n\n* :pr:`1922`: Fixed IPython interface to exit cleanly when OpenGL renderer raises an error\n\n\n* :pr:`1923`: Fixed CLI help text for ``manim init`` subcommand so that it is not truncated\n\n\n* :pr:`1868`: Added OpenGL support to IPython magic\n   The OpenGL renderer can now be used in jupyter notebooks when using the ``%%manim`` magic command.\n\n* :pr:`1841`: Reduced default resolution of :class:`~.Dot3D`\n\n\n* :pr:`1866`: Allow passing keyword argument ``corner_radius`` to :class:`~.SurroundingRectangle`\n\n\n* :pr:`1847`: Allow :class:`~.Cross` to be created without requiring a mobject\n\n\nFixed bugs\n----------\n\n* :pr:`1985`: Use ``height`` to determine ``font_size`` instead of the ``_font_size`` attribute\n\n\n* :pr:`1758`: Fixed scene selection being ignored when using the OpenGL renderer\n\n\n* :pr:`1871`: Fixed broken :meth:`.VectorScene.vector_to_coords`\n\n\n* :pr:`1973`: Fixed indexing of :meth:`.Table.get_entries` to respect row length\n\n\n* :pr:`1950`: Fixed passing custom arrow shapes to :class:`~.CurvedArrow`\n\n\n* :pr:`1967`: Fixed :attr:`.Axes.coordinate_labels` referring to the entire axis, not just its labels\n\n\n* :pr:`1951`: Fixed :meth:`.Axes.get_line_graph` returning a graph rendered below the axes\n\n\n* :pr:`1943`: Added ``buff`` keyword argument to :class:`~.BraceLabel`\n\n\n* :pr:`1938`: Fixed :class:`~.Rotate` for angles that are multiples of :math:`2\\pi`\n\n\n* :pr:`1924`: Made arrow tips rotate ``IN`` and ``OUT`` properly\n\n\n* :pr:`1931`: Fixed ``row_heights`` in :meth:`.Mobject.arrange_in_grid`\n\n\n* :pr:`1893`: Fixed CLI error when rendering a file containing a single scene without specifying the scene name\n\n\n* :pr:`1744`: Fixed bug in :class:`~.NumberPlane` with strictly positive or strictly negative values for ``x_range`` and ``y_range``\n\n\n* :pr:`1887`: Fixed ``custom_config`` not working in ``frames_comparison``\n\n\n* :pr:`1879`: Fixed how the installed version is determined by Poetry\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`1979`: Corrected Japanese phrases in documentation\n\n\n* :pr:`1976`: Fixed labelling of languages in documentation example\n\n\n* :pr:`1949`: Rewrite installation instructions from scratch\n\n\n* :pr:`1963`: Added sitemap to ``robots.txt``\n\n\n* :pr:`1939`: Fixed formatting of parameter description of :class:`~.NumberPlane`\n\n\n* :pr:`1918`: Fixed a typo in the text tutorial\n\n\n* :pr:`1915`: Improved the wording of the installation instructions for Google Colab\n\n\n* :pr:`1906`: Improved language and overall consistency in ``README``\n\n\n* :pr:`1880`: Updated tutorials to use ``.animate`` instead of :class:`~.ApplyMethod`\n\n\n* :pr:`1877`: Remove duplicated imports in some documentation examples\n\n\n* :pr:`1869`: Fixed duplicated Parameters section in  :meth:`.Mobject.arrange_in_grid`\n\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`1894`: Fixed an OpenGL test\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`1987`: Added support for using OpenGL in subprocess in Windows pipeline\n\n\n* :pr:`1964`: Added ``CITATION.cff`` and a method to automatically update this citation with new releases\n\n\n* :pr:`1856`: Modified Dockerfile to support multi-platform builds via ``docker buildx``\n\n\n* :pr:`1955`: Partially support OpenGL rendering with Docker\n\n\n* :pr:`1896`: Made RTD apt install FFMPEG instead of installing a Python binding\n\n\n* :pr:`1864`: Shortened and simplified PR template\n\n\n* :pr:`1853`: Updated Sphinx to 4.1.2\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`1960`: Ignore fewer flake8 errors\n\n\n* :pr:`1947`: Set flake8 not to ignore undefined names in Python code\n\n\n* :pr:`1948`: flake8: Set max-line-length instead of ignoring long lines\n\n\n* :pr:`1956`:  Upgrade to modern Python syntax\n   - This pull request was created `with the command <https://github.com/asottile/pyupgrade#readme>`__ ``pyupgrade --py36-plus **/*.py``\n   - Python f-strings simplify the code and `should speed up execution <https://www.scivision.dev/python-f-string-speed>`__.\n\n* :pr:`1898`: Replaced ``self.data[\"attr\"]`` and ``self.uniforms[\"attr\"]`` with ``self.attr``\n   In particular, ``OpenGLVMobject.points`` can now be accessed directly.\n\n* :pr:`1934`: Improved code quality by implementing suggestions from LGTM\n\n\n* :pr:`1861`: Updated ``dearpygui`` version to 0.8.x\n\n\nNew releases\n------------\n\n* :pr:`1989`: Prepare new release v0.10.0\n"
  },
  {
    "path": "docs/source/changelog/0.11.0-changelog.rst",
    "content": "*******\nv0.11.0\n*******\n\n:Date: October 02, 2021\n\nContributors\n============\n\nA total of 31 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Aathish Sivasubrahmanian\n* Benjamin Hackl\n* Charlie +\n* Christopher Besch +\n* Darylgolden\n* Evan Boehs +\n* GameDungeon\n* Hugues Devimeux\n* Jerónimo Squartini\n* Laith Bahodi\n* Meredith Espinosa +\n* Mysaa\n* Naveen M K\n* Nicolai Weitkemper +\n* Oliver\n* Ryan McCauley\n* Tim +\n* icedcoffeeee\n* imadjamil +\n* leleogere +\n* Максим Заякин +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Aathish Sivasubrahmanian\n* Benjamin Hackl\n* Charlie\n* Darylgolden\n* Evan Boehs\n* GameDungeon\n* Hugues Devimeux\n* Jan-Hendrik Müller\n* Jason Villanueva\n* Laith Bahodi\n* Mark Miller\n* Mysaa\n* Naveen M K\n* Nicolai Weitkemper\n* Oliver\n* Raghav Goel\n* Ryan McCauley\n* Skaft\n* friedkeenan\n* icedcoffeeee\n* leleogere\n\nPull requests merged\n====================\n\nA total of 55 pull requests were merged for this release.\n\nBreaking changes\n----------------\n\n* :pr:`1990`: Changed and improved the implementation of :meth:`.CoordinateSystem.get_area` to work without Riemann rectangles\n   This changes how :meth:`.CoordinateSystem.get_area` is implemented. To mimic the old behavior (tiny Riemann rectangles), use :meth:`.CoordinateSystem.get_riemann_rectangles` with a small value for ``dx``.\n\n* :pr:`2095`: Changed angles for polar coordinates to use math convention\n   This PR switches the parameter names ``phi`` and ``theta`` in :func:`cartesian_to_spherical` and :func:`spherical_to_cartesian` to align with the `usual definition in mathematics <https://user-images.githubusercontent.com/83535735/131709630-87290522-7747-4b21-9411-dd3d35ebaf0f.png>`__.\n\nHighlights\n----------\n\n* :pr:`2094`: Implemented :class:`~.ImplicitFunction` and :meth:`.CoordinateSystem.get_implicit_curve` for plotting implicit curves\n   An :class:`~.ImplicitFunction` that plots the points :math:`(x, y)` which satisfy some equation :math:`f(x,y) = 0`.\n\n* :pr:`2075`: Implemented :meth:`.Mobject.set_default`, a mechanism for changing default values of keyword arguments\n\n\n* :pr:`1998`: Added support for Boolean Operations on VMobjects\n   This PR introduces boolean operations for :class:`~.VMobject`; see details and examples at\n   :class:`~.Union`, :class:`~.Difference`, :class:`~.Intersection` and :class:`~.Exclusion`.\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`2123`: Renamed ``distance`` parameter of :class:`.ThreeDScene` and :class:`.ThreeDCamera` to ``focal_distance``\n\n\n* :pr:`2102`: Deprecated :class:`~.SampleSpaceScene` and :class:`~.ReconfigurableScene`\n\n\n* :pr:`2061`: Removed deprecated ``u_min``, ``u_max``, ``v_min``, ``v_max`` in :class:`~.Surface`\n\n\n* :pr:`2024`: Deprecated redundant methods :meth:`.Mobject.rotate_in_place`, :meth:`.Mobject.scale_in_place`, :meth:`.Mobject.scale_about_point`\n\n\n* :pr:`1991`: Deprecated :meth:`.VMobject.get_points`\n\n\nNew features\n------------\n\n* :pr:`2118`: Added 3D support for :class:`~.ArrowVectorField` and :class:`~.StreamLines`\n\n\n* :pr:`1469`: Added :meth:`.VMobject.proportion_from_point` to measure the proportion of points along a Bezier curve\n\n\nEnhancements\n------------\n\n* :pr:`2111`: Improved setting of OpenGL colors\n\n\n* :pr:`2113`: Added OpenGL compatibility to :meth:`.ThreeDScene.begin_ambient_camera_rotation` and :meth:`.ThreeDScene.move_camera`\n\n\n* :pr:`2016`: Added OpenGL support for :mod:`~.mobject.boolean_ops`\n\n\n* :pr:`2084`: Added :meth:`~Table.get_highlighted_cell` and fixed :meth:`~Table.add_highlighted_cell`\n\n\n* :pr:`2013`: Removed unnecessary check in :class:`~.TransformMatchingAbstractBase`\n\n\n* :pr:`1971`: Added OpenGL support for :class:`~.StreamLines`\n\n\n* :pr:`2041`: Added config option to enable OpenGL wireframe for debugging\n\n\nFixed bugs\n----------\n\n* :pr:`2070`: Fixed :meth:`~OpenGLRenderer.get_frame` when window is created\n\n\n* :pr:`2071`: Fixed :class:`~AnimationGroup` OpenGL compatibility\n\n\n* :pr:`2108`: Fixed swapped axis step values in :class:`~.NumberPlane`\n\n\n* :pr:`2072`: Added OpenGL compatibility for :class:`~.Cube`.\n\n\n* :pr:`2060`: Fixed OpenGL compatibility issue for meth:`~Line.set_opacity`\n\n\n* :pr:`2037`: Fixed return value of :meth:`~.OpenGLMobject.apply_complex_function`\n\n\n* :pr:`2039`: Added OpenGL compatibility for :meth:`~Cylinder.add_bases`.\n\n\n* :pr:`2066`: Fixed error raised by logging when cache is full\n\n\n* :pr:`2026`: Fixed OpenGL shift animation for :class:`~.Text`\n\n\n* :pr:`2028`: Fixed OpenGL overriding SVG fill color\n\n\n* :pr:`2043`: Fixed bug where :meth:`.NumberLine.add_labels`  cannot accept non-mobject labels\n\n\n* :pr:`2011`: Fixed ``-a`` flag for OpenGL rendering\n\n\n* :pr:`1994`: Fix :meth:`~.input_to_graph_point` when passing a line graph (from :meth:`.Axes.get_line_graph`)\n\n\n* :pr:`2017`: Avoided using deprecated ``get_points`` method and fixed :class:`~.OpenGLPMPoint` color\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`2131`: Copyedited the configuration tutorial in the documentation\n\n\n* :pr:`2120`: Changed ``manim_directive`` to use a clean configuration via ``tempconfig``\n\n\n* :pr:`2122`: Fixed broken links in inheritance graphs by moving them to ``reference.rst``\n\n\n* :pr:`2115`: Improved docstring of :meth:`.PMobject.add_points`\n\n\n* :pr:`2116`: Made type hint for ``line_spacing`` argument of :class:`~.Paragraph` more accurate\n\n\n* :pr:`2117`: Changed the way the background color was set in a documentation example to avoid leaking the setting to other examples\n\n\n* :pr:`2101`: Added note that translation process is not ready\n\n\n* :pr:`2055`: Fixed parameter types of :meth:`.Graph.add_edges` and :meth:`.Graph.add_vertices`\n\n\n* :pr:`862`: Prepared documentation for translation (still work in progress)\n\n\n* :pr:`2035`: Fixed broken link in README\n\n\n* :pr:`2020`:  Corrected paths to user-wide configuration files for MacOS and Linux\n\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`2008`: Reuse CLI flag tests for OpenGL\n\n\n* :pr:`2080`: Reused :class:`~.Mobject` tests for :class:`~.OpenGLMobject`\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`2004`: Cancel previous workflows in the same branch in Github Actions\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`2050`: Make colour aliases IDE-friendly\n\n\n* :pr:`2126`: Fixed whitespace in info message issued by :meth:`.SceneFileWriter.clean_cache`\n\n\n* :pr:`2124`: Upgraded several dependencies (in particular: ``skia-pathops``)\n\n\n* :pr:`2001`: Fixed several warnings issued by LGTM\n\n\n* :pr:`2064`: Removed duplicate insert shader directory\n\n\n* :pr:`2027`: Improved wording in info message issued by :meth:`.SceneFileWriter.clean_cache`\n\n\n* :pr:`1968`: Sharpened Flake8 configuration and fixed resulting warnings\n\n\nNew releases\n------------\n\n* :pr:`2114`: Prepared new release, ``v0.11.0``\n"
  },
  {
    "path": "docs/source/changelog/0.12.0-changelog.rst",
    "content": "*******\nv0.12.0\n*******\n\n:Date: November 02, 2021\n\nContributors\n============\n\nA total of 40 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Anima. +\n* Arcstur +\n* Benjamin Hackl\n* Christopher Besch\n* Darylgolden\n* David Yang +\n* Dhananjay Goratela +\n* Ethan Rooke +\n* Eugene Chung +\n* GameDungeon\n* Gustav-Rixon +\n* Jan-Hendrik Müller\n* Josiah Winslow +\n* Laith Bahodi\n* Martmists +\n* Michael Hill +\n* Naveen M K\n* Nick +\n* NotWearingPants +\n* Peeter Joot +\n* Ryan McCauley\n* Viicos +\n* heitor +\n* icedcoffeeee\n* kieran-pringle +\n* Виктор Виктор +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Alex Lembcke\n* Anima.\n* Benjamin Hackl\n* Christopher Besch\n* Darylgolden\n* David Yang\n* Dhananjay Goratela\n* Ethan Rooke\n* Eugene Chung\n* Gustav-Rixon\n* Hugues Devimeux\n* Jan-Hendrik Müller\n* Jason Villanueva\n* Laith Bahodi\n* Mysaa\n* Naveen M K\n* Nick\n* Oliver\n* Ryan McCauley\n* Viicos\n* icedcoffeeee\n* kieran-pringle\n\nPull requests merged\n====================\n\nA total of 52 pull requests were merged for this release.\n\nHighlights\n----------\n\n* :pr:`1812`: Implemented logarithmic scaling for :class:`~.NumberLine` / :class:`~.Axes`\n   This implements scaling bases that can be passed to the ``scaling`` keyword\n   argument of :class:`.NumberLine`. See :class:`.LogBase` (for a logarithmic scale) and\n   :class:`.LinearBase` (for the default scale) for more details and examples.\n\n* :pr:`2152`: Introduced API for scene sections via :meth:`.Scene.next_section`\n   Sections divide a scene into multiple parts, resulting in multiple output videos (when using the ``--save_sections`` flag).\n   The cuts between two sections are defined by the user in the :meth:`~.Scene.construct` method.\n   Each section has an optional name and type, which can be used by a plugin (`see an example <https://github.com/ManimEditorProject/manim_editor>`__).\n   You can skip rendering specific sections with the ``skip_animations`` keyword argument.\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`1926`: OpenGL: changed ``submobjects`` to be a property\n\n\n* :pr:`2245`: Removed deprecated method ``get_center_point`` and parameters ``azimuth_label_scale``, ``number_scale_value``, ``label_scale``, ``scale_factor``, ``size``, ``x_min``, ``x_max``, ``delta_x``, ``y_min``, ``y_max``, ``delta_y``\n\n\n* :pr:`2187`: Renamed ``get_graph`` and its variants to :meth:`~.CoordinateSystem.plot`\n\n\n* :pr:`2065`: Deprecated :class:`~.FullScreenFadeRectangle` and :class:`~.PictureInPictureFrame`\n\n\nNew features\n------------\n\n* :pr:`2025`: Implemented :meth:`.CoordinateSystem.input_to_graph_coords` and fixed :meth:`.CoordinateSystem.angle_of_tangent`\n\n\n* :pr:`2151`: Added option to set the input file from a config file\n\n\n* :pr:`2128`: Added keyword arguments ``match_center``, ``match_width`` etc. to :meth:`.Mobject.become`\n\n\n* :pr:`2162`: Implemented :meth:`.MovingCamera.auto_zoom` for automatically zooming onto specified mobjects\n\n\n* :pr:`2236`: Added ``skip_animations`` argument to :meth:`.Scene.next_section`\n\n\n* :pr:`2196`: Implemented :meth:`.Line3D.parallel_to` and :meth:`.Line3D.perpendicular_to`\n\n\nEnhancements\n------------\n\n* :pr:`2138`: Fixed example for :meth:`~.Vector.coordinate_label` and added more customization for :class:`~.Matrix`\n   - Additional keyword arguments for :meth:`~.Vector.coordinate_label` are passed to the constructed matrix.\n   - :class:`~.Matrix` now accepts a ``bracket_config`` keyword argument.\n\n* :pr:`2139`: Changed the color of :class:`~.NumberLine` from ``LIGHT_GREY`` to ``WHITE``\n\n\n* :pr:`2157`: Added :meth:`.CoordinateSystem.plot_polar_graph`\n\n\n* :pr:`2243`: Fixed wasteful recursion in :meth:`.Mobject.get_merged_array`\n\n\n* :pr:`2205`: Improved last frame output handling for the OpenGL renderer\n\n\n* :pr:`2172`: Added ``should_render`` attribute to disable rendering mobjects\n\n\n* :pr:`2182`: Changed the default width of videos in Jupyter notebooks to 60%\n\n\nFixed bugs\n----------\n\n* :pr:`2244`: Fixed :meth:`.CoordinateSystem.get_area` when using few plot points and a boundary graph\n\n\n* :pr:`2232`: Fixed :class:`.Graph` stopping to update after animating additions/deletions of vertices or edges\n\n\n* :pr:`2142`: Fixed issue with duplicates in OpenGL family and added tests\n\n\n* :pr:`2168`: Fixed order of return values of :func:`.space_ops.cartesian_to_spherical`\n\n\n* :pr:`2160`: Made projection shaders compatible with :class:`.StreamLines`\n\n\n* :pr:`2140`: Fixed passing color lists to :meth:`.Mobject.set_color` for the OpenGL renderer\n\n\n* :pr:`2211`: Fixed animations not respecting the specified rate function\n\n\n* :pr:`2161`: Fixed ``IndexOutOfBoundsError`` in TeX logging\n\n\n* :pr:`2148`: Fixed :class:`~.Arrow` tip disorientation with :meth:`.Line.put_start_and_end_on`\n\n\n* :pr:`2192`: Fixed :func:`.svg_path.string_to_numbers` sometimes returning strings\n\n\n* :pr:`2185`: Fixed type mismatch for height and width parameters of :class:`~.Text`\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`2228`: Added a new boolean operation example to the gallery\n\n\n* :pr:`2239`: Removed erroneous raw string from text tutorial\n\n\n* :pr:`2184`: Moved comments in :class:`~.VMobject` to documentation\n\n\n* :pr:`2217`: Removed superfluous dots in documentation of :class:`.Section`\n\n\n* :pr:`2215`: Fixed typo in docstring of :meth:`.ThreeDAxes.get_z_axis_label`\n\n\n* :pr:`2212`: Fixed Documentation for Sections\n\n\n* :pr:`2201`: Fixed a typo in the documentation\n\n\n* :pr:`2165`: Added Crowdin configuration and changed source files to ``.pot`` format\n\n\n* :pr:`2130`:  Transferred troubleshooting installation related snippets from Discord to the documentation\n\n\n* :pr:`2176`: Modified :meth:`.Mobject.set_default` example to prevent leaking across the docs\n\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`2197`: Added tests for resolution flag\n\n\n* :pr:`2146`: Increased test coverage for OpenGL renderer\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`2191`: Removed ``add-trailing-comma`` pre-commit hook\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`2136`: Added type hints to all colors\n\n\n* :pr:`2220`: Cleanup: let ``Scene.renderer.time`` return something that makes sense\n\n\n* :pr:`2222`: Updated Classifiers in ``pyproject.toml``: removed Python 3.6, added Python 3.9\n\n\n* :pr:`2213`: Removed redundant ``partial_movie_files`` parameter in :meth:`.SceneFileWriter.combine_to_movie`\n\n\n* :pr:`2200`: Addressed some maintenance TODOs\n   - Changed an `Exception` to `ValueError`\n   - Fixed :meth:`.MappingCamera.points_to_pixel_coords` by adding the ``mobject`` argument of the parent\n   - Rounded up width in :class:`.SplitScreenCamera`\n   - Added docstring to :meth:`.Camera.capture_mobject`\n\n* :pr:`2194`: Added type hints to :mod:`.utils.images`\n\n\n* :pr:`2171`: Added type hints to :mod:`.utils.ipython_magic`\n\n\n* :pr:`2164`: Improved readability of regular expression\n\n\nNew releases\n------------\n\n* :pr:`2247`: Prepared new release ``v0.12.0``\n"
  },
  {
    "path": "docs/source/changelog/0.13.0-changelog.rst",
    "content": "*******\nv0.13.0\n*******\n\n:Date: December 04, 2021\n\nContributors\n============\n\nA total of 27 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Alex Lembcke\n* Benjamin Hackl\n* Christopher Besch\n* Darylgolden\n* Filip +\n* John Ingles +\n* Laith Bahodi\n* Lucas Ricci +\n* Marcin Serwin +\n* Mysaa\n* Naveen M K\n* Ricky +\n* Viicos\n* ask09ok +\n* citrusmunch +\n* icedcoffeeee\n* mostlyaman +\n* vmiezys +\n* zhujisheng +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Alex Lembcke\n* Benjamin Hackl\n* Christopher Besch\n* Darylgolden\n* Filip\n* Hugues Devimeux\n* Jan-Hendrik Müller\n* Laith Bahodi\n* Lucas Ricci\n* Naveen M K\n* Oliver\n* Ryan McCauley\n* Viicos\n* ask09ok\n* icedcoffeeee\n* mostlyaman\n\nPull requests merged\n====================\n\nA total of 39 pull requests were merged for this release.\n\nHighlights\n----------\n\n* :pr:`2313`: Finalized translation process and documentation\n\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`2331`: Removed deprecations up to ``v0.12.0``\n   - Removed ``distance`` parameters from :class:`~.ThreeDCamera` (replacement: ``focal_distance``)\n   - Removed ``min_distance_to_new_point`` parameter from :class:`~.TracedPath`\n   - Removed ``positive_space_ratio`` and ``dash_spacing`` parameters from :class:`~.DashedVMobject`\n   - Removed ``<method>_in_place`` methods from :mod:`.mobject`\n   - Removed ``ReconfigurableScene``\n   - Removed ``SampleSpaceScene``\n\n* :pr:`2312`: Replaced all occurrences of ``set_submobjects``\n\n\nNew features\n------------\n\n* :pr:`2314`: Added basic support for adding subcaptions via :meth:`.Scene.add_subcaption`\n   - New method :meth:`.Scene.add_subcaption`\n   - New keyword arguments ``subcaption``, ``subcaption_duration``, ``subcaption_offset`` for :meth:`.Scene.play`\n\n* :pr:`2267`: Implemented :meth:`.CoordinateSystem.plot_antiderivative_graph`\n\n\nEnhancements\n------------\n\n* :pr:`2347`: Moved ``manim_directive.py`` to ``manim.utils.docbuild``\n\n\n* :pr:`2340`: Added documentation for :mod:`.animation.growing` and improved :class:`.SpinInFromNothing`\n\n\n* :pr:`2343`: Replaced current tree layout algorithm with SageMath's for improved layout of large trees\n\n\n* :pr:`2351`: Added missing ``**kwargs`` parameter to :meth:`.Table.add_highlighted_cell`\n\n\n* :pr:`2344`: Resized SVG logos, fit content to canvas\n\n\nFixed bugs\n----------\n\n* :pr:`2359`: Resolved ``ValueError`` when calling ``manim cfg write``\n\n\n* :pr:`2276`: Fixed bug with alignment of z-axis in :class:`~.ThreeDAxes`\n\n\n* :pr:`2325`: Several improvements to handling of ``quality`` argument\n\n\n* :pr:`2335`: Fixed bug with zooming camera and :class:`~.PointCloud`\n\n\n* :pr:`2328`: Fixed bug causing incorrect RGBA values to be passed to cairo\n\n\n* :pr:`2292`: Fixed positioning of :class:`~.Flash`\n\n\n* :pr:`2262`: Fixed wrong cell coordinates with :meth:`.Table.get_cell` after scaling\n\n\n* :pr:`2280`: Fixed :class:`~.DecimalNumber` color when number of displayed digits changes\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`2354`: Port over docs and typings from ``mobject.py`` and ``vectorized_mobject.py`` to their OpenGL counterparts\n\n\n* :pr:`2350`: Added mention of Manim sideview extension for VS Code\n\n\n* :pr:`2342`: Removed :meth:`~.CoordinateSystem.get_graph` usage from :class:`~.Axes` example\n\n\n* :pr:`2216`: Edited and added new sections to the quickstart tutorial\n\n\n* :pr:`2279`: Added documentation for discontinuous functions\n\n\n* :pr:`2319`: Swapped ``dotL`` and ``dotR`` in :meth:`.Mobject.interpolate` example\n\n\n* :pr:`2230`: Copyedited building blocks tutorial\n\n\n* :pr:`2310`: Clarified that Manim does not support Python 3.10 yet in the documentation\n\n\n* :pr:`2294`: Made documentation front page more concise and rearranged order of tutorials\n\n\n* :pr:`2287`: Replace link to old interactive notebook\n\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`2346`: Made ``frames_comparsion`` decorator for frame testing a proper module of the library\n\n\n* :pr:`2318`: Added tests for ``remover`` keyword argument of :class:`~.AnimationGroup`\n\n\n* :pr:`2301`: Added a test for :meth:`.ThreeDScene.add_fixed_in_frame_mobjects`\n\n\n* :pr:`2274`: Optimized some tests to reduce duration\n\n\n* :pr:`2272`: Added test for :class:`~.Broadcast`\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`2327`: Corrected type hint for ``labels`` keyword argument of :class:`~.Graph`\n\n\n* :pr:`2329`: Remove unintended line break in README\n\n\n* :pr:`2305`: Corrected type hint ``discontinuities`` argument for :class:`~.ParametricFunction`\n\n\n* :pr:`2300`: Add contact email for PyPi\n\n\nNew releases\n------------\n\n* :pr:`2353`: Prepare new release: ``v0.13.0``\n\n\nUnclassified changes\n--------------------\n\n* :pr:`2348`: Updated translation source files\n"
  },
  {
    "path": "docs/source/changelog/0.13.1-changelog.rst",
    "content": "*******\nv0.13.1\n*******\n\n:Date: December 05, 2021\n\nContributors\n============\n\nA total of 2 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Benjamin Hackl\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Laith Bahodi\n\nPull requests merged\n====================\n\nA total of 2 pull requests were merged for this release.\n\nFixed bugs\n----------\n\n* :pr:`2363`: Fixed broken IPython magic command\n\n\nNew releases\n------------\n\n* :pr:`2364`: Prepared bugfix release ``v0.13.1``\n"
  },
  {
    "path": "docs/source/changelog/0.14.0-changelog.rst",
    "content": "*******\nv0.14.0\n*******\n\n:Date: January 07, 2022\n\nContributors\n============\n\nA total of 29 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Benjamin Hackl\n* BorisTheBrave +\n* Darylgolden\n* GameDungeon\n* Gergely Bencsik +\n* Jan-Hendrik Müller\n* Jihoon +\n* Kian Kasad +\n* Kiran-Raj-Dev +\n* Laith Bahodi\n* Leo Xu +\n* Marcin Serwin\n* Matt Gleich +\n* Naveen M K\n* Steven nguyen +\n* Vectozavr +\n* Viicos\n* citrusmunch\n* netwizard22 +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Benjamin Hackl\n* BorisTheBrave\n* Christopher Besch\n* Darylgolden\n* GameDungeon\n* Gergely Bencsik\n* Hugues Devimeux\n* Jan-Hendrik Müller\n* Kiran-Raj-Dev\n* Laith Bahodi\n* Leo Xu\n* Lucas Ricci\n* Marcin Serwin\n* Naveen M K\n* Raghav Goel\n* Ryan McCauley\n* Viicos\n* icedcoffeeee\n\nPull requests merged\n====================\n\nA total of 29 pull requests were merged for this release.\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`2390`: Removed deprecations up to `v0.13.0`\n   - Removed ``get_graph``, ``get_implicit_curve``, ``get_derivative_graph``, ``get_line_graph`` and ``get_parametric_curve`` in favour of their ``plot`` variants\n   - Removed ``FullScreenFadeRectangle`` and ``PictureInPictureFrame``\n   - Removed ``path_arc`` parameter from :class:`~.SpinInFromNothing`\n   - Removed ``set_submobjects`` method from ``opengl_mobject.py``\n\nNew features\n------------\n\n* :pr:`2341`: Update :class:`~.Text` to use new ``ManimPango`` color setting\n   * :class:`~.Text` class now uses color setting introduced in ``ManimPango 0.4.0`` for color and gradient.\n\n* :pr:`2397`: Added ``label_constructor`` parameter for :class:`~.NumberLine`\n   Allows changing the class that will be used to construct :class:`~.Axes` and :class:`~.NumberLine` labels by default. Makes it possible to easily use :class:`~.Text` for labels if needed.\n\nEnhancements\n------------\n\n* :pr:`2383`: Made :meth:`.Surface.set_fill_by_value` support gradients along different axes\n\n\n* :pr:`2388`: Added ``about_point`` keyword argument to :class:`~.ApplyMatrix`\n\n\n* :pr:`2395`: Add documentation for paths functions\n\n\n* :pr:`2372`: Improved :class:`~.DashedVMobject`\n   :class:`~.DashedVMobject` used to create stretched and uneven dashes on most plotted curves. Now the dash lengths are equalized. An option is reserved to use the old method.\n   New keyword argument: ``dash_offset``. This parameter shifts the starting point.\n\nFixed bugs\n----------\n\n* :pr:`2409`: Fixed performance degradation by trimming empty curves from paths when calling :meth:`.VMobject.align_points`\n\n\n* :pr:`2392`: Fixed ``ZeroDivisionError`` in :mod:`~.mobject.three_dimensions`\n\n\n* :pr:`2362`: Fixed phi updater in :meth:`.ThreeDScene.begin_3dillusion_camera_rotation`\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`2415`: Removed instructions on using and installing Docker in README\n\n\n* :pr:`2414`: Made improvements to the :doc:`/guides/configuration` tutorial\n\n\n* :pr:`2423`: Changed recommendation to ``mactex-no-gui`` from ``mactex`` for macOS install\n\n\n* :pr:`2407`: Clarified docstrings of :meth:`.Mobject.animate`, :meth:`.Mobject.set` and :class:`~.Variable`\n\n\n* :pr:`2352`: Added Crowdin badge\n\n\n* :pr:`2371`: Added ``dvips`` to list of required LaTeX packages on Linux\n\n\n* :pr:`2403`: Improved docstring of :class:`~.ApplyMethod` and removed propagated ``__init__`` docstring\n\n\n* :pr:`2391`: Fixed typo in parameter name in documentation of :class:`~.NumberLine`\n\n\n* :pr:`2368`: Added note in Internationalization\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`2408`: Removed various return annotations that were stifling type inference\n\n\n* :pr:`2424`: Removed ``strings.py``\n\n\n* :pr:`1972`: Added support for MyPy\n\n\n* :pr:`2410`: Fixed Flake8\n\n\n* :pr:`2401`: Fixed type annotations in :mod:`.mobject.three_dimensions`\n\n\n* :pr:`2405`: Removed some unused OpenGL files\n\n\n* :pr:`2399`: Fixed type annotations in :mod:`~.mobject.table`\n\n\n* :pr:`2385`: Made comments in quickstart tutorial more precise\n\n\n* :pr:`2377`: Fixed type hint for an argument of :class:`~.MoveAlongPath`\n\n\nNew releases\n------------\n\n* :pr:`2411`: Prepare new release, ``v0.14.0``\n"
  },
  {
    "path": "docs/source/changelog/0.15.0-changelog.rst",
    "content": "*******\nv0.15.0\n*******\n\n:Date: February 26, 2022\n\nContributors\n============\n\nA total of 34 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Alex Lembcke\n* AnonymoZ +\n* Benjamin Hackl\n* Darylgolden\n* Eshaan Naga Venkata +\n* Faruk D. +\n* GameDungeon\n* Kevin Cen +\n* Laith Bahodi\n* Leo Xu\n* Lucas Ricci\n* Marcin Serwin\n* Michael McNeil Forbes +\n* Mysaa\n* Naveen M K\n* Pierre Couy +\n* Simon Ellmann +\n* Tommy Chu +\n* Viicos\n* ad_chaos\n* betafcc +\n* friedkeenan\n* icedcoffeeee\n* vmoros +\n* 鹤翔万里\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Benjamin Hackl\n* Christopher Besch\n* Darylgolden\n* Eshaan Naga Venkata\n* GameDungeon\n* Jan-Hendrik Müller\n* Laith Bahodi\n* Marcin Kurczewski\n* Marcin Serwin\n* Naveen M K\n* Raghav Goel\n* RomainJMend\n* Ryan McCauley\n* Tommy Chu\n* ad_chaos\n* betafcc\n* icedcoffeeee\n\nPull requests merged\n====================\n\nA total of 71 pull requests were merged for this release.\n\nBreaking changes\n----------------\n\n* :pr:`2476`: Improved structure of the :mod:`.mobject` module\n   Arrow tips now have to be imported from ``manim.mobject.geometry.tips`` instead of ``manim.mobject.geometry``.\n\n* :pr:`2387`: Refactored :class:`~.BarChart` and made it inherit from :class:`~.Axes`\n   - :class:`~.BarChart` now inherits from :class:`~.Axes`, allowing it to use :class:`~.Axes`' methods. Also improves :class:`~.BarChart`'s configuration and ease of use.\n   - Added :meth:`~.BarChart.get_bar_labels` to annotate the value of each bar of a :class:`~.BarChart`.\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`2568`: Removed Deprecated Methods\n   Removed methods and classes that were deprecated since v0.10.0 and v0.11.0\n\n* :pr:`2457`: Deprecated :class:`.ShowCreationThenFadeOut`\n\n\nNew features\n------------\n\n* :pr:`2442`: Added ``media_embed`` config option to control whether media in Jupyter notebooks is embedded\n\n\n* :pr:`2504`: Added finer control over :meth:`.Scene.wait` being static (i.e., no updaters) or not\n   - Added keyword argument ``frozen_frame`` to :class:`.Wait` and :meth:`.Scene.wait`\n   - New convenience method: :meth:`.Scene.pause` (alias for ``Scene.wait(frozen_frame=True)``)\n   - Changed default behavior for OpenGL updaters: updater functions are now not called by default when they are added\n   - Changed default behavior of :meth:`.Scene.should_mobjects_update`: made it respect the set value of ``Wait.frozen_frame``, changed automatic determination of frozen frame state to also consider Scene updaters\n\nEnhancements\n------------\n\n* :pr:`2478`: Alternative scaling for tree graph layout\n\n\n* :pr:`2565`: Allowed passing vertex configuration keyword arguments to :meth:`.Graph.add_edges`\n\n\n* :pr:`2467`: :class:`~.MathTex`, :class:`~.Tex`, :class:`~.Text` and :class:`~.MarkupText` inherit color from their parent mobjects\n\n\n* :pr:`2537`: Added support for PySide coordinate system\n\n\n* :pr:`2158`: Added OpenGL compatibility to :meth:`.ThreeDScene.add_fixed_orientation_mobjects` and  :meth:`.ThreeDScene.add_fixed_in_frame_mobjects`\n\n\n* :pr:`2535`: Implemented performance enhancement for :meth:`.VMobject.insert_n_curves_to_point_list`\n\n\n* :pr:`2516`: Cached view matrix for :class:`~.OpenGLCamera`\n\n\n* :pr:`2508`: Improve performance for :meth:`.Mobject.become`\n\n\n* :pr:`2332`: Changed ``color``, ``stroke_color`` and ``fill_color`` attributes to properties\n\n\n* :pr:`2396`: Fixed animations introducing or removing objects\n   * :class:`.ShowPassingFlash` now removes objects when the animation is finished\n   * Added ``introducer`` keyword argument to :class:`.Animation` analogous to ``remover``\n   * Updated :class:`.Graph` vertex addition handling\n\nFixed bugs\n----------\n\n* :pr:`2574`: Improved Error in :mod:`.utils.tex_file_writing`\n\n\n* :pr:`2580`: Fixed :func:`.find_intersection` in :mod:`.space_ops`\n\n\n* :pr:`2576`: Fixed a bug with animation of removal of edges from a :class:`.Graph`\n\n\n* :pr:`2556`: Fixed showing highlighted cells when creating :class:`.Table`\n\n\n* :pr:`2559`: Fix setting line numbers in :class:`.Text` when using ManimPango settings\n\n\n* :pr:`2557`: Fixed logger bug in :meth:`.Camera.make_background_from_func`\n\n\n* :pr:`2548`: Fixed :class:`.Axes` plotting bug with logarithmic x-axis\n\n\n* :pr:`1547`: Fixed certain unicode characters in users' paths causing issues on Windows\n\n\n* :pr:`2526`: Fixed segfault when using ``--enable_gui``\n\n\n* :pr:`2538`: Fixed flickering OpenGL preview when using ``frozen_frame``\n\n\n* :pr:`2528`: Fixed custom naming of gifs and added some tests\n\n\n* :pr:`2487`: Fixed :meth:`.ThreeDCamera.remove_fixed_orientation_mobjects`\n\n\n* :pr:`2530`: Use single source of truth for default text values\n\n\n* :pr:`2494`: Fixed an issue related to previewing gifs\n\n\n* :pr:`2490`: Fixed order of transformation application in :class:`~.SVGMobject`\n\n\n* :pr:`2357`: Fixed ``screeninfo.get_monitors`` for MacOS\n\n\n* :pr:`2444`: Fixed :meth:`.VectorScene.add_axes`\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`2560`: Refactored more docstrings in :mod:`.geometry`\n\n\n* :pr:`2571`: Refactored docstrings in :mod:`.graphing`\n\n\n* :pr:`2569`: Refactored docstrings in :mod:`.geometry`\n\n* :pr:`2549`: Added a page for internals which links to our GitHub wiki\n\n\n* :pr:`2458`: Improved documentation for :class:`.Rotate`\n\n\n* :pr:`2459`: Added examples to some transform animations\n\n\n* :pr:`2517`: Added guide on profiling and improving performance\n\n\n* :pr:`2518`: Added imports to examples for ``deprecation`` decorator\n\n\n* :pr:`2499`: Improved help text for ``--write_to_movie``\n\n\n* :pr:`2465`: Added documentation for :func:`.index_labels`\n\n\n* :pr:`2495`: Updated minimal LaTeX installation instructions\n\n\n* :pr:`2500`: Added note about contributions during refactor period\n\n\n* :pr:`2431`: Changed example in :meth:`.Surface.set_fill_by_value`\n\n\n* :pr:`2485`: Fixed some typos in documentation\n\n\n* :pr:`2493`: Fixed typo in documentation for parameters of :class:`.Square`\n\n\n* :pr:`2482`: Updated Python version requirement in installation guide\n\n\n* :pr:`2438`: Removed unnecessary rotation from example\n\n\n* :pr:`2468`: Hid more private methods from the docs\n\n\n* :pr:`2466`: Fixed a typo in the documentation for plugins\n\n\n* :pr:`2448`: Improvements to the ``.pot`` files cleaning system\n\n\n* :pr:`2436`: Fixed typo and improved example in building blocks tutorial\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`2554`: Removed ``Remove-Item`` calls for MSYS2 Python\n\n\n* :pr:`2531`: Added a GitHub Action for automatic validation of citation metadata\n\n\n* :pr:`2536`: Upgraded version of setup-ffmpeg CI action\n\n\n* :pr:`2484`: Updated tinytex download URL\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`2573`: Moved :mod:`.value_tracker` back inside :mod:`.mobject`\n\n\n* :pr:`2566`: Removed unused livestream-related imports and functions from :mod:`.scene_file_writer`\n\n\n* :pr:`2524`: Reworked :mod:`.space_ops`\n\n\n* :pr:`2519`: Removed outdated comment\n\n\n* :pr:`2503`: Removed unused imports\n\n\n* :pr:`2475`: Removed setuptools dependency\n\n\n* :pr:`2472`: Removed unnecessary comment in :mod:`.simple_functions`\n\n\n* :pr:`2429`: Upgraded to future-style type annotations\n\n\n* :pr:`2464`: Bump pillow from 8.4.0 to 9.0.0\n\n\n* :pr:`2376`: Updated dependencies for Python 3.10\n\n\n* :pr:`2437`: Cleaned up :mod:`.simple_functions`\n   - Removed ``fdiv`` as in all cases where it was used, it was just doing the same thing as numpy array division.\n   - Replaced old implementation of the choose function with scipy's implementation\n   - Use ``lru_cache`` (least recently used cache) for caching the choose function. Since it's only used for beziers, only 2 choose k and 3 choose k will be used, hence a size of 10 should be enough.\n   - Removed ``clip_in_place`` in favor of ``np.clip``\n   - Removed one use of ``clip_in_place`` that wasn't actually doing anything\n\n* :pr:`2439`: Removed twitter template from scripts\n\n\nNew releases\n------------\n\n* :pr:`2547`: Prepared new release, ``v0.15.0``\n"
  },
  {
    "path": "docs/source/changelog/0.15.1-changelog.rst",
    "content": "*******\nv0.15.1\n*******\n\n:Date: March 08, 2022\n\nContributors\n============\n\nA total of 9 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Benjamin Hackl\n* Nicolai Weitkemper\n* Yuchen +\n* ad_chaos\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Alex Lembcke\n* Benjamin Hackl\n* Darylgolden\n* Naveen M K\n* Raghav Goel\n* ad_chaos\n* icedcoffeeee\n\nPull requests merged\n====================\n\nA total of 9 pull requests were merged for this release.\n\nEnhancements\n------------\n\n* :pr:`2602`: Support groups in :class:`.TransformMatchingTex`\n\n\nFixed bugs\n----------\n\n* :pr:`2594`: Fixed render flow issues with introducer animations\n\n\n* :pr:`2584`: Fixed bug with invalid color type ``None``\n\n\n* :pr:`2587`: Fixed bug with rendering Tex string that contain ``%``\n\n\n* :pr:`2593`: Fixed bug with displaying images in Jupyter Notebooks when ``config.media_embed`` is set to ``False``\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`2570`: Refactored docstrings in :mod:`.coordinate_systems`\n\n\n* :pr:`2603`: Reduced the number of warnings during documentation build\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`2578`: Fixed incorrect type hint for color property of :class:`.Text`\n\n\nNew releases\n------------\n\n* :pr:`2596`: Prepared bugfix release v0.15.1\n"
  },
  {
    "path": "docs/source/changelog/0.15.2-changelog.rst",
    "content": "*******\nv0.15.2\n*******\n\n:Date: April 25, 2022\n\nContributors\n============\n\nA total of 33 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Bailey Powers +\n* Benjamin Hackl\n* Dan Walsh +\n* Darigov Research\n* Darylgolden\n* David Millard +\n* Hamidreza Hashemi +\n* Jan-Hendrik Müller\n* Jason Villanueva\n* Jonathan Alpert +\n* Joy Bhalla\n* Kian Cross +\n* Luca +\n* Mohsin Shaikh +\n* Naveen M K\n* Prismo +\n* Ryan McCauley\n* WillSoltas +\n* ad_chaos\n* darkways +\n* dawn*squirryl +\n* icedcoffeeee\n* peaceheis\n* sparshg\n* trickypr +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Benjamin Hackl\n* Dan Walsh\n* Darylgolden\n* GameDungeon\n* Hugues Devimeux\n* Jan-Hendrik Müller\n* Jason Villanueva\n* Jonathan Alpert\n* Luca\n* Naveen M K\n* Prismo\n* Ryan McCauley\n* ad_chaos\n* darkways\n* hickmott99\n* icedcoffeeee\n* peaceheis\n\nPull requests merged\n====================\n\nA total of 39 pull requests were merged for this release.\n\nNew features\n------------\n\n* :pr:`1975`: Improved CLI help page styling\n   - Updates dependencies on Click and Cloup libraries for CLI help page styling.\n   - Removed the dependency on click-default-group.\n   - Added ``no_args_is_help`` parameter for ``manim render`` to allow easy access to help page.\n   - Added note to ``manim`` help page epilog on how to access other command help pages.\n\n* :pr:`2404`: Add :class:`.SpiralIn` Animation\n   - Make :class:`.ManimBanner` to use :class:`.SpiralIn`.\n\n* :pr:`2534`: Implement :class:`~.OpenGLImageMobject`\n\n\n* :pr:`2684`: Created a more accessible way to create Angles with line.py angle function - :meth:`.Angle.from_three_points`\n\n\nEnhancements\n------------\n\n* :pr:`2062`: Reuse shader wrappers and shader data\n\n\n* :pr:`2642`: Migrated ``file_ops.py`` and ``scene_file_writer.py`` from os.path to Pathlib\n   In ``file_ops.py`` and ``scene_file_writer.py``: Uses of str type file names have been mostly (see further information) converted to pathlib's Path objects. Uses of ``os.path`` methods have been converted to equivalent pathlib methods.\n\n* :pr:`2655`: Fix :func:`.assert_is_mobject_method` when using OpenGL\n\n\n* :pr:`2665`: Improved handling of attributes when using the ``.animate`` syntax\n\n\n* :pr:`2674`: Document and type ``simple_functions.py``\n   - Add documentation for ``simple_functions.py``.\n   - Small additions with some extra clarity for these functions.\n\n* :pr:`2693`: Allow using :meth:`.MovingCamera.auto_zoom` without animation\n   Allows auto zooming camera without having to play an animation by passing an ``animation=False`` argument\n\nFixed bugs\n----------\n\n* :pr:`2546`: Fixed a file logging bug and some maintenance\n\n\n* :pr:`2597`: Fix Bug in :class:`.Uncreate` with ``rate_func`` via introducing new parameter ``reversed`` to :class:`.Animation`\n   - Refractor the :class:`.Uncreate`. The new implementation uses a flag member ``reversed``. Set it to ``True`` and its superclass handles the reverse.\n   - Introduce a bool parameter ``reversed`` to :class:`.Animation`. It decides whether the animation needs to be played backwards. Default to be False.\n   - Add conditional branches in :meth:`.Animation.get_sub_alpha`. If the parameter ``reversed`` is True, it would set ``rate_func(t)`` to ``rate_func(1 - t)``.\n\n* :pr:`2613`: Fixed bug in :meth:`.Circle.point_at_angle` when the angle is not in the interval :math:`[0, 2\\pi]`\n\n\n* :pr:`2634`: Fix background lines drawn twice in :class:`.NumberPlane`\n\n\n* :pr:`2648`: Handle user-defined centers for Wiggle animation\n\n\n* :pr:`2658`: Fix arguments of overridden ``set_style`` for :class:`.BackgroundRectangle`\n   Using :class:`.Write` animation on a :class:`.Text` object with ``.add_background_rectangle()`` applied no longer generates a ``TypeError``.\n\n* :pr:`2668`: (Re)set background color of :class:`.OpenGLRenderer` when initializing scene\n\n\n* :pr:`2676`: Fixed propagation of custom attributes in animations for the OpenGL renderer\n\n\n* :pr:`2688`: Fixed two minor issues of :class:`.SpiralIn` and :class:`.ManimBanner`\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`2609`: Copyedit troubleshooting.rst\n\n\n* :pr:`2610`: Add example PolygonOnAxes\n\n\n* :pr:`2617`: Re-added :mod:`.value_tracker` documentation\n\n\n* :pr:`2619`: Improve Example for arrange_in_grid\n\n\n* :pr:`2620`: Fixed typo in :meth:`.Animation.is_introducer`\n\n\n* :pr:`2640`: Copyedited Documentation\n   Reviewed ``tutorials/configurations.rst``. Edited simple mistakes such as Manim not being capitalized and commas.\n\n* :pr:`2649`: Document and type utils/iterables.py\n\n\n* :pr:`2651`: Update copyright year in documentation to 2020-2022\n\n* :pr:`2663`: Added documentation for scene updater functions\n\n\n* :pr:`2686`: Add instructions to install extra dependencies with poetry\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`2561`: Run tests on Linux-aarch64\n\n\n* :pr:`2656`: Fixed incompatibility with black version\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`2630`: Remove WebGL renderer\n   The WebGL renderer is broken and unmaintained. The support for it in Manim is removed.\n\n* :pr:`2652`: Update ``cloup`` version to 0.13.0 from 0.7.0\n\n\n* :pr:`2678`: Require ``backports-cached-property`` only for Python < 3.8\n\n\n* :pr:`2685`: Migrate from ``os.path`` to ``pathlib`` in testing scripts\n   This pull request changes a number of instances of ``os.path`` to Pathlib objects and functions. In addition, this PR modifies the SVGMobject constructor to accept both a Pathlib object or a string variable pathname its constructor.\n\n* :pr:`2691`:  Removed :class:`CameraFrame`\n\n\n* :pr:`2696`: Made changelog generation run in parallel plus further improvements to ``scripts/dev_changelog.py``\n\n\n* :pr:`2697`: Sort PRs by number in changelog sections before writing\n\n\nNew releases\n------------\n\n* :pr:`2694`: Prepared bugfix release v0.15.2\n"
  },
  {
    "path": "docs/source/changelog/0.16.0-changelog.rst",
    "content": "*******\nv0.16.0\n*******\n\n:Date: July 13, 2022\n\nContributors\n============\n\nA total of 44 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Alex Lembcke\n* Baroudi Aymen +\n* Benjamin Hackl\n* Charalampos Georgiou +\n* Cindy Park +\n* Ejar +\n* Francesco Frassinelli +\n* Francisco Manríquez Novoa +\n* Jacob Evan Shreve +\n* Jaime Santos +\n* Jonathan Alpert\n* Joshua Mankelow +\n* Kevin Lubick +\n* Laith Bahodi\n* Lingren Kong +\n* Logen +\n* Naveen M K\n* Noam Zaks\n* Pedro Lamkowski +\n* Raghav Goel\n* Simeon Widdis\n* Sparsh Goenka\n* TornaxO7 +\n* Tristan Schulz +\n* WillSoltas\n* ad_chaos\n* conor-oneill-2 +\n* fcrozatier +\n* mooncaker816 +\n* niklebedenko +\n* nyabkun +\n* quark67\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Alex Lembcke\n* Benjamin Hackl\n* Darylgolden\n* Francesco Frassinelli\n* Francisco Manríquez Novoa\n* Gianluca Gippetto\n* Jan-Hendrik Müller\n* Jonathan Alpert\n* Kevin Lubick\n* Laith Bahodi\n* Naveen M K\n* Pedro Lamkowski\n* Philipp Imhof\n* Raghav Goel\n* Ryan McCauley\n* Sparsh Goenka\n* TornaxO7\n* Tristan Schulz\n* ad_chaos\n* hickmott99\n\nPull requests merged\n====================\n\nA total of 56 pull requests were merged for this release.\n\nHighlights\n----------\n\n* :pr:`2550`: New thematic guide: a deep dive into the internals of the library\n   This new :doc:`thematic guide </guides/deep_dive>` aims to be a comprehensive walkthrough\n   describing all the things that Manim does when you run it to produce a video.\n\n* :pr:`2732`: Improved overall structure of deployed documentation; added a dedicated :doc:`FAQ section </faq/index>`\n\n\n* :pr:`2749`: Added :class:`.ChangeSpeed`, an animation wrapper that allows to smoothly change the speed at which an animation is played\n   The speed of any animation can be changed by wrapping the animation with :class:`.ChangeSpeed` and passing a dictionary as ``speedinfo`` whose keys are the relative animation run time stamps and whose values are the absolute speed factors; e.g., ``{0.5: 2, 0.75: 0.25}`` smoothly speeds up the animation by a factor of 2 once it has been completed to 50%, and then it is smoothly slowed down to 1/4 of the default run speed after 75% of the animation are completed. The ``run_time`` of the animation will be adjusted to match the changed play speed.\n\n   It is also possible to add time-based updaters that respect the change in speed, use the auxiliary :meth:`.ChangeSpeed.add_updater` method to do so.\n\nNew features\n------------\n\n* :pr:`2667`: Made FFmpeg executable path configurable\n\n\n* :pr:`2739`: Added vectorized plotting functionality via keyword argument ``use_vectorized`` to improve performance\n\n\nEnhancements\n------------\n\n* :pr:`2186`: Enabled filling color by value for :class:`.OpenGLSurface`, replaced ``colors`` keyword argument of :meth:`.Surface.set_fill_by_value`  with ``colorscale``\n\n\n* :pr:`2288`: Added warning when attempting to add same mobject as child twice\n\n\n* :pr:`2707`: Fixed missing ``get_nth_curve_length_pieces`` method of :class:`.OpenGLVMobject`\n   - Removed duplicate definition of ``get_curve_functions_with_lengths`` in ``OpenGLVMobject``\n   - Added definition of ``get_nth_curve_length_pieces`` to ``OpenGLVMobject``\n\n* :pr:`2709`: Improved the look of the brackets of :class:`.Matrix`\n\n\n* :pr:`2714`: Fixed :meth:`.OpenGLVMobject.pointwise_become_partial` to improve stroke rendering\n\n\n* :pr:`2727`: Slight performance improvement for :class:`.ArrowVectorField` and Bézier curve computation\n\n\n* :pr:`2728`: Added :meth:`.VectorField.fit_to_coordinate_system` to fit a vector field to a given coordinate system\n\n\n* :pr:`2730`: Added note to let users find documentation of default CLI subcommand easier\n\n\n* :pr:`2746`: Installed ghostscript in the docker image\n\n\n* :pr:`2841`: Added :func:`.split_quadratic_bezier` and :func:`.subdivide_quadratic_bezier`\n\n\n* :pr:`2842`: CLI: Moved functionality from ``manim new`` to ``manim init`` and added deprecation warning for ``manim new``\n\n\n* :pr:`2866`: Reorganize test files to match library module structure\n\n\nFixed bugs\n----------\n\n* :pr:`2567`: Use tempconfig for every scene render\n\n\n* :pr:`2638`: Fixed :meth:`BarChart.change_bar_values`  not updating when height is 0\n\n\n* :pr:`2661`: Fixed tip resize functionality for :class:`.Axes` to match documentation\n\n\n* :pr:`2703`: Default to utf-8 when reading files in :class:`.Code`\n\n\n* :pr:`2721`: Fixed bad text slicing for lines in :class:`.Paragraph`\n\n\n* :pr:`2725`: Fixed wrong indentation in :class:`.Code`\n\n\n* :pr:`2734`: Fixed OpenGL segfaults when running :meth:`.Scene.play` or :meth:`.Scene.wait` in interactive mode\n\n\n* :pr:`2753`: Fixed multiplatform builds for docker images in pipeline\n\n\n* :pr:`2757`: Added missing ``__init__.py`` file in :mod:`.docbuild` module\n\n\n* :pr:`2770`: Fixed bug in :meth:`.VMobject.proportion_from_point` that caused proportions greater than 1 to be returned\n\n\n* :pr:`2826`: Fixed leaked mobjects coming from :class:`.TransformMatchingAbstractBase`\n\n\n* :pr:`2870`: Fixed issue with ``manim init scene SCENE_NAME filename.py`` and removed necessity of ``main.py`` to be present in working directory\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`2704`: Updated URL to Pango Markup formatting page\n\n\n* :pr:`2716`: Improved the order of the reference manuals\n\n\n* :pr:`2720`: Fixed typo in docstring of :class:`.Angle`\n\n\n* :pr:`2722`: Fixed typos in docstrings of classes in :mod:`.mobject.table`\n\n\n* :pr:`2726`: Edited note on :class:`.NumberPlane` length and added another example\n\n\n* :pr:`2740`: Fixed documentation of :meth:`.Cylinder.get_direction`\n\n\n* :pr:`2755`: Fixed docstring of  :meth:`.VMobject.get_end_anchors`\n\n\n* :pr:`2760`: Removed ``cmake`` from the MacOS installation section\n\n\n* :pr:`2767`: Added more questions and answers to FAQ section, new :doc:`OpenGL FAQ </faq/opengl>`\n\n\n* :pr:`2771`: Added documentation and testing for ``path_func`` keyword argument of :class:`.Transform`\n\n\n* :pr:`2828`: Removed suggestion issue template, added FAQ answer regarding proposing new features\n\n\n* :pr:`2849`: Added example for ``path_arc`` keyword argument of :class:`.Transform`\n\n\n* :pr:`2851`: Added an example on constructing a (neural) network using a partite :class:`.Graph`\n\n\n* :pr:`2855`: Added implicit ``docker.io/`` URL base in reference to docker images\n\n\n* :pr:`2861`: Added docstring for :meth:`.CoordinateSystem.plot_parametric_curve`\n\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`2743`: Replaced ``assert`` statements with with assertion functions from ``np.testing``\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`2700`: CI: updated Python versions\n\n\n* :pr:`2701`: CI: added a workflow to publish docker image after releases and commits to main branch\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`2680`: Increased minimum required version of ``numpy`` to 1.19\n\n\n* :pr:`2687`: Migrated from ``os.path`` to ``pathlib`` in :class:`.SVGMobject` and other locations\n\n\n* :pr:`2715`: Updated deprecated ``pillow`` constants\n\n\n* :pr:`2735`: Bump pyjwt from 2.3.0 to 2.4.0\n\n\n* :pr:`2748`: Bump pillow from 9.1.0 to 9.1.1\n\n\n* :pr:`2751`: Fixed flake C417 and improved a comment\n\n\n* :pr:`2825`: Bump notebook from 6.4.11 to 6.4.12\n\n\n* :pr:`2864`: Updated lockfile\n\n\nNew releases\n------------\n\n* :pr:`2863`: Prepared new release,  ``v0.16.0``\n"
  },
  {
    "path": "docs/source/changelog/0.17.0-changelog.rst",
    "content": "*******\nv0.17.0\n*******\n\n:Date: December 02, 2022\n\nContributors\n============\n\nA total of 32 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Alex Lembcke\n* Alexander Vázquez\n* Benjamin Hackl\n* Duc Phat +\n* Hugues Devimeux\n* Ievgen Pyrogov +\n* Isaac Beh +\n* Jeff Hanke +\n* John Hammond +\n* Jérome Eertmans +\n* Kevin Lubick\n* Kian-Meng Ang +\n* Naveen M K\n* Nick Skriloff +\n* NotWearingPants\n* Onur Solmaz +\n* OpenRefactory, Inc +\n* Owen Samuel +\n* Pavel Zwerschke +\n* Sparsh Goenka\n* Taxo Rubio\n* ad-chaos +\n* fcrozatier\n* mostly documentation +\n* vahndi +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Benjamin Hackl\n* Darylgolden\n* Hugues Devimeux\n* Jan-Hendrik Müller\n* Kevin Lubick\n* Mohammed Belgoumri\n* Naveen M K\n* NotWearingPants\n* Raghav Goel\n* Sparsh Goenka\n* Tristan Schulz\n* ad-chaos\n* friedkeenan\n\nPull requests merged\n====================\n\nA total of 63 pull requests were merged for this release.\n\nBreaking changes\n----------------\n\n* :pr:`2898`: Ported improved implementation of :class:`.SVGMobject` from 3b1b/manim\n   The implementation of :class:`.SVGMobject` is completely changed in this release.\n   Manim now uses the Python library ``svgelements`` to parse SVGs, instead of trying\n   to do it itself. The former class for SVG path objects, ``SVGPathMobject`` has been\n   replaced (without deprecation) with :class:`.VMobjectFromSVGPath`.\n\n   If you need to create a mobject from an SVG path string, you can do so via::\n\n        import svgelements as se\n        my_path_mobject = VMobjectFromSVGPath(se.Path(my_path_string))\n\n   The unused class ``TexSymbol`` has been removed. The modules\n   ``manim.mobject.svg.svg_path`` and ``manim.mobject.svg.style_utils`` became\n   superfluous due to the rework and have been removed.\n\n\n* :pr:`3030`: Added support for Python 3.11, dropped support for Python 3.7\n\n\nHighlights\n----------\n\n* :pr:`3049`: Added thematic guide for the ``manim-voiceover`` plugin\n   This new :doc:`thematic guide </guides/add_voiceovers>` provides a brief\n   introduction to ``manim-voiceover``, a plugin that helps to add voiceovers\n   to your manimations. Supports both working with your own voice as well as\n   synthetically generated voices.\n\n\nNew features\n------------\n\n* :pr:`2883`: Added animation :class:`.RemoveTextLetterByLetter`\n\n\n* :pr:`3016`: Implemented :class:`.LineJointTypes` for both Cairo and OpenGL renderer\n\n\n* :pr:`3017`: Replaced renderer strings with :class:`.RendererType` enum entries\n\n\nEnhancements\n------------\n\n* :pr:`2927`: Allowed ``networkx`` to return 3D layouts when passing ``dim=3`` in the ``layout_config`` of a :class:`.Graph`\n\n\n* :pr:`3014`: Enabled code completion for :meth:`.Mobject.animate` for some IDEs\n   Uses a Union of the existing Generic `Mobject` Type `T` and `_Animation Builder` as the declared return type from `Mobject.animate` to improve code completion.\n\nFixed bugs\n----------\n\n* :pr:`2846`: Prevent :class:`.TransformMatchingTex` from crashing when there is nothing to fade\n\n\n* :pr:`2885`: Always expand user when validating file-paths\n\n\n* :pr:`2888`: Fixed bug with propagation of ``tex_template`` value when using ``tempconfig``\n\n\n* :pr:`2895`: Fixed broken :class:`.ShowPassingFlashWithThinningStrokeWidth`\n\n\n* :pr:`2920`: Fixed alignment of faded lines when passing ``faded_line_ratio`` to :class:`.NumberPlane`\n\n\n* :pr:`2977`: Allow rendering of empty text strings\n\n\n* :pr:`2992`: Fixed ``CLI.tex_template_file`` config file setting\n\n\n* :pr:`3003`: Fixed setting ``run_time`` of :class:`.Succession` after creating the animation object\n\n\n* :pr:`3019`: Fixed rendering SVG paths with multiple move commands\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`2881`: Fixed small typo in deep dive guide\n\n\n* :pr:`2886`: Added docstring to and fixed type hint of :func:`.get_winding_number`\n\n\n* :pr:`2892`: Corrected error in the ``PolygonOnAxes`` example\n\n\n* :pr:`2903`: Fixed minor grammar issues in :doc:`/faq/general`\n\n\n* :pr:`2904`: Fixed formatting and grammar issues in :doc:`/contributing/development`\n\n\n* :pr:`2911`: Disabled autoplay for ``SoundExample`` in documentation\n\n\n* :pr:`2914`: Added conda installation instructions\n\n\n* :pr:`2915`: Added documentation to :mod:`.three_dimensions`\n\n\n* :pr:`2919`: Corrected parameters and enhanced the description of :meth:`.ImageMobject.interpolate_color`\n\n\n* :pr:`2932`: Fixed whitespace formatting issue\n\n\n* :pr:`2933`: Improved answer to the \"no scenes in this module\" error\n\n\n* :pr:`2936`: Added installation instructions for Windows via ``winget``\n\n\n* :pr:`2962`: Disabled \"Edit on GitHub\" button in documentation\n\n\n* :pr:`2978`: Added documentation and example for :class:`.CyclicReplace`\n\n\n* :pr:`3001`: Added FAQ entry regarding failed ``manimpango`` build\n\n\n* :pr:`3004`: Fixed docbuild warnings\n\n\n* :pr:`3018`: Follow-up to :pr:`2988` -- fixes and improvements to some docstrings\n\n\n* :pr:`3022`: Corrected type hint in :meth:`Axes.coords_to_point`\n\n\n* :pr:`3035`: Include latex install instructions on ubuntu\n\n\n* :pr:`3044`: Added Debian dependencies required for pycairo and manimpango\n\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`2893`: Improved performance of ``test_threed.py``\n\n\n* :pr:`2981`: Implemented fallback save behavior for ``pytest --show_diff``\n\n\n* :pr:`2982`: Rewrote unstable tests for :mod:`.text_mobject` to be non-graphical\n\n\n* :pr:`2991`: Migrated ``os.path`` to ``pathlib.Path`` in tests\n\n\n* :pr:`3053`: Added threshold for pixel value errors in frame comparison tests\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`2925`: CI (test-arm): Updated python version to ``3.10.6``\n\n\n* :pr:`2963`: CI (test-arm): Always select the correct python version\n\n\n* :pr:`3029`: CI: Updated actions version and added dependabot config\n\n\n* :pr:`3045`: Updated python-opengl -> python3-opengl for Ubuntu CI task\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`2872`: Add ``extract_frames.py`` utility script to help visualize test control data\n\n\n* :pr:`2877`: Fixed binder launch problem by adding missing optional ``notebook`` dependency\n\n\n* :pr:`2887`: Removed empty i18n files that caused filename clashes\n\n\n* :pr:`2931`: Updated ``mapbox-earcut``\n\n\n* :pr:`2938`: Suggested fixes by iCR, OpenRefactory, Inc.\n\n\n* :pr:`2954`: Fixed click version string in ``pyproject.toml``\n\n\n* :pr:`2958`: Fix missing stub packages for mypy\n\n\n* :pr:`2975`: Fixed broken links in README\n\n\n* :pr:`2980`: Migrate more ``os.path`` to ``pathlib.Path``\n\n\n* :pr:`2983`: Fixed Windows CI Pipeline\n\n\n* :pr:`2988`: Converted all types of parameters in docstrings to proper type annotations\n\n\n* :pr:`2994`: Fixed segmentation faults from doctests under Python 3.10\n\n\n* :pr:`2995`: Added encoding to ``open`` in :mod:`.utils.text_file_writing`\n\n\n* :pr:`3032`: Bump jupyter-core from 4.11.1 to 4.11.2\n\n\n* :pr:`3033`: Bump pillow from 9.2.0 to 9.3.0\n\n\n* :pr:`3054`: Removed unused ``GraphicalUnitTester``\n\n\nNew releases\n------------\n\n* :pr:`3023`: Prepared new release: v0.17.0\n"
  },
  {
    "path": "docs/source/changelog/0.17.1-changelog.rst",
    "content": "*******\nv0.17.1\n*******\n\n:Date: December 08, 2022\n\nContributors\n============\n\nA total of 5 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Alex Lembcke\n* Benjamin Hackl\n* Naveen M K\n* Onur Solmaz\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Benjamin Hackl\n* Naveen M K\n* Sparsh Goenka\n\nPull requests merged\n====================\n\nA total of 6 pull requests were merged for this release.\n\nFixed bugs\n----------\n\n* :pr:`3061`: Always expand file paths using ``/`` when calling LaTeX\n\n\n* :pr:`3062`: Added Unicode encoding in :meth:`.Scene.add_subcaption`\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`2953`: Added documentation for lagged animations in :mod:`.animation.composition`\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`3064`: Increased minimal required version of ``svgelements``\n\n\n* :pr:`3066`: Increased minimal version of ``pytest``\n\n\nNew releases\n------------\n\n* :pr:`3065`: Prepared new release: ``v0.17.1``\n"
  },
  {
    "path": "docs/source/changelog/0.17.2-changelog.rst",
    "content": "*******\nv0.17.2\n*******\n\n:Date: December 26, 2022\n\nContributors\n============\n\nA total of 5 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* CaftBotti +\n* Tristan Schulz\n* lgtm-com[bot] +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Benjamin Hackl\n* Naveen M K\n* Tristan Schulz\n\nPull requests merged\n====================\n\nA total of 7 pull requests were merged for this release.\n\nFixed bugs\n----------\n\n* :pr:`3089`: Fixed OpenGL mobjects like :class:`.Surface` by reordering init calls\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`3073`: Fixed typo: \"Whetherer\" to \"Whether\"\n\n\n* :pr:`3074`: Fixed typo in a comment\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`3024`: Add CodeQL workflow for GitHub code scanning\n\n\n* :pr:`3079`: Updated CI syntax for runner version >= 2.298.2\n\n\n* :pr:`3084`: Properly setup CodeQL\n\n\nNew releases\n------------\n\n* :pr:`3090`: Prepared new Hotfix Release: ``v0.17.2``\n"
  },
  {
    "path": "docs/source/changelog/0.17.3-changelog.rst",
    "content": "*******\nv0.17.3\n*******\n\n:Date: April 06, 2023\n\nContributors\n============\n\nA total of 35 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Alex Lembcke\n* Benjamin Hackl\n* DegrangeM +\n* Elyanah Aco +\n* Francisco Manríquez Novoa\n* Fredrik Lundström +\n* Frédéric Crozatier\n* Ikko Eltociear Ashimine +\n* ItIsJoeyG +\n* JinchuLi2002 +\n* Kevin Lubick\n* KingAndCross +\n* M. A. Ali +\n* Matthew Lee +\n* Max Coplan +\n* Naveen M K\n* NotWearingPants\n* Oscar Rangel +\n* Papierkorb2292 +\n* Phoenix2157 +\n* Tristan Schulz\n* ciobaca +\n* coreyp1 +\n* davidot +\n* icedcoffeeee\n* karpfediem +\n* vahndi\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Benjamin Hackl\n* Fredrik Lundström\n* Frédéric Crozatier\n* Hugues Devimeux\n* Kevin Lubick\n* KingAndCross\n* Matthew Lee\n* Naveen M K\n* Tristan Schulz\n* coreyp1\n* davidot\n* strager\n\nPull requests merged\n====================\n\nA total of 42 pull requests were merged for this release.\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`3103`: Removed deprecated function ``OpenGLSurface.set_fill_by_value``\n\n\nNew features\n------------\n\n* :pr:`2974`: Added :class:`.DiGraph`, a mobject representing directed graphs\n\n\n* :pr:`3042`: Added :meth:`.Scene.replace` and use in :class:`.ReplacementTransform`\n\n* :pr:`3155`: Added support for individualized radius values in :meth:`.Polygram.round_corners`\n\n\n* :pr:`3159`: Added :meth:`.set_opacity_by_tex` method for setting the opacity of parts of Tex mobjects\n\n\n* :pr:`3201`: New tip shape :class:`.StealthTip`, allow specifying tip shape of :class:`.NumberLine`\n\n\nEnhancements\n------------\n\n* :pr:`3046`: Add warning if font is not found for Text, Code, and MarkupText\n\n\n* :pr:`3083`: Minor performance improvement in :mod:`.bezier` with preallocating array\n\n\n* :pr:`3092`: Improved :meth:`.Mobject.add` performance by checking for redundancy only once\n\n\n* :pr:`3134`: Performance: Store color data of ``OpenGLSurface`` to prevent OpenGL embed lag\n\n\n* :pr:`3180`: Performance: Speed up width/height/depth calculations by reducing copying\n\n\n* :pr:`3181`: Improved creation time for large :class:`.Text` mobjects\n\n\n* :pr:`3182`: Reduce memory allocations when building :class:`.SVGMobject`\n\n\n* :pr:`3191`: Fixed OpenGL rendering in named threads\n\n\nFixed bugs\n----------\n\n* :pr:`3015`: Fixed bug with ``label_constructor`` in :meth:`.NumberLine.add_labels`\n\n\n* :pr:`3095`: Fixed ``get_axis_labels`` for :class:`.Axes` and :class:`.ThreeDAxes`\n\n\n* :pr:`3106`: Fixed ignored ``depth_test`` argument for ``OpenGLVMobjects``\n\n\n* :pr:`3149`: Allow to use ``call_updater=True`` in :meth:`.Mobject.add_updater` with non-timebased updaters too\n\n\n* :pr:`3152`: Fixed behavior of :class:`.Wait` and :meth:`.Scene.wait` with specified ``stop_condition``\n\n\n* :pr:`3163`: Fixed :class:`.BraceLabel` not passing additional keyword arguments to :class:`.Brace`\n\n\n* :pr:`3195`: Fixed :class:`.Axes` scaling for :meth:`.plot_implicit_curve`\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`3105`: Converted types specified in docstrings to proper type hints in :mod:`.three_dimensions`\n\n\n* :pr:`3108`: Clarified documentation for ``--resolution`` command line flag\n\n\n* :pr:`3109`: Clean-up, type-hints and documentation for :mod:`.three_dimensions`\n\n\n* :pr:`3124`: Fixed docstring of :meth:`.ThreeDCamera.get_value_trackers`\n\n\n* :pr:`3126`: Fixed dead links to troubleshooting page\n\n\n* :pr:`3137`: Fixed example using ``reverse=True`` with :class:`.Write`\n\n\n* :pr:`3160`: Fixed a typo\n\n\n* :pr:`3189`: Corrected the hinted return type for :func:`angle_between_vectors`\n\n\n* :pr:`3199`: Updated ``winget`` command for installing MiKTeX in documentation\n\n\n* :pr:`3204`: Fixed docstring formatting of :meth:`.Scene.replace` and improved its error handling\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`3144`: Fixed typo in ``stripUntranslatable.awk``\n\n\n* :pr:`3154`: Bump ipython from 8.7.0 to 8.10.0\n\n\n* :pr:`3156`: CI: Remove actions using self-hosted runners\n\n\n* :pr:`3164`: Bump markdown-it-py from 2.1.0 to 2.2.0\n\n\n* :pr:`3165`: Removed deprecated keyword argument in :meth:`.Mobject.align_to`\n\n\n* :pr:`3166`: Made :class:`.ArrowTriangleTip`, :class:`.ArrowTriangleFilledTip` available to module namespace\n\n\n* :pr:`3179`: Fixed deprecation warning in :class:`.ParametricFunction` with ``use_vectorized=True``\n\n\n* :pr:`3186`: Updated extlinks to work with latest version of Sphinx\n\n\n* :pr:`3196`: CI: updated PATH for recent changed in TinyTex\n\n\n* :pr:`3200`: Made import from ``moderngl`` compatible with more recent versions\n\n\nNew releases\n------------\n\n* :pr:`3198`: Prepare new release: v0.17.3\n"
  },
  {
    "path": "docs/source/changelog/0.18.0-changelog.rst",
    "content": "*******\nv0.18.0\n*******\n\n:Date: November 11, 2023\n\nContributors\n============\n\nA total of 41 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Abulafia +\n* Adhyyan Sekhsaria +\n* Adrien Ludwig +\n* Alex Kempen +\n* Andres Berejnoi +\n* Anousheh Moonen +\n* Benjamin Hackl\n* Francisco Manríquez Novoa\n* Harald Schilly +\n* Immanuel-Alvaro-Bhirawa +\n* Jason Grace +\n* Jason Villanueva\n* Jinchu Li\n* John Lynch +\n* Jérome Eertmans\n* Matt Turner +\n* Narahari Rao +\n* Naveen M K\n* Nikhil Iyer +\n* Ron Li +\n* Sujal Singh +\n* Tristan Schulz\n* Uwe Zimmermann +\n* Václav Blažej +\n* Zachary Winkeler +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Alex Lembcke\n* Andres Berejnoi\n* Axel\n* Benjamin Hackl\n* Francisco Manríquez Novoa\n* Immanuel-Alvaro-Bhirawa\n* Jan-Hendrik Müller\n* Jason Grace\n* Jason Villanueva\n* Jinchu Li\n* John Lynch\n* Jérome Eertmans\n* Kevin Lubick\n* Narahari Rao\n* Naveen M K\n* NotWearingPants\n* SsNiPeR1\n* TheMathematicFanatic\n* Tristan Schulz\n* Uwe Zimmermann\n* Viicos\n* icedcoffeeee\n\nPull requests merged\n====================\n\nA total of 59 pull requests were merged for this release.\n\nBreaking changes\n----------------\n\n* :pr:`3020`: Rewrote Manim's color system\n   This change removed the ``colour`` library as a dependency\n   of Manim and replaced the internal handling of colors with\n   the newly added :class:`.ManimColor`. This also adds hundreds\n   of new predefined colors, see :mod:`.utils.color` for more\n   details.\n   This should only be a breaking change if you have interacted\n   directly with the ``colour`` module before. The general interface\n   has been kept stable.\n\n\nHighlights\n----------\n\n* :pr:`3299`: Added new ``manim checkhealth`` CLI subcommand\n   This adds a new command line interface subcommand which can be used to check\n   whether a local installation of Manim has been configured correctly, and all\n   required (and optional) dependencies are available. To try it, run it via\n   ``manim checkhealth`` or ``python -m manim checkhealth``.\n\n* :pr:`3427`: New feature: rendered examples in documentation can now be run directly via binder\n   This adds a \"Make interactive\" button below the examples in our documentation\n   that establishes a connection to binder such that examples can be modified and\n   rerendered directly from your browser.\n\n* :pr:`3086`: Introduced a new module :mod:`.typing` for type hints\n   This also adds various type hints to integral parts of the code base.\n\n* :pr:`3322`: Implemented auto-removal of auxiliary LaTeX files, enabled by default\n   This automatically removes auxiliary files creating during the compilation of\n   LaTeX documents like ``.aux`` or ``.dvi`` files. This behavior can be controlled\n   via the newly introduced ``no_latex_cleanup`` config key (``False`` by default).\n   On the command line, the autoremoval can be disabled via the ``--no_latex_cleanup``\n   CLI flag.\n\n* :pr:`3395`: Added support for Python 3.12\n\nNew features\n------------\n\n* :pr:`3361`: Added three new rate functions\n    This adds the rate functions :func:`.smoothstep`, :func:`.smootherstep`,\n    :func:`.smoothererstep` based on the SmoothStep sigmoid functions.\n\n* :pr:`3264`: Added new mobjects :class:`.LabeledLine` and :class:`.LabeledArrow`\n\n\nEnhancements\n------------\n\n* :pr:`3190`: Made :class:`.CurvesAsSubmobjects` mobjects compatible with :meth:`.input_to_graph_point`\n\n\n* :pr:`3226`: Avoid using a mobject as a default argument of :class:`.ArcBrace`\n\n\n* :pr:`3366`: Added spacing between values and unit in :class:`.DecimalNumber`\n   This adds the new keyword argument ``unit_buff_per_font_unit`` (default: 0, for\n   backwards compatibility). Setting it to some positive number creates additional\n   space between the numeric value and the displayed unit.\n\nFixed bugs\n----------\n\n* :pr:`3205`: Fixed type hint of ``angle`` in :class:`.Arc`\n\n\n* :pr:`3210`: Fixed :class:`.DecimalNumber` with ``show_ellipsis=True`` with the OpenGL renderer\n\n\n* :pr:`3211`: Fixed display issues with custom labels for :class:`.Axes` with the OpenGL renderer\n\n\n* :pr:`3298`: Fixed expand animation for :class:`.ManimBanner`\n\n\n* :pr:`3306`: Fixed IPython terminal history and embedded shell instantiation for scenes using :meth:`.Scene.interactive_embed`\n\n\n* :pr:`3315`: Fixed issue with parameter types in :meth:`.Scene.add_subcaption`\n\n\n* :pr:`3423`: Fixed incorrect submobject count of multi-part :class:`.Tex` mobjects\n   This resolves various issues where formulas were not displayed completely,\n   like it was the case with ``MathTex(\"1\", \"^{\", \"0\")``.\n\n* :pr:`3284`: Fixed ``LinearTransformationSceneExample`` in Jupyter notebooks\n\n\n* :pr:`3302`: Fixed typo in comparison in :meth:`.OpenGLVMobject.interpolate`\n\n\n* :pr:`3340`: Fixed incorrect computation of bounding box for rotated :class:`.ImageMobject`\n\n\n* :pr:`3343`: Fixed return value of :meth:`.TexTemplate.add_to_preamble` and :meth:`.TexTemplate.add_to_document`\n\n\n* :pr:`3282`: Ensure that :meth:`.ArrowVectorField.get_vector` does not modify the passed inputs\n\n\n* :pr:`3392`: Fixed behavior of elongated tick lines for :class:`.NumberLine`\n\n\n* :pr:`3430`: Fixed CSV reader adding empty lists in rendering summary during documentation build\n\n\n* :pr:`3404`: Properly raise an exception on empty inputs to :class:`.AddTextLetterByLetter`\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`3219`: Enabled social cards for links to documentation\n\n\n* :pr:`3274`: Replaced incorrect mentions of Python 3.7 as the minimally required version\n\n\n* :pr:`3297`: Improved arrow tip sowcase example for :class:`.ArrowTip`\n\n\n* :pr:`3312`: Added documentation for :func:`.always_redraw`\n\n\n* :pr:`3218`: Improved grammar in the :doc:`deep dive guide </guides/deep_dive>`\n\n\n* :pr:`3251`: Add LaTeX installation instructions for Fedora\n\n\n* :pr:`3290`: Updated required dependencies for MacOS installations\n\n\n* :pr:`3325`: Added documentation for functions in :mod:`.mobject_update_utils`\n   This adds docstrings and typehints to :func:`.always_rotate`,\n   :func:`.always_shift`, :func:`.turn_animation_into_updater`\n\n* :pr:`3353`: Added documentation for :meth:`.Mobject.center`\n\n\n* :pr:`3355`: Temporarily enabled ``htmlzip`` build on ReadTheDocs\n\n\n* :pr:`3377`: Fixed a typo in the :doc:`deep dive guide </guides/deep_dive>`\n\n\n* :pr:`3389`: Removed superfluous curly braces in a LaTeX expression\n\n\n* :pr:`3417`: Replaced ``htmlzip`` ReadTheDocs build with workflow attaching downloadable documentation to GitHub releases\n\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`3416`: Fixed tests to run on Cairo 1.18.0\n\n\n* :pr:`3257`: Fix a configuration error concerning poetry\n\n\n* :pr:`3419`: Fixed caching of Cairo builds on CI runners\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`3229`: Made docbuild errors easier to debug and fixed error from changed exception class\n\n\n* :pr:`3231`: Fixed errors reported by ``flake8``\n\n\n* :pr:`3232`: Upgrade ReadTheDocs build environment to use newer image\n\n\n* :pr:`3286`: Optimized :meth:`.Axes.coords_to_point`\n\n\n* :pr:`3224`: Replace final few occurrences of ``os.path`` by ``pathlib.Path``\n\n\n* :pr:`3236`: Return self in :meth:`.AbstractImageMobject.set_resampling_algorithm`\n\n\n* :pr:`3253`: Bump tornado from 6.3.1 to 6.3.2\n\n\n* :pr:`3272`: Bump docker/build-push-action from 3 to 4\n\n\n* :pr:`3287`: Bump cryptography from 41.0.1 to 41.0.2\n\n\n* :pr:`3350`: Added missing dependency ``typing-extensions``\n\n\n* :pr:`3431`: Bump teatimeguest/setup-texlive-action from 2 to 3\n\n\n* :pr:`3433`: Bump dependencies\n\n\n* :pr:`3399`: Updated several dependencies\n\n\n* :pr:`3397`: Several GitHub actions updates\n\n\n* :pr:`3405`: Updated manimpango version to fix error regarding type strictness\n\n\n* :pr:`3421`: Improved order of input checks when creating a tree graph\n\n\nNew releases\n------------\n\n* :pr:`3439`: Prepared new release: v0.18.0\n"
  },
  {
    "path": "docs/source/changelog/0.18.0.post0-changelog.rst",
    "content": "*************\nv0.18.0.post0\n*************\n\n:Date: April 08, 2024\n\nThis release is a post-release fixing `#3676\n<https://github.com/ManimCommunity/manim/issues/3676>`_, a bug caused by a recent\nchange introduced to the way how SVG files of text are generated by Pango.\n"
  },
  {
    "path": "docs/source/changelog/0.18.1-changelog.md",
    "content": "---\nshort-title: v0.18.1\ndescription: Changelog for Manim v0.18.1\n---\n\n# v0.18.1\n\nDate\n: April 28, 2024\n\n## What's Changed\n\n### Breaking Changes and Deprecations\n\n* Removed deprecated `manim new` command by {user}`chopan050` in {pr}`3512`\n* Removed support for dynamic plugin imports by {user}`Viicos` in {pr}`3524`\n* Remove meth:``.Mobject.wag`` by {user}`JasonGrace2282` in {pr}`3539`\n* Remove deprecated parameters and animations by {user}`JasonGrace2282` in {pr}`3688`\n\n\n### New Features\n\n* Added `cap_style` feature to `VMobject` by {user}`MathItYT` in {pr}`3516`\n* Allow hiding version splash by {user}`jeertmans` in {pr}`3329`\n* Added the ability to pass lists and generators to `Scene.play()` by {user}`MrDiver` in {pr}`3365`\n* Added ``--preview_command`` cli flag by {user}`JasonGrace2282` in {pr}`3615`\n\n### Fixed Bugs and Enhancements\n\n* Allow accessing ghost vectors in :class:`.LinearTransformationScene` by {user}`JasonGrace2282` in {pr}`3435`\n* Optimized `get_unit_normal()` and replaced `np.cross()` with custom `cross()` in `manim.utils.space_ops` by {user}`chopan050` in {pr}`3494`\n* Implement caching of fonts list to improve runtime performance by {user}`MrDiver` in {pr}`3316`\n* Reformatting the `--save_sections` output to have the format `<Scene>_<SecNum>_<SecName><extension>` by {user}`doaamuham` in {pr}`3499`\n* Account for dtype in the pixel array so the maximum value stays correct in the invert function by {user}`jeertmans` in {pr}`3493`\n* Added `grid_lines` attribute to `Rectangle` to add individual styling to the grid lines by {user}`RobinPH` in {pr}`3428`\n* Fixed rectangle grid properties (#3082) by {user}`pauluhlenbruck` in {pr}`3513`\n* Fixed animations with zero runtime length to give a useful error instead of a broken pipe by {user}`MrDiver` in {pr}`3491`\n* Fixed stroke width being ignored by `StreamLines` with a single color by {user}`yashm277` in {pr}`3436`\n* Fixed formatting of ``MoveAlongPath`` docs by {user}`JasonGrace2282` in {pr}`3541`\n* Added helpful hints to `VGroup.add()` error message by {user}`vvolhejn` in {pr}`3561`\n* Made `earclip_triangulation` more robust by {user}`hydromelvictor` in {pr}`3574`\n* Refactored `TexTemplate` by {user}`Viicos` in {pr}`3520`\n* Fixed `write_subcaption_file` error when using OpenGL renderer by {user}`yuan-xy` in {pr}`3546`\n* Fixed `get_arc_center()` returning reference of point by {user}`sparshg` in {pr}`3599`\n* Improved handling of specified font name by {user}`staghado` in {pr}`3429`\n* Fixing the behavior of `.become` to not modify target mobject via side effects fix color linking by {user}`MrDiver` in {pr}`3508`\n* Fixed bug in :class:`.VMobjectFromSVGPath` by {user}`abul4fia` in {pr}`3677`\n* Fix for windows cp1252 encoding failure (fix test pipeline) by {user}`JasonGrace2282` in {pr}`3687`\n* Fix NameError in try... except by {user}`JasonGrace2282` in {pr}`3694`\n* Fix successive calls of :meth:`.LinearTransformationScene.apply_matrix` by {user}`SirJamesClarkMaxwell` in {pr}`3675`\n* Fixed `Mobject.put_start_and_end_on` with same start and end point by {user}`MontroyJosh` in {pr}`3718`\n* Fixed issue where `SpiralIn` doesn't show elements by {user}`Gixtox` in {pr}`3589`\n* Cleaned `Graph` layouts and increase flexibility by {user}`Nikhil-42` in {pr}`3434`\n* `AnimationGroup`: optimized `interpolate()` and fixed alpha bug on `finish()` by {user}`chopan050` in {pr}`3542`\n* Fixed warning about missing plugin `\"\"` by {user}`behackl` in {pr}`3734`\n\n### Documentation\n\n* Typo in `indication` documentation by {user}`jcep` in {pr}`3477`\n* Fixed typo: 360° to 180° in quickstart tutorial by {user}`szchixy` in {pr}`3498`\n* Fixed typo in mobject docstring: `line` -> `square` by {user}`yuan-xy` in {pr}`3509`\n* Explain ``.Transform`` vs ``.ReplacementTransform`` in quickstart examples by {user}`JasonGrace2282` in {pr}`3500`\n* Fixed formatting in building blocks tutorial by {user}`MrDiver` in {pr}`3515`\n* Fixed `Indicate` docstring typo by {user}`Lawqup` in {pr}`3461`\n* Added Documentation to `.to_edge` and `to_corner` by {user}`TheMathematicFanatic` in {pr}`3408`\n* Added some words about Cairo 1.18 by {user}`jeertmans` in {pr}`3530`\n* Fixed typo of `get_y_axis_label` parameter documentation by {user}`yuan-xy` in {pr}`3547`\n* Added note in docstring of `ManimColor` about class constructors by {user}`JasonGrace2282` in {pr}`3554`\n* Improve documentation section about contributing to docs by {user}`chopan050` in {pr}`3555`\n* Removed duplicated documentation for -s / --save_last_frame CLI flag by {user}`Gixtox` in {pr}`3528`\n* Updated Docker instructions to use bash from the PATH by {user}`NotWearingPants` in {pr}`3582`\n* Fixed typo in `value_tracker.py` by {user}`yuan-xy` in {pr}`3594`\n* Added `ref_class` for `BooleanOperations` in Example Gallery by {user}`JasonGrace2282` in {pr}`3598`\n* Changed `Vector3` to `Vector3D` in contributing docs by {user}`JasonGrace2282` in {pr}`3639`\n* Added some examples for `Mobject`/`VMobject` methods by {user}`JasonGrace2282` in {pr}`3641`\n* Fixed broken link to Poetry's installation guide in the documentation by {user}`biinnnggggg` in {pr}`3692`\n* Fixed minor grammatical errors found in the index page of the documentation by {user}`biinnnggggg` in {pr}`3690`\n* Fixed typo on page about translations by {user}`biinnnggggg` in {pr}`3696`\n* Fixed outdated description of CLI option in Manim's Output Settings by {user}`HairlessVillager` in {pr}`3674`\n* Mention pixi in installation guide by {user}`pavelzw` in {pr}`3678`\n* Updated typing guidelines by {user}`JasonGrace2282` in {pr}`3704`\n* Updated documentation and typings for `ParametricFunction` by {user}`danielzsh` in {pr}`3703`\n* Fixed docstring markup in `Rotate` by {user}`TheCrowned` in {pr}`3721`\n* Improve consistency in axis label example by {user}`amrear` in {pr}`3730`\n\n### Maintenance and Testing\n\n* Fixed wrong path in action building downloadable docs by {user}`behackl` in {pr}`3450`\n* Add type hints to `_config` by {user}`Viicos` in {pr}`3440`\n* Update dependency constraints, fix deprecation warnings by {user}`Viicos` in {pr}`3376`\n* Update Docker base image to python3.12-slim (#3458) by {user}`PikaBlue107` in {pr}`3459`\n* Fixed `line_join` to `joint_type` in example_scenes/basic.py by {user}`szchixy` in {pr}`3510`\n* Fixed :attr:`.Mobject.animate` type-hint to allow LSP autocomplete by {user}`JasonGrace2282` in {pr}`3543`\n* Finish TODO's in ``contributing/typings.rst`` by {user}`JasonGrace2282` in {pr}`3545`\n* Fixed use of `Mobject`'s deprecated `get_*()` and `set_*()` methods in Cairo tests by {user}`JasonGrace2282` in {pr}`3549`\n* Added support for Manim type aliases in Sphinx docs and added new TypeAliases by {user}`chopan050` in {pr}`3484`\n* Fixed typing of `Animation` by {user}`dandavison` in {pr}`3568`\n* Added some TODOs for future use of `ManimFrame` by {user}`chopan050` in {pr}`3553`\n* Fixed typehint of :attr:`InternalPoint2D_Array` by {user}`JasonGrace2282` in {pr}`3592`\n* Fixed error in Windows CI pipeline by {user}`behackl` in {pr}`3611`\n* Fixed type hint of indication.py by {user}`yuan-xy` in {pr}`3613`\n* Revert vector type aliases to NumPy ndarrays by {user}`chopan050` in {pr}`3595`\n* Run `poetry lock --no-update` by {user}`JasonGrace2282` in {pr}`3621`\n* Code Cleanup: removing unused imports and global variables by {user}`JasonGrace2282` in {pr}`3620`\n* Fixed type hint of `Vector` direction parameter by {user}`JasonGrace2282` in {pr}`3640`\n* Flake8 rule C901 is about McCabe code complexity by {user}`cclauss` in {pr}`3673`\n* Updated year in license by {user}`JasonGrace2282` in {pr}`3689`\n* Automated copyright updating for docs by {user}`JasonGrace2282` in {pr}`3708`\n* Fixed some typehints in `mobject.py` by {user}`JasonGrace2282` in {pr}`3668`\n* Search for type aliases if TYPE_CHECKING by {user}`JasonGrace2282` in {pr}`3671`\n* Follow-up to graph layout cleanup: improvements for tests and typing by {user}`behackl` in {pr}`3728`\n* GH Actions: Changed from macos-latest to macos-13 by {user}`JasonGrace2282` in {pr}`3729`\n* Fixed return type inconsistency for `get_anchors()` by {user}`JinchuLi2002` in {pr}`3214`\n* Prepared new release: `v0.18.1` by {user}`behackl` in {pr}`3719`\n\n#### Dependency Version Changes\n\n* Bump jupyter-server from 2.9.1 to 2.11.2 by {user}`dependabot` in {pr}`3497`\n* Bump github/codeql-action from 2 to 3 by {user}`dependabot` in {pr}`3567`\n* Bump actions/upload-artifact from 3 to 4 by {user}`dependabot` in {pr}`3566`\n* Bump actions/setup-python from 4 to 5 by {user}`dependabot` in {pr}`3565`\n* updated several packages (pillow, jupyterlab, notebook, jupyterlab-lsp, jinja2, gitpython) by {user}`behackl` in {pr}`3593`\n* Update jupyter.rst by {user}`abul4fia` in {pr}`3630`\n* Bump black from 23.12.1 to 24.3.0 by {user}`dependabot` in {pr}`3649`\n* Bump cryptography from 42.0.0 to 42.0.4 by {user}`dependabot` in {pr}`3629`\n* Bump actions/cache from 3 to 4 by {user}`dependabot` in {pr}`3607`\n* Bump FedericoCarboni/setup-ffmpeg from 2 to 3 by {user}`dependabot` in {pr}`3608`\n* Bump ssciwr/setup-mesa-dist-win from 1 to 2 by {user}`dependabot` in {pr}`3609`\n* Bump idna from 3.6 to 3.7 by {user}`dependabot` in {pr}`3693`\n* Bump pillow from 10.2.0 to 10.3.0 by {user}`dependabot` in {pr}`3672`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci` in {pr}`3332`\n* Updated sphinx deps by {user}`JasonGrace2282` in {pr}`3720`\n\n\n## New Contributors\n* {user}`Lawqup` made their first contribution in {pr}`3461`\n* {user}`jcep` made their first contribution in {pr}`3477`\n* {user}`szchixy` made their first contribution in {pr}`3498`\n* {user}`PikaBlue107` made their first contribution in {pr}`3459`\n* {user}`yuan-xy` made their first contribution in {pr}`3509`\n* {user}`MathItYT` made their first contribution in {pr}`3516`\n* {user}`doaamuham` made their first contribution in {pr}`3499`\n* {user}`RobinPH` made their first contribution in {pr}`3428`\n* {user}`pauluhlenbruck` made their first contribution in {pr}`3513`\n* {user}`yashm277` made their first contribution in {pr}`3436`\n* {user}`TheMathematicFanatic` made their first contribution in {pr}`3408`\n* {user}`vvolhejn` made their first contribution in {pr}`3561`\n* {user}`hydromelvictor` made their first contribution in {pr}`3574`\n* {user}`dandavison` made their first contribution in {pr}`3568`\n* {user}`Gixtox` made their first contribution in {pr}`3528`\n* {user}`staghado` made their first contribution in {pr}`3429`\n* {user}`biinnnggggg` made their first contribution in {pr}`3692`\n* {user}`HairlessVillager` made their first contribution in {pr}`3674`\n* {user}`SirJamesClarkMaxwell` made their first contribution in {pr}`3675`\n* {user}`danielzsh` made their first contribution in {pr}`3703`\n* {user}`TheCrowned` made their first contribution in {pr}`3721`\n* {user}`MontroyJosh` made their first contribution in {pr}`3718`\n* {user}`amrear` made their first contribution in {pr}`3730`\n\n**Full Changelog**: https://github.com/ManimCommunity/manim/compare/v0.18.0.post0...v0.18.1\n"
  },
  {
    "path": "docs/source/changelog/0.19.0-changelog.rst",
    "content": "*******\nv0.19.0\n*******\n\n:Date: January 20, 2025\n\nMajor Changes\n=============\n\nWith the release of Manim v0.19.0, we've made lots of progress with making\nManim easier to install!\n\nOne of the biggest changes in this release is the replacement of the external\n``ffmpeg`` dependency with the ``pyav`` library. This means that users no longer\nhave to install ``ffmpeg`` in order to use Manim - they can just ``pip install manim``\nand it will work!\n\nIn light of this change, we also rewrote our :ref:`installation docs <local-installation>`\nto recommend using a new tool called `uv <https://docs.astral.sh/uv/>`_ to install Manim.\n\n.. note::\n\n   Do not worry if you installed Manim with any previous methods, like homebrew, pip,\n   choco, or scoop. Those methods will still work, and are not deprecated. However,\n   the recommended way to install Manim is now with `uv <https://docs.astral.sh/uv/>`_.\n\nContributors\n============\n\nA total of 54 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Aarush Deshpande\n* Abulafia\n* Achille Fouilleul +\n* Benjamin Hackl\n* CJ Lee +\n* Cameron Burdgick +\n* Chin Zhe Ning\n* Christopher Hampson +\n* ChungLeeCN +\n* Eddie Ruiz +\n* F. Muenkel +\n* Francisco Manríquez Novoa\n* Geoo Chi +\n* Henrik Skov Midtiby +\n* Hugo Chargois +\n* Irvanal Haq +\n* Jay Gupta +\n* Laifsyn +\n* Larry Skuse +\n* Nemo2510 +\n* Nikhil Iyer\n* Nikhila Gurusinghe +\n* Rehmatpal Singh +\n* Romit Mohane +\n* Saveliy Yusufov +\n* Sir James Clark Maxwell\n* Sophia Wisdom +\n* Tristan Schulz\n* VPC +\n* Victorien\n* Xiuyuan (Jack) Yuan +\n* alembcke\n* anagorko +\n* czuzu +\n* fogsong233 +\n* jkjkil4 +\n* modjfy +\n* nitzanbueno +\n* yang-tsao +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Aarush Deshpande\n* Achille Fouilleul\n* Benjamin Hackl\n* Christopher Hampson\n* Eddie Ruiz\n* Francisco Manríquez Novoa\n* Henrik Skov Midtiby\n* Hugo Chargois\n* Irvanal Haq\n* Jay Gupta\n* Jérome Eertmans\n* Nemo2510\n* Nikhila Gurusinghe\n* OliverStrait\n* Saveliy Yusufov\n* Sir James Clark Maxwell\n* Tristan Schulz\n* VPC\n* Victorien\n* Xiuyuan (Jack) Yuan\n* alembcke\n* github-advanced-security[bot]\n\nPull requests merged\n====================\n\nA total of 138 pull requests were merged for this release.\n\nHighlights\n----------\n\n* :pr:`3501`: Replaced external ``ffmpeg`` dependency with ``pyav``\n   This change removes the need to have ``ffmpeg`` available as a command line tool\n   when using Manim. While ``pyav`` technically also uses ``ffmpeg`` internally,\n   the maintainers of ``pyav`` distribute it in their binary wheels.\n\n\n* :pr:`3518`: Created a :class:`.HSV` color class, and added support for custom color spaces\n   This extends the color system of Manim and adds support to implement custom color spaces.\n   See the implementation of :class:`.HSV` for a practical example.\n\n\n* :pr:`3930`: Completely reworked the installation instructions\n   As a consequence of removing the need for the external ``ffmpeg`` dependency,\n   we have reworked and massively simplified the installation instructions. Given\n   that practically, user-written scenes are effectively small self-contained Python\n   projects, the new instructions strongly recommend using the\n   `project and dependency management tool uv <https://docs.astral.sh/uv/>`__ to ensure\n   a consistent and reproducible environment.\n\n\n* :pr:`3967`: Added support for Python 3.13\n   This adds support for Python 3.13, which brings the range of currently supported\n   Python versions to 3.9 -- 3.13.\n\n\n* :pr:`3966`: :class:`.VGroup` can now be initialized with :class:`.VMobject` iterables\n   Groups of Mobjects can now be created by passing an iterable to the :class:`.VGroup`\n   constructors::\n\n      my_group = VGroup(Dot() for _ in range(10))\n\n\nBreaking changes\n----------------\n\n* :pr:`3797`: Replaced ``Code.styles_list`` with :meth:`.Code.get_styles_list`\n   The ``styles_list`` attribute of the :class:`.Code` class has been replaced with\n   a class method :meth:`.Code.get_styles_list`. This method returns a list of all\n   available values for the ``formatter_style`` argument of :class:`.Code`.\n\n\n* :pr:`3884`: Renamed parameters and variables conflicting with builtin functions\n   To avoid having keyword arguments named after builtin functions, the following\n   two changes were made to user-facing functions:\n\n   - ``ManimColor.from_hex(hex=...)`` is now  ``ManimColor.from_hex(hex_str=...)``\n   - ``Scene.next_section(type=...)`` is now ``Scene.next_section(section_type=...)``\n\n\n* :pr:`3922`: Removed ``inner_radius`` and ``outer_radius`` from :class:`.Sector` constructor\n   To construct a :class:`.Sector`, you now need to specify a ``radius`` (and an ``angle``).\n   In particular, :class:`.AnnularSector` still accepts both ``inner_radius`` and ``outer_radius``\n   arguments.\n\n\n* :pr:`3964`: Allow :class:`.SurroundingRectangle` to accept multiple Mobjects\n   This changes the signature of :class:`.SurroundingRectangle` to accept\n   a sequence of Mobjects instead of a single Mobject. As a consequence, other\n   arguments that could be specified as positional ones before now need to be\n   specified as keyword arguments::\n\n      SurroundingRectangle(some_mobject, RED, 0.3)  # raises error now\n      SurroundingRectangle(some_mobject, color=RED, buff=0.3)  # correct usage\n\n\n* :pr:`4115`: Completely rewrite the implementation of the :class:`.Code` mobject\n   This includes several breaking changes to the interface of the class to make it\n   more consistent. See the documentation of :class:`.Code` for a detailed description\n   of the new interface, and the description of the pull request :pr:`4115` for\n   an overview of changes to the old keyword arguments.\n\n\nNew features\n------------\n\n* :pr:`3148`: Added a ``colorscale`` argument to :meth:`.CoordinateSystem.plot`\n\n\n* :pr:`3612`: Add three animations that together simulate a typing animation\n\n\n* :pr:`3754`: Add ``@`` shorthand for :meth:`.Axes.coords_to_point` and :meth:`.Axes.point_to_coords`\n\n\n* :pr:`3876`: Add :meth:`.Animation.set_default` class method\n\n\n* :pr:`3903`: Preserve colors of LaTeX coloring commands\n\n\n* :pr:`3913`: Added :mod:`.DVIPSNAMES` and :mod:`.SVGNAMES` color palettes\n\n\n* :pr:`3933`: Added :class:`.ConvexHull`, :class:`.ConvexHull3D`, :class:`.Label` and :class:`.LabeledPolygram`\n\n\n* :pr:`3992`: Add darker, lighter and contrasting methods to :class:`.ManimColor`\n\n\n* :pr:`3997`: Add a time property to scene (:attr:`.Scene.time`)\n\n\n* :pr:`4039`: Added the ``delay`` parameter to :func:`.turn_animation_into_updater`\n\n\nEnhancements\n------------\n\n* :pr:`3829`: Rewrite :func:`~.bezier.get_quadratic_approximation_of_cubic` to produce smoother animated curves\n\n\n* :pr:`3855`: Log execution time of sample scene in the ``manim checkhealth`` command\n\n\n* :pr:`3888`: Significantly reduce rendering time with a separate thread for writing frames to stream\n\n\n* :pr:`3890`: Better error messages for :class:`.DrawBorderThenFill`\n\n\n* :pr:`3893`: Improve line rendering performance of :class:`.Cylinder`\n\n\n* :pr:`3901`: Changed :attr:`.Square.side_length` attribute to a property\n\n\n* :pr:`3965`: Added the ``scale_stroke`` boolean parameter to :meth:`.VMobject.scale`\n\n\n* :pr:`3974`: Made videos embedded in Google Colab by default\n\n\n* :pr:`3982`: Refactored ``run_time`` validation for :class:`.Animation` and :meth:`.Scene.wait`\n\n\n* :pr:`4017`: Allow animations with ``run_time=0`` and implement convenience :class:`.Add` animation\n\n\n* :pr:`4034`: Draw more accurate circular :class:`.Arc` mobjects for large angles\n\n\n* :pr:`4051`: Add ``__hash__`` method to :class:`.ManimColor`\n\n\n* :pr:`4108`: Remove duplicate declaration of ``__all__`` in :mod:`.vectorized_mobject`\n\n\nOptimizations\n-------------\n\n* :pr:`3760`: Optimize :meth:`.VMobject.pointwise_become_partial`\n\n\n* :pr:`3765`: Optimize :class:`.VMobject` methods which append to ``points``\n\n\n* :pr:`3766`: Created and optimized Bézier splitting functions such as :func:`~.utils.bezier.partial_bezier_points()` in :mod:`manim.utils.bezier`\n\n\n* :pr:`3767`: Optimized :func:`manim.utils.bezier.get_smooth_cubic_bezier_handle_points()`\n\n\n* :pr:`3768`: Optimized :func:`manim.utils.bezier.is_closed`\n\n\n* :pr:`3960`: Optimized :func:`~.bezier.interpolate` and :func:`~.bezier.bezier` in :mod:`manim.utils.bezier`\n\n\n\nFixed bugs\n----------\n\n* :pr:`3706`: Fixed :meth:`.Line.put_start_and_end_on` to use the actual end of an :class:`.Arrow3D`\n\n\n* :pr:`3732`: Fixed infinite loop in OpenGL :meth:`.BackgroundRectangle.get_color`\n\n\n* :pr:`3756`: Fix assertions and improve error messages when adding submobjects\n\n\n* :pr:`3778`: Fixed :func:`.there_and_back_with_pause` rate function behaviour with different ``pause_ratio`` values\n\n\n* :pr:`3786`: Fix :class:`.DiGraph` edges not fading correctly on :class:`.FadeIn` and :class:`.FadeOut`\n\n\n* :pr:`3790`: Fixed the :func:`.get_nth_subpath` function expecting a numpy array\n\n\n* :pr:`3832`: Convert audio files to ``.wav`` before passing to pydub\n\n\n* :pr:`3680`: Fixed behavior of ``config.background_opacity < 1``\n\n\n* :pr:`3839`: Fixed :attr:`.ManimConfig.format` not updating movie file extension\n\n\n* :pr:`3885`: Fixed :meth:`.OpenGLMobject.invert` not reassembling family\n\n\n* :pr:`3951`: Call :meth:`.Animation.finish` for animations in an :class:`.AnimationGroup`\n\n\n* :pr:`4013`: Fixed scene skipping for :attr:`ManimConfig.upto_animation_number` set to 0\n\n\n* :pr:`4089`: Fixed bug with opacity of :class:`.ImageMobject`\n\n\n* :pr:`4091`: Fixed :meth:`.VMobject.add_points_as_corners` to safely handle empty ``points`` parameter\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`3669`: Added a :mod:`manim.typing` guide\n\n\n* :pr:`3715`: Added docstrings to Brace\n\n\n* :pr:`3745`: Underline tag should be ``<u></u>`` in the documentation\n\n\n* :pr:`3818`: Automatically document usages of :class:`typing.TypeVar`\n\n\n* :pr:`3849`: Fix incorrect ``versionadded`` version number in plugin section in docs\n\n\n* :pr:`3851`: Rename ``manim.typing.Image`` type aliases to :class:`.PixelArray` to avoid conflict with ``PIL.Image``\n\n\n* :pr:`3857`: Update installation instructions for MacOS (via dedicated brew formula)\n\n\n* :pr:`3878`: Fixed typehint in ``types.rst`` and replaced outdated reference to ``manim.typing.Image`` with :class:`manim.typing.PixelArray`\n\n\n* :pr:`3924`: Fix ``SyntaxWarning`` when building docs + use Python 3.13 for readthedocs build\n\n\n* :pr:`3958`: Fix: ``.to_edge``'s example demonstration in docs\n\n\n* :pr:`3972`: Refining documentations for :mod:`.moving_camera_scene` module\n\n\n* :pr:`4032`: Bump version and create changelog for ``v0.19.0``\n\n\n* :pr:`4044`: Added support for autodocumenting type aliases that use the ``type`` syntax\n\n\n* :pr:`4065`: Polish documentation of :mod:`.utils.color.core` and remove ``interpolate_array`` function\n\n\n* :pr:`4077`: Update README and documentation landing page, improve way how 3b1b is credited\n\n\n* :pr:`4100`: Add wavy square example to :class:`.Homotopy`\n\n\n* :pr:`4107`: Corrected a typo in the deep dive guide\n\n\n* :pr:`4116`: Fix broken link to Poetry installation in contribution docs\n\n\nType Hints\n----------\n\n* :pr:`3751`: Added typehints to :mod:`manim.utils.iterables`\n\n\n* :pr:`3803`: Added typings to :class:`.OpenGLMobject`\n\n\n* :pr:`3902`: fixed a wrong type hint in :meth:`.Scene.restructure_mobjects`\n\n\n* :pr:`3916`: fixed type hint in :meth:`.DrawBorderThenFill.interpolate_submobject`\n\n\n* :pr:`3926`: Fixed some typehints of :class:`.ParametricFunction`\n\n\n* :pr:`3940`: Fixed ``np.float_`` to ``np.float64`` while using numpy versions above 2.0\n\n\n* :pr:`3961`: Added typehints to :mod:`manim.mobject.geometry`\n\n\n* :pr:`3980`: Added new :class:`.PointND` and :class:`.PointND_Array` type aliases\n\n\n* :pr:`3988`: Added type hints to :mod:`manim.cli` module\n\n\n* :pr:`3999`: Add type annotations to :mod:`manim.utils`\n\n\n* :pr:`4006`: Stopped ignoring :mod:`manim.plugins` errors in ``mypy.ini``\n\n\n* :pr:`4007`: Added typings to :mod:`manim.__main__`\n\n\n* :pr:`4027`: Rename ``InternalPoint3D`` to :class:`~.typing.Point3D`, ``Point3D`` to :class:`~.Point3DLike` and other point-related type aliases\n\n\n* :pr:`4038`: Fixed type hint of :meth:`.Scene.play` to allow :attr:`.Mobject.animate`\n\n\nInternal Improvements and Automation\n------------------------------------\n\n* :pr:`3737`: Fixed action for building downloadable documentation\n\n\n* :pr:`3761`: Use ``--py39-plus`` in pre-commit\n\n\n* :pr:`3777`: Add pyproject for ruff formatting\n\n\n* :pr:`3779`: Switch pre-commit to use ``ruff`` for linting\n\n\n* :pr:`3795`: Replace Pyupgrade with Ruff rule\n\n\n* :pr:`3812`: Fix MacOS LaTeX CI\n\n\n* :pr:`3853`: Change from tempconfig to a config fixture in tests\n\n\n* :pr:`3858`: Update docker to use ENV x=y instead of ENV x y\n\n\n* :pr:`3872`: Use ruff for pytest style\n\n\n* :pr:`3873`: Use ruff instead of flake8-simplify\n\n\n* :pr:`3877`: Fix pre-commit linting\n\n\n* :pr:`3780`: Add Ruff Lint\n\n\n* :pr:`3781`: Ignore Ruff format in git blame\n\n\n* :pr:`3881`: Standardize docstrings with ruff pydocstyle rules\n\n\n* :pr:`3882`: Change flake8-comprehensions and flake8-bugbear to ruff\n\n\n* :pr:`3887`: Fix typo from HSV PR\n\n\n* :pr:`3923`: Use Ruff pygrep rules\n\n\n* :pr:`3925`: Use Github Markdown on README\n\n\n* :pr:`3955`: Use ``subprocess`` instead of ``os.system``.\n\n\n* :pr:`3956`: Set AAC codec for audio in mp4 files, add transcoding utility\n\n\n* :pr:`4069`: Include Noto fonts in Docker image\n\n\n* :pr:`4102`: Remove PT004 from Ruff ignore rules\n\n\nDependencies\n------------\n\n* :pr:`3739`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3746`: Bump tqdm from 4.66.1 to 4.66.3\n\n\n* :pr:`3750`: Bump jinja2 from 3.1.3 to 3.1.4\n\n\n* :pr:`3776`: Bump requests from 2.31.0 to 2.32.0\n\n\n* :pr:`3784`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3794`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3796`: Bump tornado from 6.4 to 6.4.1\n\n\n* :pr:`3801`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3809`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3810`: Bump urllib3 from 2.2.1 to 2.2.2\n\n\n* :pr:`3823`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3827`: Fix docker build\n\n\n* :pr:`3834`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3835`: Bump docker/build-push-action from 5 to 6\n\n\n* :pr:`3841`: Bump certifi from 2024.2.2 to 2024.7.4\n\n\n* :pr:`3844`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3847`: Bump zipp from 3.18.2 to 3.19.1\n\n\n* :pr:`3865`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3880`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3889`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3895`: Lock `poetry.lock`\n\n\n* :pr:`3896`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3904`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3911`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3918`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3929`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`3931`: Bump cryptography from 43.0.0 to 43.0.1\n\n\n* :pr:`3987`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`4023`: Bump tornado from 6.4.1 to 6.4.2\n\n\n* :pr:`4035`: [pre-commit.ci] pre-commit autoupdate\n\n\n* :pr:`4037`: Cap ``pyav`` version\n"
  },
  {
    "path": "docs/source/changelog/0.19.1-changelog.md",
    "content": "---\nshort-title: v0.19.1\ndescription: Changelog for Manim v0.19.1\n---\n\n# v0.19.1\n\nDate\n: December 01, 2025\n\n## What's Changed\n\n### New Features\n\n* Introduce seed in `random_color` method to produce colors deterministically by {user}`ishu9bansal` in {pr}`4265`\n* Add support for arithmetic operators `//`, `%`, `*`, `**` and `/` on `ValueTracker` by {user}`fmuenkel` in {pr}`4351`\n* Add `TangentialArc` mobject by {user}`Brainsucker92` in {pr}`4469`\n\n\n### Fixed Bugs and Enhancements\n\n* Fix environment formatting for Tex() mobject by {user}`fmuenkel` in {pr}`4159`\n* Improved consistency of rate_function implementations by {user}`BenKirkels` in {pr}`4144`\n* Make new `Code` mobject compatible with OpenGL renderer by {user}`behackl` in {pr}`4164`\n* Fix HSL color ordering in ManimColor by {user}`thehugwizard` in {pr}`4202`\n* Fix return type of `Polygram.get_vertex_groups()` and rename variables in `.round_corners()` by {user}`chopan050` in {pr}`4063`\n* Improve `Mobject.align_data` docstring by {user}`irvanalhaq9` in {pr}`4152`\n* Fix :meth:`VMobject.pointwise_become_partial` failing when `vmobject` is `self` by {user}`irvanalhaq9` in {pr}`4193`\n* Fix `add_points_as_corners` not connecting single point to existing path by {user}`irvanalhaq9` in {pr}`4219`\n* Complete typing for logger_utils.py by {user}`fmuenkel` in {pr}`4134`\n* Fix(graph): Allow any Line subclass as edge_type in Graph/DiGraph by {user}`Akshat-Mishra-py` in {pr}`4251`\n* Replace exceptions, remove unused parameters, and fix type hints in `Animation`, `ShowPartial`, `Create`, `ShowPassingFlash`, and `DrawBorderThenFill` by {user}`irvanalhaq9` in {pr}`4214`\n* Fix: `Axes` submobject colors are not being set properly by {user}`ishu9bansal` in {pr}`4291`\n* Refactor `Rotating` and add docstrings to `Mobject.rotate()` and `Rotating` by {user}`irvanalhaq9` in {pr}`4147`\n* Fix default config of `manim init project` to use correct `pixel_height` and `pixel_width` by {user}`StevenH34` in {pr}`4213`\n* Handle opacity and transparent images by {user}`henrikmidtiby` in {pr}`4313`\n* Gracefully fall back when version metadata is missing by {user}`mohiuddin-khan-shiam` in {pr}`4324`\n* Fix for issue 4255 - Do not clear points when the number of curves is zero by {user}`henrikmidtiby` in {pr}`4320`\n* Use utf-8 encoding to read generated .tex files. by {user}`OliverStrait` in {pr}`4334`\n* Add zero to vmobject points to remove negative zeros in `get_mobject_key` by {user}`elshorbagyx` in {pr}`4332`\n* Ensure `stroke_width` attribute of `SVGMobject` is not set to `None` by {user}`henrikmidtiby` in {pr}`4319`\n* Fix `Prism` incorrectly rendering with `dimensions=[2, 2, 2]` in OpenGL by {user}`ra1u` in {pr}`4003`\n* Fix `BraceLabel.change_label()` and document `BraceText` by {user}`henrikmidtiby` in {pr}`4347`\n* Include `Text.gradient` in hash to properly regenerate `Text` when its gradient changes by {user}`AbhilashaTandon` in {pr}`4099`\n* Fixed surface animations in OpenGL by {user}`nubDotDev` in {pr}`4286`\n* Add type hints and support for arithmetic operators `+` and `-` on `ValueTracker` by {user}`fmuenkel` in {pr}`4129`\n* Fix duplicate references in `Scene.mobjects` after `ReplacementTransform` with existing target mobject by {user}`irvanalhaq9` in {pr}`4242`\n* Optimize `always_redraw()` by reducing `Mobject` copying in `Mobject.become()` by {user}`chopan050` in {pr}`4357`\n* Enhance `manim cfg show` output and add info-level logging for config files read  by {user}`xnov18` in {pr}`4375`\n* Let `Cube` use Bevel type line joints by {user}`nubDotDev` in {pr}`4361`\n* Properly define `init_points` methods for use in OpenGL instead of defining `init_points = generate_points` by {user}`chopan050` in {pr}`4360`\n* Allow passing a tuple to `buff` in `SurroundingRectangle` to specify buffer in x and y direction independently by {user}`nubDotDev` in {pr}`4390`\n* Rewrite `color_gradient` to always return a list of ManimColors by {user}`henrikmidtiby` in {pr}`4380`\n* Ensure leading whitespace does not change line height for lines in CodeMobject by {user}`behackl` in {pr}`4392`\n* Simplify the function `remove_invisible_chars` in `text_mobject.py` by {user}`henrikmidtiby` in {pr}`4394`\n* Fix some config options specified via `--config_file` not being respected properly by {user}`behackl` in {pr}`4401`\n* Fix: Correct resolution tuple order to (height, width) by {user}`Nikhil172913832` in {pr}`4440`\n* Ensure that start and end points are stored as float values in Line3D by {user}`SirJamesClarkMaxwell` in {pr}`4080`\n* OpenGL: Fix iterated nesting in `DecimalNumber.set_value` by {user}`henrikmidtiby` in {pr}`4373`\n* Update default resolution in CLI to match Manim’s 1920x1080 default settings by {user}`SASHAKT1290` in {pr}`4452`\n* Better parsing of color styles in CodeMobject by {user}`SirJamesClarkMaxwell` in {pr}`4454`\n* Allow selection of all scenes to render using '*' by {user}`NightyStudios` in {pr}`4470`\n* Prevent mutation of `about_point` in `apply_points_function_about_point` by {user}`Morkunas` in {pr}`4478`\n* Fix behavior of `Mobject.suspend_updating`: when only suspending parent mobject, let children continue updating by {user}`behackl` in {pr}`4402`\n* Allow passing a `buff` to `LabeledDot` by {user}`nubDotDev` in {pr}`4403`\n* Pass ndarrays to `mapbox_earcut.triangulate_float32()` to fix `TypeError` in `mapbox_earcut==2.0.0` by {user}`GuiCT` in {pr}`4479`\n* Fix duplicated arrow tips in DashedVMobject (issue #3220) by {user}`jakekinchen` in {pr}`4484`\n\n\n### Documentation\n\n* Add docstring to :meth:`.Mobject.get_family` by {user}`irvanalhaq9` in {pr}`4127`\n* Fix link formatting and clarify the distinction between Manim versions in index.rst by {user}`irvanalhaq9` in {pr}`4131`\n* Add instructions for installing system utilities `cairo` and `pkg-config` via Homebrew on MacOS by {user}`behackl` in {pr}`4146`\n* Add missing line break in Code of Conduct's conflict of interest policy by {user}`Hasan-Mesbaul-Ali-Taher` in {pr}`4185`\n* Fix links to Pango website by {user}`ragibson` in {pr}`4217`\n* Replace poetry with uv in the README by {user}`xinoehp512` in {pr}`4226`\n* Improve docstring for `interpolate` method in `Mobject` class by {user}`irvanalhaq9` in {pr}`4149`\n* Add docstrings to `Line` and remove `None` handling for `path_arc` parameter by {user}`irvanalhaq9` in {pr}`4223`\n* Add docstring to :meth:`Mobject.family_members_with_points` by {user}`irvanalhaq9` in {pr}`4128`\n* Update incorrect docstring for :attr:`ManimConfig.gui_location` property by {user}`SAYAN02-DEV` in {pr}`4254`\n* Fix formatting of color space documentation by {user}`behackl` in {pr}`4274`\n* Enhance and Paraphrase Description of ManimCE in README.md by {user}`irvanalhaq9` in {pr}`4141`\n* docs: add explanation about the rate_func in the custom animation by {user}`pedropxoto` in {pr}`4278`\n* Fixed artifact in docstring of Animation by {user}`barollet` in {pr}`4283`\n* Rename update function `dot_position` to `update_label` in `.add_updater` example by {user}`irvanalhaq9` in {pr}`4196`\n* Fix Microsoft typo in `TexFontTemplateLibrary` scene in `example_scenes/advanced_tex_fonts.py` by {user}`alterdim` in {pr}`4305`\n* Improved readability, grammar, as well as added docstrings for consistency  by {user}`NASAnerd05` in {pr}`4267`\n* Add docstrings for `ChangingDecimal` and `ChangeDecimalToValue` by {user}`haveheartt` in {pr}`4346`\n* Fix Sphinx exceptions when trying to build documentation via latex / as pdf by {user}`behackl` in {pr}`4370`\n* Added license information to documentation landing page by {user}`Nikil-D-Gr8` in {pr}`3986`\n* Set the default Python version to 3.13 in the uv installation guide by {user}`henrikmidtiby` in {pr}`4480`\n\n\n### Maintenance and Testing\n\n* Change project management tool from poetry to uv by {user}`behackl` in {pr}`4138`\n* Re-add ffmpeg as dependency within Docker image by {user}`behackl` in {pr}`4150`\n* Add tests for Matrix, DecimalMatrix, IntegerMatrix by {user}`pdrzan` in {pr}`4279`\n* Add tests for polylabel utility by {user}`giolucasd` in {pr}`4269`\n* Add support for `pycodestyle W` rule in Ruff by {user}`KaiqueDultra` in {pr}`4276`\n* Fix files with few MyPy typing errors by {user}`henrikmidtiby` in {pr}`4263`\n* Explicitly mention all files that mypy should ignore in the `mypy.ini` configuration file by {user}`henrikmidtiby` in {pr}`4306`\n* Remove dead code from `scene.py` and `vector_space_scene.py` by {user}`henrikmidtiby` in {pr}`4310`\n* Add type annotations to `scene.py` and `vector_space_scene.py` by {user}`henrikmidtiby` in {pr}`4260`\n* Replace setup-texlive-action in CI workflow by {user}`behackl` in {pr}`4326`\n* Adding type annotations to polyhedra.py and matrix.py by {user}`henrikmidtiby` in {pr}`4322`\n* Handling typing errors in text/numbers.py by {user}`henrikmidtiby` in {pr}`4317`\n* Move `configure_pygui` into a `Scene` method and remove `manim.gui` by {user}`chopan050` in {pr}`4314`\n* Add typing annotations to svg_mobject.py by {user}`henrikmidtiby` in {pr}`4318`\n* Add type annotations to `mobject/svg/brace.py` and default to `label_constructor=Text` in `BraceText` by {user}`henrikmidtiby` in {pr}`4309`\n* Add classes `MethodWithArgs`, `SceneInteractContinue` and `SceneInteractRerun` inside new module `manim.data_structures` by {user}`chopan050` in {pr}`4315`\n* Fix typo in import of OpenGLCamera in `utils/hashing.py` by {user}`fmuenkel` in {pr}`4352`\n* Add type annotations to `manim/renderer/shader.py` by {user}`henrikmidtiby` in {pr}`4350`\n* Add type annotations to `tex_mobject.py` by {user}`henrikmidtiby` in {pr}`4355`\n* Add type annotations to `three_d_camera.py` by {user}`henrikmidtiby` in {pr}`4356`\n* Revert change of default value for tex_environment by {user}`henrikmidtiby` in {pr}`4358`\n* Add type hints to `scene_file_writer.py`, `section.py`, and `zoomed_scene.py` by {user}`fmuenkel` in {pr}`4133`\n* Add type annotations for most of `camera` and `mobject.graphing` by {user}`henrikmidtiby` in {pr}`4125`\n* Add `VectorNDLike` type aliases by {user}`chopan050` in {pr}`4068`\n* Add type annotations to `dot_cloud.py`, `vectorized_mobject_rendering.py` and `opengl_three_dimensions.py` by {user}`henrikmidtiby` in {pr}`4359`\n* Add type annotations to `indication.py` by {user}`henrikmidtiby` in {pr}`4367`\n* Add type annotations to `composition.py` by {user}`henrikmidtiby` in {pr}`4366`\n* Add type annotations to `growing.py` by {user}`henrikmidtiby` in {pr}`4368`\n* Add type annotations to `movement.py` by {user}`henrikmidtiby` in {pr}`4371`\n* Exclude check for cyclic imports by CodeQL by {user}`behackl` in {pr}`4384`\n* Refactor imports from `collections.abc`, `typing` and `typing_extensions` for Python 3.9 by {user}`chopan050` in {pr}`4353`\n* Add type annotations to `opengl_renderer_window.py` by {user}`fmuenkel` in {pr}`4363`\n* Rename `SceneFileWriter.save_final_image()` to `save_image()` by {user}`fmuenkel` in {pr}`4378`\n* Add type annotations to `text_mobject.py` by {user}`henrikmidtiby` in {pr}`4381`\n* Rename types like `RGBA_Array_Float` to `FloatRGBA` and add types like `FloatRGBA_Array` by {user}`chopan050` in {pr}`4386`\n* Add type annotations to `opengl_geometry.py` by {user}`henrikmidtiby` in {pr}`4396`\n* Add type annotations to `moving_camera.py` by {user}`henrikmidtiby` in {pr}`4397`\n* Add type annotations to `opengl_mobject.py` by {user}`RBerga06` in {pr}`4398`\n* Fix failing pre-commit tests by {user}`cclauss` in {pr}`4434`\n* Add type annotations to  `cairo_renderer.py` by {user}`fmuenkel` in {pr}`4393`\n* Fix type errors and add typings for `Mobject.apply_function()`, its derivatives, and other utility functions by {user}`godalming123` in {pr}`4228`\n* Bump macOS image from deprecated macos-13 to macos-15-intel by {user}`chopan050` in {pr}`4481`\n* Prepare new release `v0.19.1` and bump minimum required Python version to 3.10 by {user}`behackl` in {pr}`4490`\n\n\n### Dependency Version Changes\n\n* Bump typing extensions minimum version by {user}`JasonGrace2282` in {pr}`4121`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4122`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4140`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4148`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4181`\n* Bump astral-sh/setup-uv from 5 to 6 by {user}`dependabot`[bot] in {pr}`4234`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4204`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4391`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4405`\n* Bump actions/setup-python from 5 to 6 by {user}`dependabot`[bot] in {pr}`4433`\n* Bump actions/checkout from 4 to 5 by {user}`dependabot`[bot] in {pr}`4418`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4409`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4460`\n* [pre-commit.ci] pre-commit autoupdate by {user}`pre-commit-ci`[bot] in {pr}`4467`\n* Bump github/codeql-action from 3 to 4 by {user}`dependabot`[bot] in {pr}`4466`\n* Bump astral-sh/setup-uv from 6 to 7 by {user}`dependabot`[bot] in {pr}`4465`\n* Bump actions/upload-artifact from 4 to 5 by {user}`dependabot`[bot] in {pr}`4464`\n\n\n## New Contributors\n* {user}`BenKirkels` made their first contribution in {pr}`4144`\n* {user}`Hasan-Mesbaul-Ali-Taher` made their first contribution in {pr}`4185`\n* {user}`ragibson` made their first contribution in {pr}`4217`\n* {user}`thehugwizard` made their first contribution in {pr}`4202`\n* {user}`xinoehp512` made their first contribution in {pr}`4226`\n* {user}`SAYAN02-DEV` made their first contribution in {pr}`4254`\n* {user}`Akshat-Mishra-py` made their first contribution in {pr}`4251`\n* {user}`pdrzan` made their first contribution in {pr}`4279`\n* {user}`pedropxoto` made their first contribution in {pr}`4278`\n* {user}`giolucasd` made their first contribution in {pr}`4269`\n* {user}`KaiqueDultra` made their first contribution in {pr}`4276`\n* {user}`ishu9bansal` made their first contribution in {pr}`4291`\n* {user}`StevenH34` made their first contribution in {pr}`4213`\n* {user}`alterdim` made their first contribution in {pr}`4305`\n* {user}`mohiuddin-khan-shiam` made their first contribution in {pr}`4324`\n* {user}`elshorbagyx` made their first contribution in {pr}`4332`\n* {user}`NASAnerd05` made their first contribution in {pr}`4267`\n* {user}`ra1u` made their first contribution in {pr}`4003`\n* {user}`AbhilashaTandon` made their first contribution in {pr}`4099`\n* {user}`nubDotDev` made their first contribution in {pr}`4286`\n* {user}`haveheartt` made their first contribution in {pr}`4346`\n* {user}`xnov18` made their first contribution in {pr}`4375`\n* {user}`Nikil-D-Gr8` made their first contribution in {pr}`3986`\n* {user}`RBerga06` made their first contribution in {pr}`4398`\n* {user}`Nikhil172913832` made their first contribution in {pr}`4440`\n* {user}`SASHAKT1290` made their first contribution in {pr}`4452`\n* {user}`Brainsucker92` made their first contribution in {pr}`4469`\n* {user}`NightyStudios` made their first contribution in {pr}`4470`\n* {user}`Morkunas` made their first contribution in {pr}`4478`\n* {user}`GuiCT` made their first contribution in {pr}`4479`\n* {user}`godalming123` made their first contribution in {pr}`4228`\n* {user}`jakekinchen` made their first contribution in {pr}`4484`\n\n**Full Changelog**: https://github.com/ManimCommunity/manim/compare/v0.19.0...v0.19.1\n"
  },
  {
    "path": "docs/source/changelog/0.19.2-changelog.md",
    "content": "---\nshort-title: v0.19.2\ndescription: Changelog for Manim v0.19.2\n---\n\n# v0.19.2\n\nDate\n: January 17, 2026\n\n\n## What's Changed\n### Highlights 🌟\n* Add support for Python 3.14, bump minimum Python to 3.11 and av to 14.0.1 by {user}`behackl` in {pr}`4385`\n\n### Bug Fixes 🐛\n* Fix argument passed to `get_hash_from_play_call` in hashing by {user}`judenimo` in {pr}`4524`\n* Fix incorrect `Circle.point_at_angle` calculation by {user}`Swarnlataaa` in {pr}`4438`\n\n### Testing 🧪\n* Test on Apple Silicon ARM64 by {user}`cclauss` in {pr}`4496`\n\n### Code Quality & Refactoring 🧹\n* Add ruff rules PERF for performance by {user}`cclauss` in {pr}`4492`\n* Remove deprecation warning from pytest \"np.trapz\" -> \"np.trapezoid\" by {user}`henrikmidtiby` in {pr}`4513`\n* Bump Python target versions of both mypy and ruff by {user}`behackl` in {pr}`4520`\n* Replace legacy numpy usage -- ruff rule NPY002 by {user}`cclauss` in {pr}`4516`\n* Add `.github/release.yml` for improved classifications in automatically generated changelogs by {user}`behackl` in {pr}`4526`\n* Check and bump lower version requirements for dependencies by {user}`henrikmidtiby` in {pr}`4529`\n\n### Type Hints 📝\n* Add type annotations to `three_dimensions.py` by {user}`henrikmidtiby` in {pr}`4497`\n\n### Other Changes\n* Prepare new release `v0.19.2` by {user}`behackl` in {pr}`4528`\n\n## New Contributors\n* {user}`judenimo` made their first contribution in {pr}`4524`\n* {user}`Swarnlataaa` made their first contribution in {pr}`4438`\n\n**Full Changelog**: https://github.com/ManimCommunity/manim/compare/v0.19.1...v0.19.2\n"
  },
  {
    "path": "docs/source/changelog/0.2.0-changelog.rst",
    "content": "******\nv0.2.0\n******\n\n:Date: January 1, 2021\n\nThe changes since Manim Community release v0.1.1 are listed below.\n\nBreaking Changes\n================\n\n- Remove all CONFIG dictionaries and all calls to ``digest_config`` and allow\n  passing options directly to the constructor of the corresponding classes (:pr:`783`).\n\n  Practically, this means that old constructions using ``CONFIG`` like::\n\n      class SomeMobject(Thing):\n          CONFIG = {\n              \"my_awesome_property\": 42\n          }\n\n  where corresponding objects were then instantiated as ``my_mobject = SomeMobject()``\n  should now be created simply using ``my_mobject = SomeMobject(my_awesome_property=42)``.\n\n- Remove old syntax for animating mobject methods by passing the methods and arguments to ``self.play``,\n  and use a new syntax featuring the ``animate`` property (:pr:`881`).\n\n  For example: the old-style ``play`` call\n  ::\n\n      self.play(my_square.shift, LEFT)\n\n  should be replaced with the new following call using the ``animate`` property::\n\n      self.play(my_square.animate.shift(LEFT))\n\nNew Features\n============\n\n- Added creation animation for :class:`~.ManimBanner` (:pr:`814`)\n- Added some documentation to :meth:`~.Scene.construct` (:pr:`753`)\n- Added a black and white monochromatic version of Manim's logo (:pr:`826`)\n- Added support for a plugin system (``manim plugin`` subcommand + documentation) (:pr:`784`)\n- Implemented ``__add__``, ``__iadd__``, ``__sub__``, and ``__isub__`` for :class:`~.Mobject` (allowing for notation like ``some_vgroup + some_mobject``) (:pr:`790`)\n- Added type hints to several files in the library (:pr:`835`)\n- Added some examples to :mod:`~.animation.creation` (:pr:`820`)\n- Added some examples to :class:`~.DashedLine` and :class:`~.CurvesAsSubmobjects` (:pr:`833`)\n- Added new implementation for text rendered with Pango, :class:`~.MarkupText`, which can be formatted with an HTML-like syntax (:pr:`855`)\n- Added Fading in and out examples and deprecation of ``FadeInFromDown`` and ``FadeOutAndShiftDown`` (:pr:`827`)\n- Added example for :class:`~.MoveAlongPath` to the docs (:pr:`873`)\n- Added ambient rotate for other angles - theta, phi, gamma (:pr:`660`)\n- Use custom bindings for Pango (:pr:`878`)\n- Added :class:`~.Graph`, a basic implementation for (graph theory) graphs (:pr:`861`)\n- Allow for chaining methods when using the new ``.animate`` syntax in :meth:`~.Scene.play` (:pr:`889`)\n\nBugfixes\n========\n\n- Fix doctests in .rst files (:pr:`797`)\n- Fix failing doctest after adding ``manim plugin`` subcommand (:pr:`831`)\n- Normalize the direction vector in :meth:`~.mobject_update_utils.always_shift` (:pr:`839`)\n- Add ``disable_ligatures`` to :class:`~.Text` (via :pr:`804`)\n- Make scene caching aware of order of Mobjects (:pr:`845`)\n- Fix :class:`~.CairoText` to work with new config structure (:pr:`858`)\n- Added missing argument to classes inheriting from :class:`~.Matrix` (:pr:`859`)\n- Fixed: ``z_index`` of mobjects contained in others as submobjects is now properly respected (:pr:`872`)\n- Let :meth:`~.ParametricSurface.set_fill_by_checkboard` return the modified surface to allow method chaining (:pr:`883`)\n- Mobjects added during an updater are added to ``Scene.moving_mobjects`` (:pr:`838`)\n- Pass background color to JS renderer (:pr:`876`)\n- Small fixes to docstrings. Tiny cleanups. Remove ``digest_mobject_attrs``. (:pr:`834`)\n- Added closed shape detection in :class:`~.DashedVMobject` in order to achieve an even dash pattern (:pr:`884`)\n- Fix Spelling in docstrings and variables across the library (:pr:`890`)\n\nOther changes\n=============\n\n- Change library name to manim (:pr:`811`)\n- Docker: use local files when building an image (:pr:`803`)\n- Let ffmpeg render partial movie files directly instead of temp files (:pr:`817`)\n- ``manimce`` to ``manim`` & capitalizing Manim in readme (:pr:`794`)\n- Added flowchart for different docstring categories (:pr:`828`)\n- Improve example in module docstring of :mod:`~.animation.creation` + explicitly document buff parameter in :meth:`~.Mobject.arrange` (:pr:`825`)\n- Disable CI pipeline for Python 3.6 (:pr:`823`)\n- Update URLs in docs (:pr:`832`)\n- Move upcoming changelog to GitHub-wiki (:pr:`822`)\n- Change badges in readme (:pr:`854`)\n- Exclude generated gRPC files from source control (:pr:`868`)\n- Added linguist-generated attribute to ``.gitattributes`` (:pr:`877`)\n- Cleanup: removed inheritance from ``object`` for some classes, refactor some imports (:pr:`795`)\n- Change several ``str.format()`` to ``f``-strings (:pr:`867`)\n- Update javascript renderer (:pr:`830`)\n- Bump version number to 0.2.0, update changelog (:pr:`894`)\n"
  },
  {
    "path": "docs/source/changelog/0.20.0-changelog.md",
    "content": "---\nshort-title: v0.20.0\ndescription: Changelog for v0.20.0\n---\n\n# v0.20.0\n\nDate\n: February 20, 2026\n\n\n## What's Changed\n### Breaking Changes 🚨\n* Fix `ImageMobject` 3D rotation/flipping and remove resampling algorithms `lanczos` (`antialias`), `box` and `hamming` by {user}`chopan050` in {pr}`4266`\n* Fix `YELLOW_C` and add `PURE_CYAN`, `PURE_MAGENTA` and `PURE_YELLOW` by {user}`chopan050` in {pr}`4562`\n\n### Highlights 🌟\n* Rewrite MathTex to make it more robust regarding splitting by {user}`henrikmidtiby` in {pr}`4515`\n\n  The MathTex implementation has been updated to make it more robust and fix a number of issues.\n  A beneficial side effect is that named groups in svg files can now be accessed through SVGMobject.\n\n* Add new Animation Builder `Mobject.always` by {user}`JasonGrace2282` in {pr}`4594`\n\n  This new feature is a convenience wrapper around `add_updater` that allows adding\n  updaters to a mobject in an intuitive and easy-to-read way. Example usage in a scene:\n  ```python\n  d = Dot()\n  s = Square()\n  d.always.next_to(s, UP)\n  self.add(s, d)\n  self.play(s.animate.to_edge(LEFT))\n  ```\n\n\n### New Features ✨\n* Add a `seed` config option + `--seed` CLI option for reproducible randomness in rendered scenes by {user}`arnaud-ma` in {pr}`4532`\n\n### Enhancements 🚀\n* Enable `strict=True` for `zip()` where safe  by {user}`Oll-iver` in {pr}`4547`\n\n### Bug Fixes 🐛\n* using `color` instead of `fill_color` with MathTeX for node labels by {user}`Schefflera-Arboricola` in {pr}`4501`\n* fix: infinite recursion caused by accessing color of a highlighted Ta… by {user}`BHearron` in {pr}`4435`\n* Prevent potential `UnboundLocalError` in `PolarPlane` by {user}`RinZ27` in {pr}`4557`\n* Fixed division by 0 in `turn_animation_into_updater` by {user}`SoldierSacha` in {pr}`4567`\n* Fix TOCTOU Race Conditions when creating directories by {user}`SoldierSacha` in {pr}`4587`\n* Resolve more race conditions potentially happening during directory creation by {user}`SoldierSacha` in {pr}`4589`\n* Fix `c2p`/`coords_to_point` method call with single flat list or 1D array input by {user}`danielalanbates` in {pr}`4596`\n\n### Documentation 📚\n* Enable rendered documentation of `RandomColorGenerator` by {user}`arnaud-ma` in {pr}`4533`\n* Remove pin to Python 3.13 in installation docs by {user}`chopan050` in {pr}`4534`\n* Fix broken aquabeam OpenGL link using Wayback Machine by {user}`behackl` in {pr}`4545`\n* Add type annotations and docstrings in `opengl_renderer.py` by {user}`arnaud-ma` in {pr}`4537`\n* docs: improve `TransformFromCopy` docstring by {user}`GoThrones` in {pr}`4597`\n\n### Infrastructure & Build 🔨\n* Install missing dependencies in release pipeline by {user}`behackl` in {pr}`4531`\n\n### Code Quality & Refactoring 🧹\n* Rework and consolidate release changelog script, add previously skipped changelog entries by {user}`behackl` in {pr}`4568`\n* Remove `__future__.annotations` from required imports by {user}`JasonGrace2282` in {pr}`4571`\n* Cleaned up `mypy.ini` by {user}`henrikmidtiby` in {pr}`4584`\n* Add `py.typed` to declare manim as having type hints by {user}`Timmmm` in {pr}`4553`\n* Fix assertion in `ImageMobjectFromCamera.interpolate_color()` by {user}`chopan050` in {pr}`4593`\n* Reduce dependency on scipy - replace `scipy.special.comb` with `math.comb` by {user}`fmuenkel` in {pr}`4598`\n\n### Type Hints 📝\n* Add type annotations to `rotation.py` by {user}`fmuenkel` in {pr}`4535`\n* Add type annotations to `opengl_compatibility.py` by {user}`fmuenkel` in {pr}`4585`\n* Add type annotations to `image_mobject.py` by {user}`henrikmidtiby` in {pr}`4458`\n* Add type annotations to `opengl_image_mobject.py` by {user}`fmuenkel` in {pr}`4536`\n* Add type annotations to `point_cloud_mobject.py` by {user}`fmuenkel` in {pr}`4586`\n\n## New Contributors\n* {user}`arnaud-ma` made their first contribution in {pr}`4533`\n* {user}`Schefflera-Arboricola` made their first contribution in {pr}`4501`\n* {user}`BHearron` made their first contribution in {pr}`4435`\n* {user}`RinZ27` made their first contribution in {pr}`4557`\n* {user}`SoldierSacha` made their first contribution in {pr}`4567`\n* {user}`Oll-iver` made their first contribution in {pr}`4547`\n* {user}`GoThrones` made their first contribution in {pr}`4597`\n* {user}`danielalanbates` made their first contribution in {pr}`4596`\n\n**Full Changelog**: [Compare view](https://github.com/ManimCommunity/manim/compare/v0.19.2...v0.20.0)\n"
  },
  {
    "path": "docs/source/changelog/0.20.1-changelog.md",
    "content": "---\nshort-title: v0.20.1\ndescription: Changelog for v0.20.1\n---\n\n# v0.20.1\n\nDate\n: February 27, 2026\n\n\n## What's Changed\n### Enhancements 🚀\n* Cleanup `TipableVMobject`: avoid mutable default and fix `assign_tip_attr` typo by {user}`josiest` in {pr}`4503`\n* enhancement: optimize Docker image build and runtime footprint by {user}`behackl` in {pr}`4604`\n\n### Bug Fixes 🐛\n* fix: MathTex double-brace splitting no longer fires on natural LaTeX `}}` by {user}`behackl` in {pr}`4602`\n* Fix creation or animation of a zero-length `DashedLine` by {user}`SORVER` in {pr}`4606`\n* Fix moving-object detection for nested AnimationGroups with z-indexed mobjects by {user}`Merzlikin-Matvey` in {pr}`4389`\n* Fix unintended propagation of `kwargs` in `LaggedStartMap` by {user}`irvanalhaq9` in {pr}`4613`\n\n### Documentation 📚\n* Documentation: manual installation of manim as a local package by {user}`u7920349` in {pr}`4456`\n* Add alt text to all images in `README.md` by {user}`VerisimilitudeX` in {pr}`4064`\n\n### Code Quality & Refactoring 🧹\n* Fix publish release workflow by {user}`behackl` in {pr}`4600`\n* Silence pydub ffmpeg/avconv import warning when ffmpeg CLI is absent by {user}`behackl` in {pr}`4603`\n\n### Type Hints 📝\n* Add type annotations to `manim/_config/utils.py` by {user}`henrikmidtiby` in {pr}`4230`\n\n## New Contributors\n* {user}`SORVER` made their first contribution in {pr}`4606`\n* {user}`josiest` made their first contribution in {pr}`4503`\n* {user}`u7920349` made their first contribution in {pr}`4456`\n* {user}`Merzlikin-Matvey` made their first contribution in {pr}`4389`\n* {user}`VerisimilitudeX` made their first contribution in {pr}`4064`\n\n**Full Changelog**: [Compare view](https://github.com/ManimCommunity/manim/compare/v0.20.0...v0.20.1)\n"
  },
  {
    "path": "docs/source/changelog/0.3.0-changelog.rst",
    "content": "******\nv0.3.0\n******\n\n:Date: February 1, 2021\n\nThe changes since Manim Community release v0.2.0 are listed below.\n\n\nNew Features\n============\n\n- :pr:`945`: :meth:`~.Graph.change_layout` method for :class:`~.Graph` mobject\n- :pr:`943`: IPython %%manim magic\n- :pr:`970`: Added ``--version`` command line flag\n- :pr:`948`: Allow passing a code string to :class:`~.Code`\n- :pr:`917`: Allow overriding new-style method animations\n- :pr:`756`: Allow setting frame_height and frame_width via config file\n- :pr:`939`: Added custom font files support\n- :pr:`892`: Added ManimCommunity colors\n- :pr:`922`: Tree layout for Graph mobject\n- :pr:`935`: Added code of conduct\n- :pr:`916`: Multi-column layout for partite graphs\n- :pr:`742`: Units: Pixels, Munits, Percent in :mod:`~.utils.unit`\n- :pr:`893`: Convenience method :meth:`~.Graph.from_networkx` for creating a graph from a networkx graph\n\nBugfixes and Enhancements\n=========================\n\n- :pr:`988`: Fix Windows CI pipeline by adding missing LaTeX package\n- :pr:`961`: Added typings and docs for vectorized mobjects and bezier related functions\n- :pr:`977`: JupyterLab docker image and documentation for manim and IPython\n- :pr:`985`: Fix variable name for webgl renderer\n- :pr:`954`: Fix edges lagging behind vertices in animations of graphs\n- :pr:`980`: Allow usage of custom Pygments styles in Code\n- :pr:`952`: Allow passing tween information to the WebGL frontend\n- :pr:`978`: Fix ``possible_paths`` not printing in ``code_mobject``\n- :pr:`976`: Update ``ManimPango``\n- :pr:`967`: Automatically import plugins\n- :pr:`971`: Make ManimCommunity look consistent\n- :pr:`957`: Raise ``NotImplementedError`` when trying to chain overridden method animations\n- :pr:`947`: Several fixes and improvements for :class:`~.PointCloundDot`\n- :pr:`923`: Documentation: move installation instructions for developers to page for developers\n- :pr:`964`: Added unit test for :class:`~.NumberLine`'s unit vector\n- :pr:`960`: Magnitude of :class:`~.NumberLine`'s unit vector should be ``unit_size``, not 1\n- :pr:`958`: Fix code formatting in ``utils/debug.py``\n- :pr:`953`: Update license year\n- :pr:`944`: Interpolate stroke opacity in :class:`~.FadeIn` and update ``stroke_opacity`` and ``fill_opacity`` in :meth:`~.VMobject.set_stroke` and :meth:`~.VMobject.set_fill`\n- :pr:`865`: Rename ``get_submobject_index_labels`` to ``index_labels``\n- :pr:`941`: Added keyword arguments ``x_min``, ``x_max``, ``y_min``, ``y_max`` to :class:`~.ThreeDAxes`\n- :pr:`886`: Let the render progress bar show details about the rendered animation again\n- :pr:`936`: Fix :class:`~.BulletedList` TeX environment problem and add a typing to ``get_module``\n- :pr:`938`: Remove dependency on progressbar\n- :pr:`937`: Change 'brew cask install' to 'brew install --cask' for CI pipeline\n- :pr:`933`: Make matrix work with lists again\n- :pr:`932`: Correctly parse ``log_dir`` option\n- :pr:`920`: Raise error if markup in :class:`~.MarkupText` is invalid\n- :pr:`929`: Raise an error if a :class:`~.Matrix` object is created with < 2-dimensional input\n- :pr:`907`: Make Scene.add_sound work again (when running with ``--disable_caching``)\n- :pr:`906`: Allow new-style method animation to be used in animation groups\n- :pr:`908`: Removed deprecated command line arguments from documentation\n- :pr:`903`: Tiny grammar improvements\n- :pr:`904`: Added blank line between imports and class example\n- :pr:`898`: CI: fix publish workflow\n"
  },
  {
    "path": "docs/source/changelog/0.4.0-changelog.rst",
    "content": "******\nv0.4.0\n******\n\n:Date: March 3, 2021\n\nThe changes since Manim Community release v0.3.0 are listed below.\n\nBreaking Changes\n================\n\n- :pr:`915`: Manim's SVG engine has been reworked and is able to handle a wider variations of SVG files. In particular: fill and stroke properties are now retained from the original files. Breaking change: ``VMobjectFromSVGPathstring`` is deprecated and has been renamed to ``SVGPathMobject``.\n\n\nNew Features\n============\n\n- :pr:`1026`: Add 3D Mobjects: :class:`~.Cone`, :class:`~.Cylinder`, :class:`~.Line3D`, :class:`~.Arrow3D` and :class:`~.Torus`\n- :pr:`1047`: Add documentation and examples for :class:`~.Matrix`\n- :pr:`1044`: ``register_font`` is available for macOS\n- :pr:`995`: Add generic :func:`~.Mobject.set` method and compatibility layer between properties and ``get_*``/``set_*`` methods\n\nBugfixes and Enhancements\n=========================\n\n- :pr:`981`: Fixed hot reload functionality for the WebGL renderer on Windows\n- :pr:`1053`: Repair links to source code in stable version of documentation\n- :pr:`1067`: Add ManimPango to ReadTheDocs requirements\n- :pr:`1058`: Replace ``<color>`` syntax by Pango's ``<span foreground>`` for coloring parts of :class:`~.MarkupText` and allow using colors for underline, overline and strikethrough in MarkupText\n- :pr:`1063`: Fix documentation related to ``.animate``\n- :pr:`1065`: Remove duplicate word 'vector'\n- :pr:`1060`: Update Linux installation instructions to mention the installation of Pango\n- :pr:`1050`: Ensure that the user-supplied stroke color and width gets applied to :class:`~.Cross`\n- :pr:`1059`: More descriptive error when accessing an unhandled mobject attribute\n- :pr:`1048`: Use absolute path in ``make_and_open_docs.py``\n- :pr:`1000`: Remove ``MovingCameraScene.setup`` and ``MovingCameraScene.camera_frame``\n- :pr:`1051`: Corrections for setting stroke related attributes on :class:`~.VMobject`\n- :pr:`1043`: Make :class:`~.CubicBezier` explicitly accept four points\n- :pr:`1046`: Use any version of ``importlib-metadata``\n- :pr:`1030`: Parse ``.log`` file and try to print LaTeX errors if compilation fails\n- :pr:`1015`: Documentation: Add more explicit instructions related to ``tlmgr``\n- :pr:`1028`: Documentation: Update installation guide on mac with Apple Silicon\n- :pr:`1032`: Remove ``Square.side_length`` property\n- :pr:`1031`: Fix link to wikipedia vector graphics page\n- :pr:`1021`: Documentation: Added example to :class:`~.CubicBezier`\n- :pr:`1017`: Added ``progress_bar`` to ``digest_args`` to fix the ``--progress_bar`` CLI flag\n- :pr:`1018`: Remove redundancy in :class:`~.FunctionGraph` arguments\n- :pr:`1024`: Migrate ``width`` / ``height`` / ``depth`` to properties\n- :pr:`1022`: Fix ``-p`` flag when passing ``-s``\n- :pr:`1008`: CI pipeline: fix release asset upload\n- :pr:`983`: Make sure last frame for animations with updaters is correct\n- :pr:`984`: Add manim version to CLI output, append version name for generated ``.gif`` and ``.png`` files, add version to metadata of rendered videos, change dark blue terminal text to default green\n- :pr:`993`: Fix setting Mobject color to a gradient by passing a list of colors in :meth:`~.VMobject.set_color`\n- :pr:`1003`: Fix animation :class:`~.GrowArrow`\n- :pr:`1010`: Disable STDIN interaction for ffmpeg concat.\n- :pr:`969`: Fix the ``--tex_template`` CLI flag\n- :pr:`989`: Fix the ``manim cfg export`` subcommand\n- :pr:`1005`: Fix the feature where ``-`` is used as the filename\n- :pr:`998`: Allow using hexadecimal color codes with 3 characters\n- :pr:`996`: Changed the message of ``manim --version`` to not include \"Edition\"\n"
  },
  {
    "path": "docs/source/changelog/0.5.0-changelog.rst",
    "content": "******\nv0.5.0\n******\n\n:Date: April 02, 2021\n\nContributors\n============\n\nA total of 35 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Abel Aebker +\n* Abhijith Muthyala\n* AntonBallmaier +\n* Aron\n* Benjamin Hackl\n* Bogdan Stăncescu +\n* Darylgolden\n* Devin Neal\n* GameDungeon +\n* Hugues Devimeux\n* Jason Villanueva\n* Kapil Sachdeva\n* KingWampy\n* Lionel Ray +\n* Mark Miller\n* Mohammad Al-Fetyani +\n* Naveen M K\n* Niklas Dewally +\n* Oliver +\n* Roopesh +\n* Seb Pearce +\n* aebkea +\n* friedkeenan\n* hydrobeam +\n* kolibril13\n* sparshg\n* tfglynn +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Abel Aebker\n* Abhijith Muthyala\n* Benjamin Hackl\n* Bogdan Stăncescu\n* Devin Neal\n* Hugues Devimeux\n* Jason Villanueva\n* Kapil Sachdeva\n* KingWampy\n* Leo Torres\n* Lionel Ray\n* Mark Miller\n* Mohammad Al-Fetyani\n* Naveen M K\n* Oliver\n* Ricky Chon\n* vector67\n\nPull requests merged\n====================\n\nA total of 64 pull requests were merged for this release.\n\nHighlights\n----------\n\n* :pr:`1075`: Add OpenGL Renderer\n   Adds an OpenGLRenderer, OpenGLCamera, OpenGL-enabled Mobjects, and a ``--use_opengl_renderer`` flag. When this flag is passed, you can pass the ``-p`` flag to preview animations, the ``-w`` flag to generate video, and the ``-q`` flag to specify render quality. If you don't pass either the ``-p`` or the ``-w`` flag, nothing will happen. Scenes rendered with the OpenGL renderer must *only* use OpenGL-enabled Mobjects.\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`1124`: Deprecated :class:`ShowCreation` in favor of :class:`Create`\n   1. Deprecated :class:`ShowCreation` in favor of :class:`Create` across the library with the exception of the `show_creation` boolean variable `vector_space_scene.py`\n   2. Added a deprecation warning in the original :class:`ShowCreation` class.\n\n* :pr:`1110`: Deprecated SmallDot + OpenGLSmallDot\n   `SmallDot` isn't necessary and a deprecation warning will be raised. This will be removed in a future release.\n\nNew features\n------------\n\n* :pr:`1037`: Added new fade and transform animations (:class:`~.TransformMatchingShapes`, :class:`~.TransformMatchingTex`, :class:`~.FadeTransform`) from 3b1b/manim\n   Added new Fade animation: :class:`~FadeOutToPoint`\n   Added :class:`~FadeTransform` and :class:`~FadeTransformPieces` for transforming mobjects and submobjects with a fade\n   Added :class:`~TransformMatchingShapes` and :class:`~TransformMatchingTex` for transforming mobjects and tex that have matching parts\n\n* :pr:`1097`: Added 3D Mobject :class:`~.Dot3D`\n\n\n* :pr:`1074`: Added jupyter media_width option to the config\n\n\n* :pr:`1107`: Added :class:`~.Unwrite` animation class to complement :class:`~.Write`\n   Added :class:`Unwrite` which inherits from :class:`~.Write`. It automatically reverses the animation of :class:`~.Write` by passing the reversed rate function, but it also takes an additional boolean parameter `reverse` which, if `False`, renders the animation from left to right (assuming text oriented in the usual way), but if `True`, it renders right to left.\n\n* :pr:`1085`: Added :class:`~.Angle` and :class:`~.RightAngle` for intersecting lines\n   :class:`~.Angle` and :class:`~.RightAngle` both take two lines as input. If they intersect, or share a common vertex, an angle is drawn between them. Users can customize the look of the angle and also use a dotted right angle.\n\nEnhancements\n------------\n\n* :pr:`1144`: Improved quality of GIFs\n\n\n* :pr:`1157`: Refresh triangulation on call to :meth:`~.OpenGLVMobject.apply_points_function`\n   Rotate called apply_points_function, which was previous not subclassed by OpenGLMobject - now it is. Then, the vertex normals can be updated too.\n\n   Additionally, the old_points matrix would change after rotating, making the old points / new points test irrelevant. This is addressed with a .copy call.\n\n* :pr:`1151`: Added parametric function support to :class:`OpenGLSurface`\n\n\n* :pr:`1139`: In-Code `config[\"preview\"]` Support\n\n\n* :pr:`1123`: Added caching, skipping, and user-specified background colors to the OpenGL renderer\n   OpenGL play logic has been improved to support caching and skipping with `-n` argument ( it is now similar to Cairo play logic). A random bug was fixed in OpenGLSurface and OpenGL background color can now be changed via `background_color` argument.\n\n* :pr:`1118`: Allow passing animation arguments with .animate syntax\n   Users will now be able to do things like `obj.animate(run_time=2).method(arg)` if they want to specify animation arguments for an individual `.animate` call, and can still not specify any arguments like `obj.animate.method(arg)`.\n\n   Passing animation arguments is only allowed directly after `.animate` is accessed, if passed elsewhere then a `ValueError` is raised.\n\n* :pr:`718`: Rotating the numbers in y axis\n   In Axes, the y axis will be rotated 90deg but the numbers are\n   also rotated and shouldn't be. Fixes this issue.\n\n* :pr:`1070`: Raise FileNotFoundError when unable to locate the .cfg file specified via ``--config_file``\n   Raising the error will stop script execution and let the user know that there are problems with the `--config_file` location instead of reverting back to the default configuration.\n\nFixed bugs\n----------\n\n* :pr:`1224`: Fixed :class:`~.ShowIncreasingSubsets`, :class:`~.ShowSubmobjectsOneByOne`, and :class:`~.AddTextLetterByLetter`\n\n\n* :pr:`1201`: Prevent crash on :meth:`~.Scene.embed` for empty scenes\n\n\n* :pr:`1192`: Fixed issue when an animation is cached, manim can't merge the partial movie files.\n\n\n* :pr:`1193`: Fixed using :class:`~.Animation` without a child :class:`~.Mobject` in :class:`~.AnimationGroup`\n   `AnimationGroup` may now take `Animation` objects which do not have a child `Mobject`, such as `Wait`.\n\n* :pr:`1170`: Fixed minor SVG parsing bugs\n\n\n* :pr:`1159`: Added support for multiple transforms in the same SVG element\n\n\n* :pr:`1156`: Fixed :class:`~.DrawBorderThenFill` to support OpenGL and improved type hints for some functions\n   Fixed a bug in :class:`~.DrawBorderThenFill` that prevented :class:`~.Write` animations from working with :class:`~.OpenGLVMobjects` and slightly improved type hints for some animation functions to include :class:`~.OpenGLVMobject`.\n\n* :pr:`1134`: Fixed the `-a` flag.\n   The ``-a`` / ``--write-all`` flag was broken. When used, it would cause Manim to crash just after beginning to render the second scene.\n\n* :pr:`1115`: Fixed bugs in :class:`~.OpenGLMobject` and added :class:`ApplyMethod` support\n   Fixed undefined variables and converted :class:`Mobject` to :class:`OpenGLMobject`. Also, fixed assert statement in :class:`ApplyMethod`.\n\n* :pr:`1092`: Refactored coordinate_systems.py, fixed bugs, added :class:`~.NumberPlane` test\n   The default behavior of :meth:`~.Mobject.rotate` is to rotate about the center of :class:`~.Mobject`. :class:`~.NumberLine` is symmetric about the point at the number 0 only when ``|x_min|`` == ``|x_max|``. Ideally, the rotation should coincide with\n   the point at number 0 on the line.\n\n   Added a regression test and additionally fixed some bugs introduced in :pr:`718`.\n\n* :pr:`1078`: Removed stray print statements from `__main__.py`\n   Uses rich's print traceback instead and fixes an issue in printing the version twice when `manim --version` is called.\n\n* :pr:`1086`: Fixed broken line spacing in :class:`~.Text`\n   The `line_spacing` kwarg was missing when creating :class:`Text` Mobjects; this adds it.\n\n* :pr:`1083`: Corrected the shape of :class:`~.Torus`\n   :class:`Torus` draws a surface with an elliptical cross-section when `minor_radius` is different from 1. This PR ensures the cross-section is always a circle.\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`1217`: Copyedited the document on testing in our documentation\n\n\n* :pr:`1206`: Added Docstrings to :class:`~.Mobject`\n\n\n* :pr:`1218`: Removed BezierSpline from the example gallery\n\n\n* :pr:`1219`: Updated Dockerfile (include dependencies for building documentation), moved documentation to main README\n\n\n* :pr:`1209`: Added :ref_methods: to the manim directive\n   This allows class methods to be linked in the documentation. Checkout the `example references <https://docs.manim.community/en/latest/examples.html#movingaround>`_ below the code to see how this is used!\n\n* :pr:`1204`: Added rotation example to example gallery\n\n\n* :pr:`1137`: Added GitHub Wiki pages on adding testing/documentation to Sphinx Docs\n\n\n* :pr:`1114`: Added examples for :class:`~.Ellipse`, :class:`~.Polygon`, :class:`~.RegularPolygon`, :class:`~.Triangle` and :class:`~.RoundedRectangle`\n\n\n* :pr:`1195`: Removed SmallDot from example\n\n\n* :pr:`1130`: Added pre-commit to run black and flake8, updated contributing documentation accordingly\n\n\n* :pr:`1138`: Moved previous version changelogs to separate files; Added a Script to generate future changelogs\n   This script quickly generates a changelog for whoever is making the release.\n\n* :pr:`1190`: Added note in contributing guide to read the latest version of the documentation\n\n\n* :pr:`1188`: Added sounds example to docs\n\n\n* :pr:`1165`: Added documentation for installing Manim on Colab\n\n\n* :pr:`1128`: Added examples for :class:`~.DashedLine`, :class:`~.TangentLine`, :class:`~.Elbow`, :class:`~.Arrow`, :class:`~.Vector`, :class:`~.DoubleArrow`\n\n\n* :pr:`1177`: Replace links to the latest version of the documentation to the stable version\n\n\n* :pr:`1077`: Added details to :func:`~.Mobject.get_critical_point`\n\n\n* :pr:`1154`: Fixed some typing hints. (ints to floats)\n\n\n* :pr:`1036`: Added :class:`~.SurroundingRectangle` to the example gallery\n\n\n* :pr:`1103`: Added documentation and examples for Square, Dot, Circle and Rectangle\n\n\n* :pr:`1101`: Added documentation to :class:`~.Mobject`\n\n\n* :pr:`1088`: Added new svg files to documentation and imports\n   In particular, SVGPathMobject, VMobjectFromPathstring, and the style_utils functions to manim's namespace.\n\n* :pr:`1076`: Improve documentation for GraphScene\n   Updated `coords_to_point` and `point_to_coords` under `manim/scene/graph_scene.py` as the dosctring of each function confusingly described the opposite of what it is supposed to do.\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`1160`: Enable CI testing for OpenGL\n\n\n* :pr:`1100`: Rewrote test cases to use sys.executable in the command instead of \"python\"\n   Tests would fail due to `capture()` not spawning a subshell in the correct environment, so when python was called, the test would be unable to find necessary packages.\n\n* :pr:`1079`: Removed the hardcoded value, `manim`, in `test_version.py`\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`1213`: Updated TinyTex dependencies\n\n\n* :pr:`1187`: Add CodeCov to Github Workflow\n\n\n* :pr:`1166`: CI: Use poetry's cache dir rather than pip\n\n\n* :pr:`1071`: Enable pytest-cov based code coverage\n   - Include pytest-cov as a python module as part of developer dependencies\n   - In updating poetry to include pytest-cov, manimpango moved from version 0.2.3 to 0.2.4, and libpango1.0-dev needed to be installed in Ubuntu.\n   - Add to the CI workflow (`ci.yml`) to create and upload test coverage.\n\n* :pr:`1073`: Removed \"one line summary\" from PULL_REQUEST_TEMPLATE.md\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`1167`: Merge :class:`~.OpenGLMobject` and :class:`~.Mobject`\n\n\n* :pr:`1164`: Fixed single PEP8 style in `cairo_renderer.py`\n\n\n* :pr:`1140`: Flake8 Compat & Code Cleanup\n\n\n* :pr:`1019`: Refactored :meth:`~.Scene.play`\n   - Removed the _**three**_ decorators of :meth:`~.Scene.play`, in particular: caching logic and file writer logic are now included within :meth:`~.Scene.play` (it wasn't possible before, because `scene.wait` and `scene.play` were two different things).\n   - Added `is_static_wait` attributes to Wait. (<=> if wait is a frozen frame).\n   - Renamed and moved `scene.add_static_frame` to `renderer.freeze_current_frame`.\n   - Now when calling play without animation, it raises `ValueError` instead of just a warning.\n   - Fixed :pr:`874` by modifying `renderer.update_skipping_status`\n   - `renderer` starts the animation with `scene.begin_animations` (`scene.compile_animation_data` used to do this)\n   - The run time and the time progression generation is now done in `scene.play_internal` although it'd make more sense that renderer processes it later.\n   - Added a bunch of cool tests thanks to mocks, and thanks to the new syntax `scene.render`\n"
  },
  {
    "path": "docs/source/changelog/0.6.0-changelog.rst",
    "content": "******\nv0.6.0\n******\n\n:Date: May 02, 2021\n\nContributors\n============\n\nA total of 40 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Abel Aebker\n* Abhijith Muthyala\n* Adam Ryczkowski +\n* Alex Lembcke +\n* Anton Ballmaier\n* Aron\n* Benjamin Hackl\n* Darylgolden\n* Deniz Hasler +\n* Devin Neal\n* Elisha Hollander +\n* Erik Tastepe +\n* Jan-Hendrik Müller\n* Jason Villanueva\n* Laith Bahodi\n* Mark Miller\n* Mohammad Al-Fetyani\n* Naveen M K\n* Newell Jensen +\n* Nidhal Baccouri +\n* Nikhil Garuda +\n* Peilonrayz +\n* Raghav Goel\n* Ricky Chon +\n* friedkeenan\n* kamilczerwinski22 +\n* sparshg\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Aathish Sivasubrahmanian\n* Abel Aebker\n* Abhijith Muthyala\n* Adam Ryczkowski\n* Alex Lembcke\n* Anton Ballmaier\n* Aron\n* Benjamin Hackl\n* Darylgolden\n* Deniz Hasler\n* Devin Neal\n* Elisha Hollander\n* GameDungeon\n* Hugues Devimeux\n* Jan-Hendrik Müller\n* Jason Villanueva\n* KingWampy\n* Laith Bahodi\n* Mark Miller\n* Mohammad Al-Fetyani\n* Naveen M K\n* Nidhal Baccouri\n* Nikhil Garuda\n* Oliver\n* Philipp Imhof\n* Raghav Goel\n* Ricky Chon\n* friedkeenan\n* sparshg\n\nPull requests merged\n====================\n\nA total of 112 pull requests were merged for this release.\n\nBreaking changes\n----------------\n\n* :pr:`1347`: Restructure vector_field module and add documentation\n   :class`~.VectorField` is renamed to :class:`~.ArrowVectorField` and a new class :class:`~.VectorField` is added as a superclass for :class:`~.ArrowVectorField` and :class:`~.StreamLines`. :class:`~.AnimatedStreamLines` is removed. It's functionality is moved to :class:`~.StreamLines`. Added a lot of new options when working with vector fields. :class:`~.ShowPassingFlashWithThinningStrokeWidth` was moved to the indication module.\n\n* :pr:`1161`: Upgrades to CoordinateSystem and graphing.\n   Breaking changes were introduced to :class:`~.Axes`, :class:`~.ThreeDAxes`, :class:`~.NumberPlane` and :class:`~.NumberLine`\n   All the above now use lists to construct their ranges as opposed to explicitly defining these values. `x_range` has replaced `x_min`, `x_max` and defining the step is much easier with `x_step` --> ``x_range``  :  ``[x_min, x_max, x_step]``. There were also many upgrades to these classes which improve their functionality and appearance.\n\n   ``NumberLineOld`` was introduced to continue support for :class:`~.GraphScene`, although we are moving away from GraphScene and intend to deprecate it in a future release.\n\n* :pr:`1013`: Refactored the Command Line Interface to use Click instead of Argparse\n   This change breaks the CLI API to organize the structure of Manim Community's commands, options, and arguments.\n\n   To be more in line with POSIX compliant CLI conventions, options for commands are given *BEFORE* their arguments.\n   In Argparse: ``manim basic.py -p -ql``\n   With Click: ``manim -p -ql basic.py``\n\n   Although this is primarily a refactor and most of the common options are still there, some options have been added/removed. Use the ``manim`` command's ``--help`` option, or simply run the command without providing options/arguments to view the help page with the full list of subcommands/options/arguments.\n\n   - Added a ``--fps``/``--frame_rate`` option which allows for custom fps that don't have to be integer (i.e. 29.97, 23.98, etc.). Users no longer have to specify the FPS from within a config file. Additionally, the ``--webgl_renderer_fps`` option has been removed. Use ``--fps`` or ``--frame_rate`` instead.\n   - Added a ``--renderer`` option which you can use to select your choice of renderer (e.g. ``--renderer=opengl``). There are currently *THREE* renderers to choose from!\n   - Removed the ``--background_color`` option. Reassigned the ``--background_color`` option's shorthand ``-c`` to ``--config_file``.\n   - Removed the ``--leave_progress_bars`` option. Use ``--progress_bars=leave`` instead.\n   - Removed the deprecated render quality flags, in particular: ``-l``, ``-m``, ``-h``, ``-k``.\n   - Removed the ``--sound`` option. It lost support long ago with the removal of SoX.\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`1431`: Fix CLI bugs\n   - Fixed conflict with ``-f`` which was previously assigned to both ``--show_in_file_browser`` and ``--format`` by removing ``-f`` from ``--format``. A warning is issued that ``-f`` will soon move to ``--format``.\n   - Added back in flags to render the files as gif/last frame. Deprecated them in favor of ``--format``.\n   - Fixed the broken ``--output_file``/``-o`` option.\n   - Fixed an issue where the ``-qh`` quality option was interpreted as ``-q`` ``-h``, prompting the help page.\n\n* :pr:`1354`: Refactored a few functions in space_ops.py, deprecated :func:`~.angle_between`\n\n\n* :pr:`1370`: Remove TexMobject and TextMobject\n   TexMobject and TextMobject have been deprecated for a while, they are now fully removed. Use Tex or MathTex instead.\n\n* :pr:`1349`: Removed the deprecated ``SmallDot`` mobject\n\n\n* :pr:`1259`: Removed deprecated CairoText class\n\nNew features\n------------\n\n* :pr:`1386`: Implement utility methods for adding/removing vertices and edges of graphs; allow custom mobjects as vertices\n\n\n* :pr:`1385`: Added :meth:`~.Axes.get_line_graph` for plotting a line graph\n   Added :meth:`~.Axes.get_line_graph` that returns a line graph from lists of points along x, y and z (optional) axes.\n\n* :pr:`1381`: Hot reloading for the OpenGL renderer\n   Rerun scene when the input file is modified\n\n* :pr:`1383`: Overhaul of the :mod:`~.animation.indication` module interfaces\n   - Added class `Circumscribe` combining functionality of `CircleIndicate`, `AnimationOnSurroundingRectangle`, `ShowPassingFlashAround`, `ShowCreationThenDestructionAround`, `ShowCreationThenFadeAround`, which have all been deprecated.\n   - Changes to `Flash`: `flash_radius` parameter now defines inner radius of the animation. Added new parameter `time_width`.\n   - `ShowCreationThenDestruction` has been deprecated in favor of `ShowPassingFlash`\n   - Changes to `ApplyWave`: New implementation giving more flexibility with new parameters `wave_func`, `time_width` and`ripples`\n   - Renamed `WiggleOutThenIn` to `Wiggle` (`WiggleOutThenIn` has been deprecated)\n   - Added documentation and examples to all the above\n   - Other minor enhancements and bug-fixes\n\n* :pr:`1348`: Added :class:`~.Polyhedron`, and platonic solids :class:`~.Tetrahedron`, :class:`~.Octahedron`, :class:`~.Icosahedron` and :class:`~.Dodecahedron`\n\n\n* :pr:`1285`: Add :meth:`~.Scene.interactive_embed` for OpenGL rendering\n   :meth:`~.Scene.interactive_embed` allows interaction with Scene via mouse and keyboard as well as dynamic commands via an iPython terminal.\n\n* :pr:`1261`: Render image automatically if no animation is played in a scene\n   - If no animations in scene and asked to preview/render a video, preview/render an image instead of raising a confusing error.\n\n* :pr:`1200`: Add text and SVG mobjects to OpenGL\n   Added OpenGL-compatible text and SVG mobjects\n\nEnhancements\n------------\n\n* :pr:`1398`: Fix and enhance `Mobject.arrange_in_grid`\n   `arrange_in_grid` now actually arranges submobjects in a grid. Added new parameters `buff`, `cell_alignment`, `row_alignments`, `col_alignments`, `row_heights`, `col_widths`, `flow_order`.\n\n* :pr:`1407`: Fix bug and rename :meth:`vector_coordinate_label` to :meth:`~.Vector.coordinate_label` and move it to :class:`geometry.py`\n\n\n* :pr:`1380`: Allow image objects as background images\n\n\n* :pr:`1391`: Add `path_arc` support to `.animate` syntax\n   The parameter `path_arc` of :class:`~.Transform` now works with the `.animate` syntax\n\n* :pr:`1364`: Added :meth:`~.Mobject.match_points`\n   - Added :func:`~.Mobject.match_points`, which transforms the points, positions and submobjects of a Mobject to match that of the other while keeping style unchanged.\n\n* :pr:`1363`: Change of TeX compiler and output file format\n\n\n* :pr:`1359`: Make FILE a required argument\n   * Make `FILE` a required argument, `manim/cli/render/commands.py`:L30\n\n* :pr:`1304`: Improve Tex string splitting at double braces: only split for double brace groups\n\n\n* :pr:`1340`: Add OpenGL support to the new transform animations\n   Made `FadeTransform`, `FadeTransformPieces`, `TransformMatchingShapes` and `TransformMatchingTex` compatible with OpenGL rendering.\n\n* :pr:`1343`: Make TexTemplate() simple, but keep Tex()'s default template\n   TexTemplate() now returns a simple tex template.\n\n* :pr:`1321`: Add OpenGL support to :class:`~.AnimationGroup`\n\n\n* :pr:`1302`: Raise appropriate errors in :meth:`~.VMobject.point_from_proportion`\n   - Raise an error if the ``alpha`` argument is not between 0 and 1.\n   - Raise an error if the :class:`~.VMobject` has no points.\n\n* :pr:`1315`: Fix performance issues with :meth:`~.VMobject.get_arc_length`, stemming from :pr:`1274`\n\n\n* :pr:`1320`: Add `jpeg` extension to the default image extensions\n\n\n* :pr:`1234`: Added new method :meth:`~.Mobject.get_midpoint`\n   Implemented :meth:`~.Mobject.get_midpoint` to return the point that is the middle of the stroke line of an mobject.\n\n* :pr:`1237`: Notify user if they are using an outdated version of Manim\n\n\n* :pr:`1308`: Improved :class:`~.ManimBanner` animations\n\n\n* :pr:`1275`: Add SVG <line> element support to :class:`~.SVGMobject`\n\n\n* :pr:`1238`: Add parameter ``about_point`` for :meth:`~.Mobject.rotate`\n\n\n* :pr:`1260`: Change Brace from Tex to SVG (#1258)\n\n\n* :pr:`1122`: Support for specifying the interpolation algorithms for individual ImageMobjects\n\n\n* :pr:`1283`: Set default value of keyword ``random_seed`` in :class:`~.Scene` to ``None`` (was 0 and fixed before)\n\n\n* :pr:`1220`: Added sanity checks to :meth:`~.Mobject.add_to_back` for Mobjects\n   Add Mobject `add_to_back` sanity checks:\n   - Raises ValueError when Mobject tries to add itself\n   - Raises TypeError when a non-Mobject is added\n   - Filters out incoming duplicate submobjects if at least one instance of that submobject exists in the list\n\n* :pr:`1249`: Set corners of :class:`~.Rectangle` in counterclockwise direction\n   This improves the look of transformations between rectangles and other simple mobjects.\n\n* :pr:`1248`: Add Copy function to TexTemplate\n\n\nFixed bugs\n----------\n\n* :pr:`1368`: Added a check to ensure checking for the latest version was successful\n\n\n* :pr:`1413`: Prevent duplication of the same mobject when adding to submobjects via :meth:`~.Mobject.add_to_back`\n   Fixes #1412\n\n* :pr:`1395`: SVG transforms now handle exponent notation (6.02e23)\n\n\n* :pr:`1355`: Rewrite `put_start_and_end_on` to work in 3D\n\n\n* :pr:`1346`: Fixed errors introduced by stray print in :class:`~.MathTex`\n\n\n* :pr:`1305`: Automatically remove long tick marks not within the range of the :class:`~NumberLine`\n\n\n* :pr:`1296`: Fix random pipeline TeX failures\n\n\n* :pr:`1274`: Fix :meth:`~.VMobject.point_from_proportion` to account for the length of curves.\n   - Add :meth:`~.VMobject.get_nth_curve_function_with_length` and associated functions.\n   - Change :meth:`~.VMobject.point_from_proportion` to use these functions to account for curve length.\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`1430`: Un-deprecated GraphScene (will be deprecated later), fixed an old-style call to NumberPlane\n   - More work is required in order to fully replace `GraphScene` via `Axes`, thus `GraphScene` is not deprecated yet.\n   - Fixed one example in which the old `NumberPlane` syntax was used.\n\n* :pr:`1425`: Added a \"How to Cite Manim\" section to the Readme\n\n\n* :pr:`1387`: Added Guide to Contribute Examples from GitHub Wiki to Documentation\n   Added a Guide\n\n* :pr:`1424`: Fixed all current docbuild warnings\n\n\n* :pr:`1389`: Adding Admonitions Tutorial to docs\n\n\n* :pr:`1341`: Reduce complexity of ThreeDSurfacePlot example\n\n\n* :pr:`1362`: Quick reference to modules\n\n\n* :pr:`1376`: Add flake8 and isort in docs\n   added 'flake8' and 'isort' usages to docs\n\n* :pr:`1360`: Grammatical error corrections in documentation\n   changed a few sentences in docs/source\n\n* :pr:`1351`: Some more typehints\n\n\n* :pr:`1358`: Fixed link to installation instructions for developers\n\n\n* :pr:`1338`: Added documentation guidelines for type hints\n\n\n* :pr:`1342`: Multiple ValueTracker example for docs\n\n\n* :pr:`1210`: Added tutorial chapter on coordinates of an mobject\n\n\n* :pr:`1335`: Added import statements to examples in documentation\n\n\n* :pr:`1245`: Added filled angle Example\n\n\n* :pr:`1328`: Docs: Update Brace example\n\n\n* :pr:`1326`: Improve documentation of :class:`~.ManimMagic` (in particular: fix documented order of CLI flags)\n\n\n* :pr:`1323`: Blacken Docs Strings\n\n\n* :pr:`1300`: Added typehints for :class:`~.ValueTracker`\n\n\n* :pr:`1301`: Added further docstrings and typehints to :class:`~.Mobject`\n\n\n* :pr:`1298`: Add double backquotes for rst code samples (value_tracker.py)\n\n\n* :pr:`1297`: Change docs to use viewcode extension instead of linkcode\n   Switched ``sphinx.ext.linkcode`` to ``sphinx.ext.viewcode`` and removed ``linkcode_resolve`` in ``conf.py``.\n\n* :pr:`1246`: Added docstrings for :class:`~.ValueTracker`\n\n\n* :pr:`1251`: Switch documentation from guzzle-sphinx-theme to furo\n\n\n* :pr:`1232`: Further docstrings and examples for :class:`~.Mobject`\n\n\n* :pr:`1291`: Grammar improvements in README.md\n\n\n* :pr:`1269`: Add documentation about :meth:`~.set_color_by_tex`\n\n\n* :pr:`1284`: Updated readme by providing the correct link to the example_scenes\n\n\n* :pr:`1029`: Added example jupyter notebook into the examples folders\n\n\n* :pr:`1279`: Added sphinx requirements to pyproject.toml\n   New contributors who wanted to build the sphinx documentation had an extra step that could be removed by making use of ``poetry install``. This removes the developer's need for ``pip install -r requirements.txt``.\n\n* :pr:`1268`: Added documentation explaining the differences between manim versions\n\n\n* :pr:`1247`: Added warning for the usage of `animate`\n\n\n* :pr:`1242`: Added an example for the manim colormap\n\n\n* :pr:`1239`: Add TinyTex installation instructions\n\n\n* :pr:`1231`: Improve changelog generation script\n\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`1299`: Red pixels (different value) now appear over green pixels (same value) in GraphicalUnitTest\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`1436`: Cache poetry venv with `pyproject.toml` hash in key\n   Cache poetry venv with `pyproject.toml` hash in key\n\n* :pr:`1435`: CI: Update poetry cache when new version is released\n   Fix `test_version` failure in CI when using cached poetry venv\n\n* :pr:`1427`: Add URL's to pyproject.toml\n\n\n* :pr:`1421`: Updated changelog generator's labels and removed pre-commit bot from changelog\n\n\n* :pr:`1339`: CI: Fix macOS installation error from creating file in read-only file system\n\n\n* :pr:`1257`: CI: Caching ffmpeg, tinytex dependencies and poetry venv\n   CI: Caching ffmpeg, tinytex dependencies and poetry venv\n\n* :pr:`1294`: Added mixed-line-ending to .pre-commit-config.yaml\n\n\n* :pr:`1278`: Fixed flake8 errors and removed linter/formatter workflows\n\n\n* :pr:`1270`: Added isort to pre_commit file\n\n\n* :pr:`1263`: CI: Turn off experimental installer for poetry to fix installation errors\n   - Turn off experimental installer for poetry to prevent manim installation errors for packages.\n   - Downgrade py39 to py38 for flake checks as `pip` does not enjoy py39, along with `poetry`.\n\n* :pr:`1255`: CI: Fix macOS pipeline failure\n   Update `ci.yml` to update and upgrade brew if necessary before installing dependencies, and remove the unsupported `dvisvgm.86_64-darwin` package.\n\n* :pr:`1254`: Removed the comment warning that GitHub doesn't allow uploading video in the issue templates.\n\n\n* :pr:`1216`: Use actions/checkout for cloning repository; black-checks\n\n\n* :pr:`1235`: Fixed version of decorator at <5.0.0\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`1411`: Change `Union[float, int]` to just `float` according to PEP 484\n\n\n* :pr:`1241`: Type Annotations: Fixing errors showing up in static type checking tool mypy\n\n\n* :pr:`1319`: Fix mean/meant typo\n   Fix typo in docs\n\n* :pr:`1313`: Singular typo fix on the Quickstart page in documentation\n\n\n* :pr:`1292`: Remove unnecessary imports from files\n   Imports reduced in a bunch of files\n\n* :pr:`1295`: Fix grammar and typos in the CODE OF CONDUCT\n\n\n* :pr:`1293`: Minor fixes - reduce lines\n   Remove unnecessary lines\n\n* :pr:`1281`: Remove all Carriage Return characters in our files\n\n\n* :pr:`1178`: Format Imports using Isort\n\n\n* :pr:`1233`: Fix deprecation warning for ``--use_opengl_renderer`` and ``--use_webgl_renderer``\n\n\n* :pr:`1282`: Fix typing hints in vectorized_mobject.py based on mypy\n\n\nNew releases\n------------\n\n* :pr:`1434`: Prepare v0.6.0\n"
  },
  {
    "path": "docs/source/changelog/0.7.0-changelog.rst",
    "content": "******\nv0.7.0\n******\n\n:Date: June 01, 2021\n\nContributors\n============\n\nA total of 45 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* André +\n* Anton Ballmaier\n* Benjamin Hackl\n* Clar Fon\n* Darylgolden\n* Devin Neal\n* Hugues Devimeux\n* Iced-Tea3 +\n* Jan-Hendrik Müller\n* Jason Villanueva\n* Jerónimo Squartini +\n* KingWampy\n* Laith Bahodi\n* Max Stoumen +\n* Mohammad Al-Fetyani\n* Naveen M K\n* NeoPlato\n* Newell Jensen\n* Nikhil Garuda\n* Nikhil Sharma +\n* PaulCMurdoch +\n* Philipp Imhof\n* Raghav Goel\n* Robert West +\n* Ryan McCauley +\n* Skaft +\n* SwiddisZwei +\n* e4coder +\n* friedkeenan\n* malte-v +\n* ralphieraccoon\n* sparshg\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Aathish Sivasubrahmanian\n* Abhijith Muthyala\n* Anton Ballmaier\n* Aron\n* Benjamin Hackl\n* Darylgolden\n* Devin Neal\n* GameDungeon\n* Hugues Devimeux\n* Iced-Tea3\n* Jan-Hendrik Müller\n* Jason Villanueva\n* Jerónimo Squartini\n* KingWampy\n* Laith Bahodi\n* Mark Miller\n* Mohammad Al-Fetyani\n* Naveen M K\n* Nikhil Garuda\n* Oliver\n* Philipp Imhof\n* Raghav Goel\n* Ricky Chon\n* Ryan McCauley\n* Skaft\n* SwiddisZwei\n* e4coder\n* friedkeenan\n* ralphieraccoon\n* sparshg\n\nPull requests merged\n====================\n\nA total of 87 pull requests were merged for this release.\n\nBreaking changes\n----------------\n\n* :pr:`1521`: Improve :class:`~.Animation` docs\n   - Improve documentation of the :class:`~.Animation` class.\n   - Unify the signature of ``get_all_mobjects``. Now it always returns a sequence of :class:`Mobjects <.Mobject>`. This breaks using  ``FadeTransform.get_all_mobjects`` as ``Group``.\n\n* :pr:`1470`: Drop support for Python 3.6\n   Manim won't work on Python 3.6 anymore.\n\nHighlights\n----------\n\n* :pr:`1447`: Added :class:`~.PolarPlane` for polar coordinates.\n\n\n* :pr:`1490`: Added :class:`~.Polygram`, rework the polygon inheritance tree, and add :class:`~.Star`\n   - Add :class:`~.Polygram`, a generalized :class:`~.Polygon` that allows for disconnected sets of edges.\n   - Make :class:`~.Polygon` inherit from :class:`~.Polygram`.\n   - Add :func:`~.regular_vertices`\n   - Add :class:`~.RegularPolygram`.\n   - Make :class:`~.RegularPolygon` inherit from :class:`~.RegularPolygram`.\n   - Add :class:`~.Star`.\n\n* :pr:`1462`: OpenGL: Added :class:`~.Shader`, :class:`~.Mesh`, and :class:`~.FullScreenQuad`\n   Add Shader and Mesh objects\n\n* :pr:`1418`: Added project management commands\n   - ``manim init`` - quickly sets up default files for a manim project.\n   - ``manim new project`` - lets the user set project settings. It also creates the project inside a new folder of name <project_name>\n   - ``manim new scene`` - used to quickly insert new scenes into files. If ``file name`` is not provided ``main.py`` is used as default.\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`1598`: Update examples to use :class:`~.Axes` and deprecate :class:`~.GraphScene`\n   :class:`~.GraphScene` has been deprecated and its functionality has been shifted to :class:`~.Axes`. See the updated example gallery for sample usage.\n\n* :pr:`1454`: Fading module enhancements\n   Moved functionality of all Fading classes to :class:`~.FadeIn` and :class:`~.FadeOut`. All other fading classes have been deprecated.\n\n* :pr:`1375`: Deleted the deprecated ``ShowCreation`` in favor of :class:`~.Create`\n\n\nNew features\n------------\n\n* :pr:`1566`: Added the ability to add gridlines to a :class:`~.Rectangle`\n\n\n* :pr:`1548`: Added :class:`~.ArcBrace`, a subclass of :class:`~.Brace`.\n\n\n* :pr:`1559`: Update VGroup to support item assignment (#1530)\n   Support indexed item-assignment for VGroup\n\n* :pr:`1518`: Allow fading multiple Mobjects in one Animation\n\n\n* :pr:`1422`: Added :func:`~.override_animation` decorator\n\n\n* :pr:`1504`: Color module enhancements\n   - Replaced ``BLUE_E`` with what was previously ``DARK_BLUE`` and removed ``DARK_BLUE``\n   - Added alias ``LIGHTER_GRAY`` for ``GRAY_A``\n   - Added ``PURE_RED``, ``PURE_BLUE`` and renamed ``GREEN_SCREEN`` to ``PURE_GREEN``\n   - All gray colors are now also available using British spelling (including ``GREY_BROWN``)\n   - Replaced color example in the docs. It can now be used as a quick reference for all color names.\n\n* :pr:`1272`: Implement metaclass approach in geometry module to make mobjects compatible with cairo and opengl rendering\n\n\n* :pr:`1404`: Added two deprecation decorators\n   Added two function decorators ``deprecated`` and ``deprecated_params`` as a consistent way of deprecating code.\n\nEnhancements\n------------\n\n* :pr:`1572`: OpenGL compatibility via metaclass: :class:`~.TracedPath`, :class:`~.ParametricFunction`, :class:`~.Brace`, :class:`~.VGroup`\n\n\n* :pr:`1472`: Porting methods from :class:`~.GraphScene` to :class:`~.CoordinateSystem`\n\n\n* :pr:`1589`: OpenGL compatibility via metaclass: :class:`~.ValueTracker`\n\n\n* :pr:`1564`: Add extra notes for TeX compilation errors\n   Add hint to use custom ``TexTemplate`` on TeX compilation errors\n\n* :pr:`1584`: Added a check for ``0`` in :meth:`~.round_corners`\n\n\n* :pr:`1586`: Add OpenGLMobject support to all ``isinstance`` occurrences\n   This PR increases the support for OpenGL in the remaining animation classes and in other places where appropriate.\n\n* :pr:`1577`: Added new metaclass ConvertToOpenGL (replacing MetaVMobject), restore IntelliSense\n\n\n* :pr:`1562`: Improved VectorField's Nudge Accuracy Per Step\n   Implemented the Runge-Kutta algorithm in VectorField's nudge function. This increases the accuracy as an object moves along a vector field. This also increases efficiency as the nudge function requires less loops to achieve accuracy than the previous implementation.\n\n* :pr:`1480`: Add logging info to tex errors\n\n\n* :pr:`1567`: Compatibility Fixes with ManimPango v0.3.0\n   - ManimPango v0.3.0+ is required for Manim now.\n   - Show errors from Pango when Markup isn't correct\n\n* :pr:`1512`: OpenGL compatibility via metaclass: graph\n\n\n* :pr:`1511`: OpenGL compatibility via metaclass: svg_mobject, text_mobject, tex_mobject\n\n\n* :pr:`1502`: Added ``center`` parameter to :class:`~.Sphere` and ``point`` parameter to :class:`~.Dot3D`\n\n\n* :pr:`1486`: Update of ``rate_functions``\n   Changed the picture for the non standard rate functions.\n\n* :pr:`1495`: Ported value_tracker to OpenGL\n\n\n* :pr:`1382`: Expand documentation, testing, and functionality of ValueTrackers; remove ExponentialValueTracker\n   Added more documentation and inline operators to ValueTracker and ComplexValueTracker. Brought coverage for value_tracker.py to 100%. Removed ExponentialValueTracker.\n\n* :pr:`1475`: Add SVG elliptical arc support\n\n\nFixed bugs\n----------\n\n* :pr:`1574`: Fixed error when processing SVG with omitted elliptical arc command\n\n\n* :pr:`1596`: Fix indexing for non-whitespace tex arg separator\n   Fixes #1568\n\n   Fix issue when setting the arg_separator of a Tex object as a non-whitespace character(s). The method `break_up_by_substrings(self)` was not accounting for the separator when setting the index.\n\n* :pr:`1588`: Fixed multiple animations being saved in the same file\n\n\n* :pr:`1571`: Fix tests after introducing parallelization\n\n\n* :pr:`1545`: Fix outdated parameters for :class:`LinearTransformationScene` and add an example + typing.\n\n\n* :pr:`1513`: Fixed rotation of gradients while rotating a VMobject\n   - Fixed the direction of gradient which remained the same while rotating VMobjects\n   - Added ``rotate_sheen_direction()`` method in VMobject\n\n* :pr:`1570`: Output errors to stderr\n\n\n* :pr:`1560`: Declare ``*.npz`` ``*.wav`` ``*.png`` as binary in ``.gitattributes``\n\n\n* :pr:`1211`: Refactored scene caching and fixed issue when a different hash was produced when copying a mobject in the scene\n   Refactored internal scene-caching mechanism and fixed bug when an inconsistent hash was produced when copying a mobject.\n\n* :pr:`1527`: Improved handling of substring isolation within sqrt, and fixed a bug with transform_mismatch for the matching shape transforms\n\n\n* :pr:`1526`: Fix fading\n\n\n* :pr:`1523`: Fix multiple FadeIn / Out only working on VMobjects\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`1599`: Added example for :class:`~.Annulus`\n\n\n* :pr:`1415`: New example for gallery and some docs refinements\n\n\n* :pr:`1509`: Copyedited Documentation\n   Added a link to Manim Community GitHub page in ``for_dev.rst``.\n   Fixed :meth:`~.Mobject.get_start`  and added ``roll`` link in ``building_blocks-rst``\n   Added language to code blocks in ``configuration.rst``\n\n* :pr:`1384`: Added typings to space_ops.py\n   Added Typehints to most of the functions\n\n* :pr:`1500`: Example for :meth:`~.apply_complex_function`\n\n\n* :pr:`1551`: Fixed the typo for Admonitions\n\n\n* :pr:`1550`: Restructuring of Contribution Section\n\n\n* :pr:`1541`: Fixing broken links and other minor doc things\n\n\n* :pr:`1516`: Update docs to use ``t_range`` instead of ``t_min`` and ``t_max`` in :class:`~.ParametricFunction`\n\n\n* :pr:`1508`: Update troubleshooting docs\n\n\n* :pr:`1485`: Added :class:`~.Title` example for the docs\n\n\n* :pr:`1439`: Cleaning ``Sequence`` typehints\n\n\n* :pr:`1440`: Added Scoop installation docs (Windows)\n\n\n* :pr:`1452`: Refine typehints at :class:`~.Angle`\n\n\n* :pr:`1458`: Refine docs of :class:`~.Text` ( add ``disable_ligatures=True`` for t2c)\n\n\n* :pr:`1449`: Added :class:`~.PointCloudDot` example\n\n\n* :pr:`1473`: Added easy example for :meth:`~.arrange_in_grid`\n\n\n* :pr:`1402`: Added typestring parser checker\n\n\n* :pr:`1451`: Reduce complexity of AngleExample\n\n\n* :pr:`1441`: Add inheritance diagrams to reference page\n   Added inheritance diagrams to the reference page as a quick navigation method.\n\n* :pr:`1457`: Fixing broken doc links\n\n\n* :pr:`1445`: Remove $ from tutorial commands\n\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`1556`: Try pytest-xdist for parallelization in tests\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`1505`: Add docs reference to PR template\n   Added documentation link to the Pull Request Template.\n\n* :pr:`1499`: Updated Discord links in the docs to point towards a standardized redirect\n\n\n* :pr:`1461`: Build the docs - Logging\n\n\n* :pr:`1481`: pyproject.toml: poetry_core -> poetry-core\n\n\n* :pr:`1477`: Update RDT sphinx package to version 3.5.3\n\n\n* :pr:`1460`: Create CONTRIBUTING.md\n\n\n* :pr:`1453`: manim_directive: fix image links in docs - Windows\n   Use POSIX path on Windows to link images so documentation can build locally.\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`1465`: Added typings and description to some functions in :mod:`~.coordinate_systems`.\n\n\n* :pr:`1552`: Removed unwanted parameters in geometry\n   Removed ``anchors_span_full_range``, ``close_new_points``, ``anchors_span_full_range``, ``preserve_tip_size_when_scaling``, ``mark_paths_closed`` and ``close_new_points``\n\n* :pr:`1597`: Removed hilite_me and insert_line_numbers_in_html from global name space\n\n\n* :pr:`1535`: Update dependencies and fix tests\n\n\n* :pr:`1544`: Adding spell checker as a pre-commit hook\n\n\n* :pr:`1542`: Swapping a pango markup link in docs\n\n\n* :pr:`1531`: Don't use deprecated methods in deprecation.py\n\n\n* :pr:`1492`: Remove stray print statements introduced in #1404\n\n\n* :pr:`1471`: Fix Some Warnings from lgtm\n\n\nChanges that needed to be reverted again\n----------------------------------------\n\n* :pr:`1606`: Bring back ``DARK_BLUE``\n\n\nNew releases\n------------\n\n* :pr:`1601`: Preparation for v0.7.0: added changelog and bumped version number\n"
  },
  {
    "path": "docs/source/changelog/0.8.0-changelog.rst",
    "content": "******\nv0.8.0\n******\n\n:Date: July 02, 2021\n\nContributors\n============\n\nA total of 37 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Benjamin Hackl\n* Bill Shillito +\n* Darigov Research +\n* Darylgolden\n* Devin Neal\n* Iced-Tea3\n* Jan-Hendrik Müller\n* Jason Villanueva\n* KingWampy\n* Laith Bahodi\n* MathInvariance +\n* Max Stoumen\n* Mehmet Ali Özer +\n* Michael Pilosov +\n* Mohammad Al-Fetyani\n* Naveen M K\n* Nikhil Garuda\n* Oliver\n* PaulCMurdoch\n* Philipp Imhof\n* PipedQuintes +\n* Raghav Goel\n* Ryan McCauley\n* Ujjayanta +\n* Vagrid +\n* andrehisatsuga +\n* friedkeenan\n* peaceheis +\n* yit6 +\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Abhijith Muthyala\n* Anton Ballmaier\n* Aron\n* Benjamin Hackl\n* Clar Fon\n* Darylgolden\n* Devin Neal\n* Jan-Hendrik Müller\n* Jason Villanueva\n* KingWampy\n* Laith Bahodi\n* Mark Miller\n* MathInvariance\n* Mohammad Al-Fetyani\n* Naveen M K\n* Nikhil Garuda\n* Oliver\n* Philipp Imhof\n* Raghav Goel\n* Ryan McCauley\n* Ujjayanta\n* Vagrid\n* friedkeenan\n\nPull requests merged\n====================\n\nA total of 76 pull requests were merged for this release.\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`1616`: Remove all functions and classes that were deprecated until ``v0.6.0``\n\n\nNew features\n------------\n\n* :pr:`1716`: Rewrite stroke and fill shaders\n   Rewrite vectorized mobject shaders to be compatible with transformation matrices.\n\n* :pr:`1695`: Add option to justify text with :class:`~.MarkupText`\n   A new parameter ``justify`` is added to :class:`~.MarkupText`. It can be used to justify a paragraph of text.\n\n* :pr:`1660`: Added support for ``.webm`` and transparency of videos in Jupyter notebooks\n   - Added support for generating ``webm`` videos via the command line flag ``--format=webm``\n   - Added transparency support for Jupyter notebooks\n\n* :pr:`1553`: Add dearpygui integration\n\n\nEnhancements\n------------\n\n* :pr:`1728`: Improved positioning and size of the OpenGL window; added some configuration options\n\n\n* :pr:`1733`: Let OpenGLMobject.copy return a deep copy by default\n\n\n* :pr:`1735`: Metaclass compatibility for `coordinate_system.py`, `Code` and `ParametricSurface`\n\n\n* :pr:`1585`: OpenGL compatibility via metaclass for :class:`~.Matrix`, :class:`~.DecimalNumber`, :class:`~.Variable`\n\n\n* :pr:`1713`: Exit the command line interface gracefully if no scene was chosen\n\n\n* :pr:`1652`: Refactored :class:`~.Mobject` and :class:`~.Scene` to no longer inherit from the abstract base class ``Container``\n   - Moved tests in ``test_container.py`` for :class:`Container` that test :class:`~.Scene` and :class:`~.Mobject` to their own files.\n   - Corrected various instances of incorrectly passed keyword arguments, or unused keyword arguments.\n\n* :pr:`1693`: Made the default arrowhead size for :class:`~.Arrow3D` smaller\n\n\n* :pr:`1678`: Allow some rate functions to assume values outside of [0, 1]; introduce clamping decorators\n   - Fixed animations so that certain rate functions (``running_start``, ``wiggle``, ``ease_in_back``, ``ease_out_back``, ``ease_in_out_back``, ``ease_in_elastic``, ``ease_out_elastic``, and ``ease_out_elastic``) can go outside the range from 0 to 1.\n   - Fixed lag ratios so that they're spaced out evenly within the time interval and the rate functions are applied to each animation individually, rather than having the rate function determine when the animation starts.\n   - Fixed faulty code for ``ease_in_out_expo``, ``ease_in_bounce``, ``ease_out_bounce``, and ``ease_in_out_bounce``.\n\n* :pr:`1649`: Made video file names in Jupyter notebook more readable\n\n\n* :pr:`1667`: Determine the default number of decimal places for :class:`~.NumberLine` labels automatically from the step size\n   As an example: If the step size is set to 0.5, labels will now show at least one decimal place.\n\n* :pr:`1608`: Color file paths in terminal; remove curly braces surrounding the file path in \"Partial movie file written in...\" messages\n\n\n* :pr:`1632`: OpenGL compatibility via metaclass: :class:`~.Group`\n\n\nFixed bugs\n----------\n\n* :pr:`1740`: Fix pillow to <8.3.0\n\n\n* :pr:`1729`: Fix bug when using :class:`~.Text` with the OpenGL renderer\n\n\n* :pr:`1675`: Fixed ignored fill and stroke colors for :class:`~.SVGMobject`\n\n\n* :pr:`1664`: Fixed accidental displacement in :class:`~.Axes` caused by ``include_numbers`` / ``numbers_to_include``\n\n\n* :pr:`1670`: Fixed missing ``numpy`` import in OpenGL shader example\n\n\n* :pr:`1636`: Fixed bugs and added examples to methods and classes in :mod:`manim.mobject.matrix`\n\n\n* :pr:`1614`: Fix tick issues and improve tick placement for :class:`~.NumberLine`\n\n\n* :pr:`1593`: Un-flip output of ``get_frame()`` when using the OpenGL renderer\n\n\n* :pr:`1619`: Fix output of automatically detected LaTeX errors\n\n\n* :pr:`1595`: Fixed a few CLI and rendering bugs\n   - Corrected issue where gifs were being logged with an incorrect extension\n   - Fixed issue where videos were output when format was set to png\n   - Added logging for png output\n   - Added precedence handling when the ``write_to_movie`` flag would conflict with ``--format``\n   - Fixed issue that caused png image output to be ignored when caching was enabled\n\n* :pr:`1635`: Added missing numpy import for :mod:`manim.mobject.probability`\n\n\n* :pr:`1634`: Fixed OpenGL examples for MacOS\n   Renamed deprecated ``gl_FragColor`` to ``fragColor``.\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`1732`: Remove reference to ``--plugins`` flag\n\n\n* :pr:`1734`: Fix inheritance graph background color\n\n\n* :pr:`1698`: Added an example for :class:`~.PMobject`\n\n\n* :pr:`1690`: Added an example for :class:`~.CoordinateSystem`\n\n\n* :pr:`1510`: Add a tutorial for using :class:`~.Text` and :class:`~.Tex`\n\n\n* :pr:`1685`: Added an example and parameter description for :class:`~.AnnularSector`\n\n\n* :pr:`1687`: Updated imports in ``geometry.py`` and added example to :class:`~.Arrow`\n\n\n* :pr:`1681`: Added an example for :class:`~.NumberLine`\n\n\n* :pr:`1697`: Added an example for :class:`~.PGroup`\n\n\n* :pr:`1594`: Several improvements to the documentation design and layout\n\n\n* :pr:`1696`: Added an example for :class:`~.DashedVMobject`\n\n\n* :pr:`1637`: Added an example for :class:`~.FunctionGraph`\n\n\n* :pr:`1626`: Added an example for :class:`~.Prism`\n\n\n* :pr:`1712`: Added a second example for :class:`~.DoubleArrow`\n\n\n* :pr:`1710`: Update copyright year in documentation to 2020-2021\n\n\n* :pr:`1708`: Fixed link to interactive example notebook\n\n\n* :pr:`1657`: Added an example for :class:`~.ParametricSurface`\n\n\n* :pr:`1642`: Added examples and docstrings for :class:`~.BarChart`\n\n\n* :pr:`1700`: Added an example for :meth:`~.Mobject.scale`\n\n\n* :pr:`1689`: Added an example for :class:`~.SurroundingRectangle`\n\n\n* :pr:`1627`: Added an example for :class:`~.Sphere`\n\n\n* :pr:`1569`: Added example to demonstrate differences between :class:`~.Transform` and :class:`~.ReplacementTransform`\n\n\n* :pr:`1647`: Added an example for :class:`~.Sector`\n\n\n* :pr:`1673`: Updated documentation examples for :class:`~.Text` and :class:`~.MarkupText`: set ``weight=BOLD`` instead of ``style``\n\n\n* :pr:`1650`: Added an example for :class:`~.ArcBetweenPoints`\n\n\n* :pr:`1628`: Added an example for :class:`~.NumberPlane`\n\n\n* :pr:`1646`: Added an example for :class:`~.Underline`\n\n\n* :pr:`1659`: Added more details to the Google Colab installation instructions\n\n\n* :pr:`1658`: Updated python requirement in the documentation\n\n\n* :pr:`1639`: Added an example for :class:`~.SampleSpace`\n\n\n* :pr:`1640`: Added an example for :class:`~.Point`\n\n\n* :pr:`1643`: Fixed ``RightArcAngleExample`` for :class:`~.Angle` in documentation\n\n\n* :pr:`1617`: Visually improved an example in our tutorial\n\n\n* :pr:`1641`: Added an example for :class:`~.ComplexPlane`\n\n\n* :pr:`1644`: Added an example for :class:`~.BackgroundRectangle`\n\n\n* :pr:`1633`: Added an example for :class:`~.Integer`\n\n\n* :pr:`1630`: Added an example for :class:`~.Arc`\n\n\n* :pr:`1631`: Added an example for :class:`~.BulletedList`\n\n\n* :pr:`1620`: Fixed reference to command line interface help command\n\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`1623`: CI: branch rename: master -> main\n\n\n* :pr:`1621`: Revert default template and add new templates\n\n\n* :pr:`1573`: PR template for the manim hackathon\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`1720`: Renamed incorrect references of ``master`` to ``main``\n\n\n* :pr:`1692`: Removed redundant warning in CLI parsing\n\n\n* :pr:`1651`: Small code cleanup for :class:`~.Polygram`\n\n\n* :pr:`1610`: Changed one image extension to lowercase letters\n\n\nNew releases\n------------\n\n* :pr:`1738`: Preparation for v0.8.0: added changelog and bumped version number\n"
  },
  {
    "path": "docs/source/changelog/0.9.0-changelog.rst",
    "content": "******\nv0.9.0\n******\n\n:Date: August 02, 2021\n\nContributors\n============\n\nA total of 35 people contributed to this\nrelease. People with a '+' by their names authored a patch for the first\ntime.\n\n* Alex Lembcke\n* Benjamin Hackl\n* Darylgolden\n* Devin Neal\n* Harivinay +\n* Hugues Devimeux\n* Jared Hughes +\n* Jason Villanueva\n* Kadatatlu Kishore +\n* KingWampy\n* LED Me Explain +\n* Laith Bahodi\n* Mohammad Al-Fetyani\n* Noam Zaks\n* Oliver\n* PaulCMurdoch\n* Raghav Prabhakar +\n* Ryan McCauley\n* Suhail Sherif +\n* Taektiek +\n* Udeshya Dhungana +\n* UraniumCronorum +\n* Vinh H. Pham (Vincent) +\n* ccn +\n* icedcoffeeee +\n* sahilmakhijani +\n* sparshg\n\n\nThe patches included in this release have been reviewed by\nthe following contributors.\n\n* Abhijith Muthyala\n* Alex Lembcke\n* Benjamin Hackl\n* Darylgolden\n* Devin Neal\n* Harivinay\n* Hugues Devimeux\n* Jan-Hendrik Müller\n* Jason Villanueva\n* KingWampy\n* Laith Bahodi\n* Lino\n* Mohammad Al-Fetyani\n* Oliver\n* Raghav Goel\n* Suhail Sherif\n* icedcoffeeee\n* sahilmakhijani\n* sparshg\n\nPull requests merged\n====================\n\nA total of 55 pull requests were merged for this release.\n\nHighlights\n----------\n\n* :pr:`1677`: Added a new :class:`~.Table` mobject\n   This brings easy-to-use and customizable tables to Manim. Several examples for this new mobject can be found at :mod:`the module documentation page <.mobject.table>` and its subpages.\n\nDeprecated classes and functions\n--------------------------------\n\n* :pr:`1848`: Deprecated parameters for :class:`~.DashedLine` and :class:`~.DashedVMobject`\n   - ``dash_spacing`` is an unused parameter\n   - ``positive_space_ratio`` has been replaced with the shorter name ``dashed_ratio``\n\n* :pr:`1773`: Remove all classes and functions that were deprecated until ``v0.7.0`` and ``v0.8.0``\n   The classes ``FadeInFrom``, ``FadeOutAndShift``, ``FadeOutToPoint``, ``FadeInFromPoint``, ``FadeInFromLarge``, ``VFadeIn``, ``VFadeOut``, ``VFadeInThenOut`` have been removed, use :class:`~.FadeIn` or :class:`~.FadeOut` with appropriate\n   keyword arguments instead.\n\n   The classes ``CircleIndicate``, ``ShowCreationThenDestruction``, ``AnimationOnSurroundingRectangle``, ``ShowPassingFlashAround``, ``ShowCreationThenDestructionAround``, ``ShowCreationThenFadeAround``, ``WiggleOutThenIn``, ``TurnInsideOut`` have been removed. Use :class:`~.Circumscribe`, :class:`~.ShowPassingFlash`, or :class:`~.Wiggle` instead.\n\n   The classes ``OpenGLTexMobject`` and ``OpenGLTextMobject`` have been removed, use :class:`~.MathTex` and :class:`~.Tex` instead. Also, ``VMobjectFromSVGPathstring`` has been removed, use :class:`~.SVGPathMobject` instead.\n\n   Finally, the utility functions ``get_norm`` and ``cross`` have been removed (use the corresponding Numpy methods instead), and the function ``angle_between`` has been replaced with ``angle_between_vectors``.\n\n* :pr:`1731`: Deprecated :class:`~.ParametricSurface` parameters\n   - ``u_min`` and ``u_max`` have been replaced by ``u_range``.\n   - ``v_min`` and ``v_max`` have been replaced by ``v_range``.\n\nNew features\n------------\n\n* :pr:`1780`: Allow non-numerical values to be added to :class:`~.NumberLine` and :class:`~.Axes`\n   - Added :meth:`.NumberLine.add_labels` method to :class:`~.NumberLine` which accepts a dictionary of positions/values.\n   - :meth:`.CoordinateSystem.add_coordinates` now accepts a dictionary too.\n\n* :pr:`1719`: Added a :class:`~.Broadcast` animation\n\n\n* :pr:`1765`: Added a static method :meth:`.Circle.from_three_points` for defining a circle from three points\n   - Added a new :func:`~.perpendicular_bisector` function in ``space_ops.py``\n\n* :pr:`1686`: Added :meth:`.ParametricSurface.set_fill_by_value`\n   This method enables a color gradient to be applied to a :class:`~.ParametricSurface`, including the ability to define at which points the colors should be centered.\n\nEnhancements\n------------\n\n* :pr:`1833`: Added OpenGL compatibility for :class:`~.VDict`, :meth:`~.Axes.get_line_graph` and :class:`~.FocusOn`\n\n\n* :pr:`1760`: Added ``window_size`` flag to manually adjust the size of the OpenGL window\n   Accepts a tuple in the form: ``x,y``.\n\n* :pr:`1823`: Reworked :class:`~.DashedVMobject`\n   Rewritten the logic to generate dashes\n\n* :pr:`1808`: OpenGL renderer updates\n   - Adds model matrices to all OpenGLVMobjects\n   - Improved performance on vectorized mobject shaders\n   - Added updaters that are part of the scene rather than a mobject\n\n* :pr:`1787`: Made :class:`~.DecimalNumber` apply color to the ellipsis\n   Made color apply to the dots when `show_ellipsis` is set to true in `DecimalNumber`\n\n* :pr:`1775`: Let :class:`~.Create` work on :class:`~.OpenGLSurface`\n\n\n* :pr:`1757`: Added warning when there is a large number of items to hash.\n\n\n* :pr:`1774`: Add the ``reverse`` parameter to :class:`~.Write`\n\n\nFixed bugs\n----------\n\n* :pr:`1722`: Fixed ``remover=True`` for :class:`~.AnimationGroup`\n\n\n* :pr:`1727`: Fixed some hot reload issues and compatibility with IDEs\n   - Fixed interactive embed issue where it would fail when running on non-tty terminals\n   - Fixed issue where file observer would error after the second run as the first observer was not closed\n\n* :pr:`1844`: Fixed the oversized :class:`~.Code` window with the OpenGL renderer\n\n\n* :pr:`1821`: Fixed issues concerning ``frame_center`` in :class:`~.ThreeDScene`\n   - Changing ``frame_center`` in a :class:`~.ThreeDScene` now actually changes the camera position.\n   - An animation with only ``frame_center`` animated will now be rendered properly.\n   - A black dot is not created at the origin once ``frame_center`` is animated.\n\n* :pr:`1826`: Fixed scaling issue with :meth:`.BarChart.change_bar_values`\n\n\n* :pr:`1839`: Allow passing arguments to ``.animate`` with the OpenGL renderer\n\n\n* :pr:`1791`: :meth:`~.Mobject.set_z_index` now sets all submobjects' ``z_index`` value\n\n\n* :pr:`1792`: Fixed bug that caused dry runs to fail when using the PNG format\n\n\n* :pr:`1790`: Fixed an import from ``manimlib``\n\n\n* :pr:`1782`: Fixed :class:`~.Tex` not working properly with the OpenGL renderer\n\n\n* :pr:`1783`: Fixed :meth:`~.OpenGLMobject.shuffle` function and added :meth:`~.Mobject.invert` to OpenGL\n\n\n* :pr:`1786`: Fixed :class:`~.DecimalNumber` not working properly when the number of digits changes\n\n\n* :pr:`1763`: Fixed not being able to set some CLI flags in the configuration file\n\n\n* :pr:`1776`: :meth:`.CoordinateSystem.get_riemann_rectangles` now uses the graph's range instead of the axes range\n   If no range specified, `get_riemann_rectangles` generates the rectangles only where the area is correctly bounded\n\n* :pr:`1770`: Rewrote :meth:`.OpenGLMobject.put_start_and_end_on` to work correctly in 3D\n\n\n* :pr:`1736`: Fixed :class:`~.LinearTransformationScene` crashing on multiple animations\n\n\nDocumentation-related changes\n-----------------------------\n\n* :pr:`1852`: Fixed docs for :meth:`.Coordinate_system.add_coordinates` and moved :class: `~.Code` example\n\n\n* :pr:`1807`: Updated installation instructions\n   - Added a warning about the incompatibility of different versions of Manim in the README\n   - Modified the admonition warning in the documentation\n   - Removed duplicated information from the README (``pip install manim`` is already covered in the docs)\n\n* :pr:`1739`: Added a section on creating a custom animation to the \"Manim's building blocks\" tutorial\n\n\n* :pr:`1835`: Updated documentation with information about reworked graphical unit test system\n\n\n* :pr:`1845`: Improve ``ThreeDSurfacePlot`` example in example gallery\n\n\n* :pr:`1842`: Removed instructions on installing Poetry from Developer Installation documentation, reference Poetry's documentation instead\n\n\n* :pr:`1829`: Switch the order of Scoop and Chocolatey in the docs for the Windows Installation\n\n\n* :pr:`1827`: Added ``robots.txt`` to prevent old versions of documentation from showing in search results\n\n\n* :pr:`1819`: Removed mention of ``-h`` CLI flag from documentation\n\n\n* :pr:`1813`: Removed unused variables from tutorial\n\n\n* :pr:`1815`: Added codespell to the list of used linters in the contribution guidelines\n\n\n* :pr:`1778`: Improve sidebar structure of the documentation's reference manual\n\n\n* :pr:`1749`: Added documentation and example for :meth:`.VMobject.set_fill`\n\n\n* :pr:`1743`: Edited the developer installation instructions to include information on cloning the repository\n\n\n* :pr:`1706`: Rework example for :class:`~.Variable`\n\n\nChanges concerning the testing system\n-------------------------------------\n\n* :pr:`1836`: Converted all the graphical tests to the new syntax\n\n\n* :pr:`1802`: Refactored graphical unit testing system, and implemented multi frames tests\n   This PR introduces a new ``@frames_comparison`` decorator which allows writing simple ``construct``-like functions as tests. Control data for new tests can be easily generated by calling ``pytest --set_test``.\n\nChanges to our development infrastructure\n-----------------------------------------\n\n* :pr:`1830`: Be more concise about the documentation URL in the PR template\n\n\nCode quality improvements and similar refactors\n-----------------------------------------------\n\n* :pr:`1851`: Renamed ``Tabular`` to :class:`~.Table`\n\n\n* :pr:`1817`: Remove pillow version requirement\n\n\n* :pr:`1806`: Fixed spelling mistake\n\n\n* :pr:`1745`: Updated the BibTeX template in the README to Manim v0.9.0\n\n\nNew releases\n------------\n\n* :pr:`1850`: Bump version number to ``v0.9.0`` and generate changelog\n"
  },
  {
    "path": "docs/source/changelog.rst",
    "content": "#########\nChangelog\n#########\n\nThis page contains a list of changes made between releases.\n\n.. toctree::\n    :maxdepth: 1\n\n    changelog/0.20.1-changelog\n    changelog/0.20.0-changelog\n    changelog/0.19.2-changelog\n    changelog/0.19.1-changelog\n    changelog/0.19.0-changelog\n    changelog/0.18.1-changelog\n    changelog/0.18.0.post0-changelog\n    changelog/0.18.0-changelog\n    changelog/0.17.3-changelog\n    changelog/0.17.2-changelog\n    changelog/0.17.1-changelog\n    changelog/0.17.0-changelog\n    changelog/0.16.0-changelog\n    changelog/0.15.2-changelog\n    changelog/0.15.1-changelog\n    changelog/0.15.0-changelog\n    changelog/0.14.0-changelog\n    changelog/0.13.1-changelog\n    changelog/0.13.0-changelog\n    changelog/0.12.0-changelog\n    changelog/0.11.0-changelog\n    changelog/0.10.0-changelog\n    changelog/0.9.0-changelog\n    changelog/0.8.0-changelog\n    changelog/0.7.0-changelog\n    changelog/0.6.0-changelog\n    changelog/0.5.0-changelog\n    changelog/0.4.0-changelog\n    changelog/0.3.0-changelog\n    changelog/0.2.0-changelog\n    changelog/0.1.1-changelog\n    changelog/0.1.0-changelog\n"
  },
  {
    "path": "docs/source/conf.py",
    "content": "# Configuration file for the Sphinx documentation builder.\n#\n# This file only contains a selection of the most common options. For a full\n# list see the documentation:\n# https://www.sphinx-doc.org/en/master/usage/configuration.html\n\nfrom __future__ import annotations\n\nimport os\nimport sys\nfrom datetime import datetime\nfrom pathlib import Path\n\nimport manim\nfrom manim.utils.docbuild.module_parsing import parse_module_attributes\n\n# -- Path setup --------------------------------------------------------------\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n\n\nsys.path.insert(0, os.path.abspath(\".\"))\n\n\n# -- Project information -----------------------------------------------------\n\nproject = \"Manim\"\ncopyright = f\"2020-{datetime.now().year}, The Manim Community Dev Team\"  # noqa: A001\nauthor = \"The Manim Community Dev Team\"\n\n\n# -- General configuration ---------------------------------------------------\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    \"sphinx.ext.autodoc\",\n    \"sphinx_copybutton\",\n    \"sphinx.ext.napoleon\",\n    \"sphinx.ext.autosummary\",\n    \"sphinx.ext.doctest\",\n    \"sphinx.ext.extlinks\",\n    \"sphinx.ext.viewcode\",\n    \"sphinxext.opengraph\",\n    \"manim.utils.docbuild.manim_directive\",\n    \"manim.utils.docbuild.autocolor_directive\",\n    \"manim.utils.docbuild.autoaliasattr_directive\",\n    \"sphinx.ext.graphviz\",\n    \"sphinx.ext.inheritance_diagram\",\n    \"sphinxcontrib.programoutput\",\n    \"myst_parser\",\n    \"sphinx_design\",\n    \"sphinx_reredirects\",\n]\n\n# Automatically generate stub pages when using the .. autosummary directive\nautosummary_generate = True\n\nmyst_enable_extensions = [\"colon_fence\", \"amsmath\", \"deflist\"]\n\n# redirects (for moved / deleted pages)\nredirects = {\n    \"installation/linux\": \"uv.html\",\n    \"installation/macos\": \"uv.html\",\n    \"installation/windows\": \"uv.html\",\n}\n\n# generate documentation from type hints\nALIAS_DOCS_DICT = parse_module_attributes()[0]\nautodoc_typehints = \"description\"\nautodoc_type_aliases = {\n    alias_name: f\"~manim.{module}.{alias_name}\"\n    for module, module_dict in ALIAS_DOCS_DICT.items()\n    for category_dict in module_dict.values()\n    for alias_name in category_dict\n}\nautoclass_content = \"both\"\n\n# controls whether functions documented by the autofunction directive\n# appear with their full module names\nadd_module_names = False\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = [\"_templates\"]\n\n# Custom section headings in our documentation\nnapoleon_custom_sections = [\"Tests\", (\"Test\", \"Tests\")]\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This pattern also affects html_static_path and html_extra_path.\nhtml_extra_path = [\"robots.txt\"]\n\nexclude_patterns: list[str] = []\n\n# -- Options for internationalization ----------------------------------------\n# Set the destination directory of the localized po files\nlocale_dirs = [\"../i18n/\"]\n\n# Splits the text in more pot files.\ngettext_compact = False\n\n# Remove useless metadata from po files.\ngettext_last_translator = \"\"\ngettext_language_team = \"\"\n\n# -- Options for HTML output -------------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\n\nhtml_theme = \"furo\"\nhtml_favicon = str(Path(\"_static/favicon.ico\"))\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = [\"_static\"]\n\nhtml_theme_options = {\n    \"source_repository\": \"https://github.com/ManimCommunity/manim/\",\n    \"source_branch\": \"main\",\n    \"source_directory\": \"docs/source/\",\n    \"light_logo\": \"manim-logo-sidebar.svg\",\n    \"dark_logo\": \"manim-logo-sidebar-dark.svg\",\n    \"light_css_variables\": {\n        \"color-content-foreground\": \"#000000\",\n        \"color-background-primary\": \"#ffffff\",\n        \"color-background-border\": \"#ffffff\",\n        \"color-sidebar-background\": \"#f8f9fb\",\n        \"color-brand-content\": \"#1c00e3\",\n        \"color-brand-primary\": \"#192bd0\",\n        \"color-link\": \"#c93434\",\n        \"color-link--hover\": \"#5b0000\",\n        \"color-inline-code-background\": \"#f6f6f6;\",\n        \"color-foreground-secondary\": \"#000\",\n    },\n    \"dark_css_variables\": {\n        \"color-content-foreground\": \"#ffffffd9\",\n        \"color-background-primary\": \"#131416\",\n        \"color-background-border\": \"#303335\",\n        \"color-sidebar-background\": \"#1a1c1e\",\n        \"color-brand-content\": \"#2196f3\",\n        \"color-brand-primary\": \"#007fff\",\n        \"color-link\": \"#51ba86\",\n        \"color-link--hover\": \"#9cefc6\",\n        \"color-inline-code-background\": \"#262626\",\n        \"color-foreground-secondary\": \"#ffffffd9\",\n    },\n}\nhtml_title = f\"Manim Community v{manim.__version__}\"\n\n# This specifies any additional css files that will override the theme's\nhtml_css_files = [\"custom.css\"]\n\nlatex_engine = \"lualatex\"\n\n# external links\nextlinks = {\n    \"issue\": (\"https://github.com/ManimCommunity/manim/issues/%s\", \"#%s\"),\n    \"pr\": (\"https://github.com/ManimCommunity/manim/pull/%s\", \"PR #%s\"),\n    \"user\": (\"https://github.com/%s\", \"@%s\"),\n}\n\n# opengraph settings\nogp_site_name = \"Manim Community | Documentation\"\nogp_site_url = \"https://docs.manim.community/\"\nogp_social_cards = {\n    \"image\": \"_static/logo.png\",\n}\n\n\n# inheritance_graph settings\ninheritance_graph_attrs = {\n    \"concentrate\": True,\n    \"size\": '\"\"',\n    \"splines\": \"ortho\",\n    \"nodesep\": 0.1,\n    \"ranksep\": 0.2,\n}\n\ninheritance_node_attrs = {\n    \"penwidth\": 0,\n    \"shape\": \"box\",\n    \"width\": 0.05,\n    \"height\": 0.05,\n    \"margin\": 0.05,\n}\n\ninheritance_edge_attrs = {\n    \"penwidth\": 1,\n}\n\nhtml_js_files = [\"responsiveSvg.js\"]\n\ngraphviz_output_format = \"svg\"\n"
  },
  {
    "path": "docs/source/contributing/development.md",
    "content": "# Manim Development Process\n\n## For first-time contributors\n\n1. Install git:\n\n   For instructions see <https://git-scm.com/>.\n\n2. Fork the project:\n\n   Go to <https://github.com/ManimCommunity/manim> and click the \"fork\" button\n   to create a copy of the project for you to work on. You will need a\n   GitHub account. This will allow you to make a \"Pull Request\" (PR)\n   to the ManimCommunity repo later on.\n\n3. Clone your fork to your local computer:\n\n   ```shell\n   git clone https://github.com/<your-username>/manim.git\n   ```\n\n   GitHub will provide both a SSH (`git@github.com:<your-username>/manim.git`) and\n   HTTPS (`https://github.com/<your-username>/manim.git`) URL for cloning.\n   You can use SSH if you have SSH keys setup.\n\n   :::{WARNING}\n   Do not clone the ManimCommunity repository. You must clone your own\n   fork.\n   :::\n\n4. Change the directory to enter the project folder:\n\n   ```shell\n   cd manim\n   ```\n\n5. Add the upstream repository, ManimCommunity:\n\n   ```shell\n   git remote add upstream https://github.com/ManimCommunity/manim.git\n   ```\n\n6. Now, `git remote -v` should show two remote repositories named:\n\n   - `origin`, your forked repository\n   - `upstream` the ManimCommunity repository\n\n7. Install the Python project management tool `uv`, as recommended\n   in our {doc}`installation guide for users </installation/uv>`.\n\n8. Let `uv` create a virtual environment for your development\n   installation by running\n\n   ```shell\n   uv sync\n   ```\n\n   In case you need (or want) to install some of the optional dependency\n   groups defined in our [`pyproject.toml`](https://github.com/ManimCommunity/manim/blob/main/pyproject.toml),\n   run `uv sync --all-extras`, or pass the `--extra` flag with the\n   name of a group, for example `uv sync --extra jupyterhub`.\n\n9. Install Pre-Commit:\n\n   ```shell\n   uv run pre-commit install\n   ```\n\n   This will ensure during development that each of your commits is properly\n   formatted against our linter and formatters.\n\nYou are now ready to work on Manim!\n\n## Develop your contribution\n\n1. Checkout your local repository's main branch and pull the latest\n   changes from ManimCommunity, `upstream`, into your local repository:\n\n   ```shell\n   git switch main\n   git pull --rebase upstream main\n   ```\n\n2. Create a branch for the changes you want to work on rather than working\n   off of your local main branch:\n\n   ```shell\n   git switch -c <new branch name> upstream/main\n   ```\n\n   This ensures you can easily update your local repository's main with the\n   first step and switch branches to work on multiple features.\n\n3. Write some awesome code!\n\n   You're ready to make changes in your local repository's branch.\n   You can add local files you've changed within the current directory with\n   `git add .`, or add specific files with\n\n   ```shell\n   git add <file/directory>\n   ```\n\n   and commit these changes to your local history with `git commit`. If you\n   have installed pre-commit, your commit will succeed only if none of the\n   hooks fail.\n\n   :::{tip}\n   When crafting commit messages, it is highly recommended that\n   you adhere to [these guidelines](https://www.conventionalcommits.org/en/v1.0.0/).\n   :::\n\n4. Add new or update existing tests.\n\n   Depending on your changes, you may need to update or add new tests. For new\n   features, it is required that you include tests with your PR. Details of\n   our testing system are explained in the {doc}`testing guide <testing>`.\n\n5. Update docstrings and documentation:\n\n   Update the docstrings (the text in triple quotation marks) of any functions\n   or classes you change and include them with any new functions you add.\n   See the {doc}`documentation guide <docs/docstrings>` for more information about how we\n   prefer our code to be documented. The content of the docstrings will be\n   rendered in the {doc}`reference manual <../reference>`.\n\n   :::{tip}\n   Use the {mod}`manim directive for Sphinx <manim.utils.docbuild.manim_directive>` to add examples\n   to the documentation!\n   :::\n\nAs far as development on your local machine goes, these are the main steps you\nshould follow.\n\n(polishing-changes-and-submitting-a-pull-request)=\n\n## Polishing Changes and Submitting a Pull Request\n\nAs soon as you are ready to share your local changes with the community\nso that they can be discussed, go through the following steps to open a\npull request. A pull request signifies to the ManimCommunity organization,\n\"Here are some changes I wrote; I think it's worthwhile for you to maintain\nthem.\"\n\n:::{note}\nYou do not need to have everything (code/documentation/tests) complete\nto open a pull request (PR). If the PR is still under development, please\nmark it as a draft. Community developers will still be able to review the\nchanges, discuss yet-to-be-implemented changes, and offer advice; however,\nthe more complete your PR, the quicker it will be merged.\n:::\n\n1. Update your fork on GitHub to reflect your local changes:\n\n   ```shell\n   git push -u origin <branch name>\n   ```\n\n   Doing so creates a new branch on your remote fork, `origin`, with the\n   contents of your local repository on GitHub. In subsequent pushes, this\n   local branch will track the branch `origin` and `git push` is enough.\n\n2. Make a pull request (PR) on GitHub.\n\n   In order to make the ManimCommunity development team aware of your changes,\n   you can make a PR to the ManimCommunity repository from your fork.\n\n   :::{WARNING}\n   Make sure to select `ManimCommunity/manim` instead of `3b1b/manim`\n   as the base repository!\n   :::\n\n   Choose the branch from your fork as the head repository - see the\n   screenshot below.\n\n   ```{image} /_static/pull-requests.png\n   :align: center\n   ```\n\n   Please make sure you follow the template (this is the default\n   text you are shown when first opening the 'New Pull Request' page).\n\nYour changes are eligible to be merged if:\n\n1. there are no merge conflicts\n2. the tests in our pipeline pass\n3. at least one (two for more complex changes) Community Developer approves the changes\n\nYou can check for merge conflicts between the current upstream/main and\nyour branch by executing `git pull upstream main` locally. If this\ngenerates any merge conflicts, you need to resolve them and push an\nupdated version of the branch to your fork of the repository.\n\nOur pipeline consists of a series of different tests that ensure\nthat Manim still works as intended and that the code you added\nsticks to our coding conventions.\n\n- **Code style**: We use the code style imposed\n  by [Black](https://black.readthedocs.io/en/stable/), [isort](https://pycqa.github.io/isort/)\n  and [flake8](https://flake8.pycqa.org/en/latest/). The GitHub pipeline\n  makes sure that the (Python) files changed in your pull request\n  also adhere to this code style. If this step of the pipeline fails,\n  fix your code formatting automatically by running `black <file or directory>` and `isort <file or directory>`.\n  To fix code style problems, run `flake8 <file or directory>` for a style report, and then fix the problems\n  manually that were detected by `flake8`.\n- **Tests**: The pipeline runs Manim's test suite on different operating systems\n  (the latest versions of Ubuntu, macOS, and Windows) for different versions of Python.\n  The test suite consists of two different kinds of tests: integration tests\n  and doctests. You can run them locally by executing `uv run pytest`\n  and `uv run pytest --doctest-modules manim`, respectively, from the\n  root directory of your cloned fork.\n- **Documentation**: We also build a version of the documentation corresponding\n  to your pull request. Make sure not to introduce any Sphinx errors, and have\n  a look at the built HTML files to see whether the formatting of the documentation\n  you added looks as you intended. You can build the documentation locally\n  by running `make html` from the `docs` directory. Make sure you have [Graphviz](https://graphviz.org/)\n  installed locally in order to build the inheritance diagrams. See {doc}`docs` for\n  more information.\n\nFinally, if the pipeline passes and you are satisfied with your changes: wait for\nfeedback and iterate over any requested changes. You will likely be asked to\nedit or modify your PR in one way or another during this process. This is not\nan indictment of your work, but rather a strong signal that the community\nwants to merge your changes! Once approved, your changes may be merged!\n\n### Further useful guidelines\n\n1. When submitting a PR, please mention explicitly if it includes breaking changes.\n2. When submitting a PR, make sure that your proposed changes are as general as\n   possible, and ready to be taken advantage of by all of Manim's users. In\n   particular, leave out any machine-specific configurations, or any personal\n   information it may contain.\n3. If you are a maintainer, please label issues and PRs appropriately and\n   frequently.\n4. When opening a new issue, if there are old issues that are related, add a link\n   to them in your new issue (even if the old ones are closed).\n5. When submitting a code review, it is highly recommended that you adhere to\n   [these general guidelines](https://conventionalcomments.org/).\n6. If you find stale or inactive issues that seem to be irrelevant, please post\n   a comment saying 'This issue should be closed', and a community developer\n   will take a look.\n7. Please do as much as possible to keep issues, PRs, and development in\n   general as tidy as possible.\n\nYou can find examples for the `docs` in several places:\nthe {doc}`Example Gallery <../examples>`, {doc}`Tutorials <../tutorials/index>`,\nand {doc}`Reference Classes <../reference>`.\n\n**Thank you for contributing!**\n"
  },
  {
    "path": "docs/source/contributing/docs/admonitions.rst",
    "content": "==================\nAdding Admonitions\n==================\n\nAdding Blocks for Tip, Note, Important etc. (Admonitions)\n---------------------------------------------------------\n\nThe following directives are called Admonitions. You\ncan use them to point out additional or important\ninformation. Here are some examples:\n\nSee also\n~~~~~~~~\n\n.. code-block:: rest\n\n   .. seealso::\n        Some ideas at :mod:`~.tex_mobject`, :class:`~.Mobject`, :meth:`~.Mobject.add_updater`, :attr:`~.Mobject.depth`, :func:`~.make_config_parser`\n\n.. seealso::\n    Some ideas at :mod:`~.tex_mobject`, :class:`~.Mobject`, :meth:`~.Mobject.add_updater`, :attr:`~.Mobject.depth`, :func:`~.make_config_parser`\n\n.. index:: reST directives; note\n\n\n\nNote\n~~~~\n\n.. code-block:: rest\n\n   .. note::\n      A note\n\n.. note::\n   A note\n\nTip\n~~~\n\n.. code-block:: rest\n\n   .. tip::\n      A tip\n\n.. tip::\n   A tip\n\nYou may also use the admonition **hint**, but this is very similar\nand **tip** is more commonly used in the documentation.\n\nImportant\n~~~~~~~~~\n\n.. code-block:: rest\n\n   .. important::\n      Some important information which should be considered.\n\n.. important::\n   Some important information which should be considered.\n\nWarning\n~~~~~~~\n\n.. code-block:: rest\n\n   .. warning::\n      Some text pointing out something that people should be warned about.\n\n.. warning::\n   Some text pointing out something that people should be warned about.\n\nYou may also use the admonitions **caution** or even **danger** if the\nseverity of the warning must be stressed.\n\nAttention\n~~~~~~~~~\n\n.. code-block:: rest\n\n   .. attention::\n      A attention\n\n.. attention::\n   A attention\n\nYou can find further information about Admonitions here: https://pradyunsg.me/furo/reference/admonitions/\n"
  },
  {
    "path": "docs/source/contributing/docs/docstrings.rst",
    "content": "=================\nAdding Docstrings\n=================\n\nA docstring is a string literal that is used right after the definition\nof a module, function, class, or method. They are used to document our code.\nThis page will give you a set of guidelines to write efficient and correct docstrings.\n\n\nFormatting the Docstrings\n-------------------------\n\nPlease begin the description of the class/function in the same line as\nthe 3 quotes:\n\n.. code:: py\n\n    def do_this():\n        \"\"\"This is correct.\n        (...)\n        \"\"\"\n\n\n    def dont_do_this():\n        \"\"\"\n        This is incorrect.\n        (...)\n        \"\"\"\n\nNumPy Format\n------------\nThe Manim Community uses numpy format for the documentation.\n\nUse the numpy format for sections and formatting - see\nhttps://numpydoc.readthedocs.io/en/latest/format.html.\n\nThis includes:\n\n1. The usage of ``Attributes`` to specify ALL ATTRIBUTES that a\n   class can have and a brief (or long, if\n   needed) description.\n\nAlso, ``__init__`` parameters should be specified as ``Parameters`` **on\nthe class docstring**, *rather than under* ``__init__``. Note that this\ncan be omitted if the parameters and the attributes are the same\n(i.e., dataclass) - priority should be given to the ``Attributes``\nsection, in this case, which must **always be present**, unless the\nclass specifies no attributes at all. (See more on Parameters in number\n2 of this list.)\n\nExample:\n\n.. code:: py\n\n    class MyClass:\n        \"\"\"My cool class. Long or short (whatever is more appropriate) description here.\n\n        Parameters\n        ----------\n        name\n            The class's name.\n        id\n            The class's id.\n        mobj\n            The mobject linked to this instance. Defaults to `Mobject()` \\\n    (is set to that if `None` is specified).\n\n        Attributes\n        ----------\n        name\n            The user's name.\n        id\n            The user's id.\n        singleton\n            Something.\n        mobj\n            The mobject linked to this instance.\n        \"\"\"\n\n        def __init__(name: str, id: int, singleton: MyClass, mobj: Mobject = None): ...\n\n2. The usage of ``Parameters`` on functions to specify how\n   every parameter works and what it does. This should be excluded if\n   the function has no parameters. Note that you **should not** specify\n   the default value of the parameter on the type. On the documentation\n   render, this is already specified on the function's signature. If you\n   need to indicate a further consequence of value omission or simply\n   want to specify it on the docs, make sure to **specify it in the\n   parameter's DESCRIPTION**.\n\nSee an example on list item 4.\n\n.. note::\n\n   When documenting varargs (args and kwargs), make sure to\n   document them by listing the possible types of each value specified,\n   like this:\n\n::\n\n    Parameters\n    ----------\n    args\n      The args specified can be either an int or a float.\n    kwargs\n      The kwargs specified can only be a float.\n\nNote that, if the kwargs expect specific values, those can be specified\nin a section such as ``Other Parameters``:\n\n::\n\n    Other Parameters\n    ----------------\n    kwarg_param_1\n      Parameter documentation here\n    (etc)\n\n3. The usage of ``Returns`` to indicate what is the type of this\n   function's return value and what exactly it returns (i.e., a brief -\n   or long, if needed - description of what this function returns). Can\n   be omitted if the function does not explicitly return (i.e., always\n   returns ``None`` because ``return`` is never specified, and it is\n   very clear why this function does not return at all). In all other\n   cases, it should be specified.\n\nSee an example on list item 4.\n\n4. The usage of ``Examples`` in order to specify an example of usage of\n   a function **is highly encouraged** and, in general, should be\n   specified for *every function* unless its usage is **extremely\n   obvious**, which can be debatable. Even if it is, it's always a good\n   idea to add an example in order to give a better orientation to the\n   documentation user. Use the following format for Python code:\n\n   .. code:: rst\n\n       ::\n\n       # python code here\n\n.. note::\n   Also, if this is a video- or animation-related change, please\n   try to add an example GIF or video if possible for demonstration\n   purposes.\n\nMake sure to be as explicit as possible in your documentation. We all\nwant the users to have an easier time using this library.\n\nExample:\n\n.. code:: py\n\n    def my_function(\n        thing: int,\n        other: np.ndarray,\n        name: str,\n        *,\n        d: \"SomeClassFromFarAway\",\n        test: Optional[int] = 45\n    ) -> \"EpicClassInThisFile\":  # typings are optional for now\n        \"\"\"My cool function. Builds and modifies an :class:`EpicClassInThisFile` instance with the given\n            parameters.\n\n        Parameters\n        ----------\n        thing\n            Specifies the index of life.\n        other\n            Specifies something cool.\n        name\n            Specifies my name.\n        d\n            Sets thing D to this value.\n        test\n            Defines the number of times things should be tested. \\\n        Defaults to 45, because that is almost the meaning of life.\n\n        Returns\n        -------\n        :class:`EpicClassInThisFile`\n            The generated EpicClass with the specified attributes and modifications.\n\n        Examples\n        --------\n        Normal usage::\n\n            my_function(5, np.array([1, 2, 3]), \"Chelovek\", d=SomeClassFromFarAway(cool=True), test=5)\n        \"\"\"\n        # code...\n        pass\n"
  },
  {
    "path": "docs/source/contributing/docs/examples.rst",
    "content": "===============\nAdding Examples\n===============\n\nThis is a page for adding examples to the documentation.\nHere are some guidelines you should follow before you publish your examples.\n\nGuidelines for examples\n-----------------------\n\nEverybody is welcome to contribute examples to the documentation. Since straightforward\nexamples are a great resource for quickly learning manim, here are some guidelines.\n\nWhat makes a great example\n--------------------------\n\n.. note::\n\n   As soon as a new version of manim is released, the documentation will be a snapshot of that\n   version. Examples contributed after the release will only be shown in the latest documentation.\n\n* Examples should be ready to copy and paste for use.\n\n* Examples should be brief yet still easy to understand.\n\n* Examples don't require the ``from manim import *`` statement, this will be added automatically when the docs are built.\n\n* There should be a balance of animated and non-animated examples.\n\n- As manim makes animations, we can include lots of animated examples; however, our RTD has a maximum 20 minutes to build. Animated examples should only be used when necessary, as last frame examples render faster.\n\n- Lots of examples (e.g. size of a plot-axis, setting opacities, making texts, etc.) will also work as images. It is a lot more convenient to see the end product immediately instead of waiting for an animation to reveal it.\n\n* Please ensure the examples run on the current main branch when you contribute an example.\n\n* If the functions used are confusing for people, make sure to add comments in the example to explain what they do.\n\nHow examples are structured\n---------------------------\n\n* Examples can be organized into chapters and subchapters.\n\n- When you create examples, the beginning example chapter should focus on only one functionality. When the functionality is simple, multiple ideas can be illustrated under a single example.\n\n- As soon as simple functionalities are explained, the chapter may include more complex examples which build on the simpler ideas.\n\nWriting examples\n~~~~~~~~~~~~~~~~\n\nWhen you want to add/edit examples, they can be found in the ``docs/source/`` directory, or directly in the manim source code (e.g. ``manim/mobject/mobject.py``). The examples are written in\n``rst`` format and use the manim directive (see :mod:`manim.utils.docbuild.manim_directive` ), ``.. manim::``. Every example is in its own block, and looks like this:\n\n.. code:: rst\n\n    Formulas\n    ========\n\n    .. manim:: Formula1\n        :save_last_frame:\n\n        class Formula1(Scene):\n            def construct(self):\n                t = MathTex(r\"\\int_a^b f'(x) dx = f(b) - f(a)\")\n                self.add(t)\n                self.wait(1)\n\nIn the building process of the docs, all ``rst`` files are scanned, and the\nmanim directive (``.. manim::``) blocks are identified as scenes that will be run\nby the current version of manim.\nHere is the syntax:\n\n* ``.. manim:: [SCENE_NAME]`` has no indentation and ``SCENE_NAME`` refers to the name of the class below.\n\n* The flags are followed in the next line (no blank line here!), with the indentation level of one tab.\n\nAll possible flags can be found at :mod:`manim.utils.docbuild.manim_directive`.\n\nIn the example above, the ``Formula1`` following ``.. manim::`` is the scene\nthat the directive expects to render; thus, in the python code, the class\nhas the same name: ``class Formula1(Scene)``.\n\n.. note::\n\n   Sometimes, when you reload an example in your browser, it has still the old\n   website somewhere in its cache. If this is the case, delete the website cache,\n   or open a new incognito tab in your browser, then the latest docs\n   should be shown.\n   **Only for locally built documentation:** If this still doesn't work, you may need\n   to delete the contents of ``docs/source/references`` before rebuilding\n   the documentation.\n"
  },
  {
    "path": "docs/source/contributing/docs/references.rst",
    "content": "=================\nAdding References\n=================\n\nReference to types in documentation\n-----------------------------------\n\nAlways specify types with the correct **role** (see\nhttps://www.sphinx-doc.org/en/1.7/domains.html#python-roles) for the\nsake of proper rendering. E.g.: Use ``:class:`int``` to refer to an int\ntype, and in general ``:class:`<path>`​`` to refer to a certain class\n(see ``Path specification`` below). See after for more specific\ninstructions.\n\nPath specifications\n~~~~~~~~~~~~~~~~~~~\n\n1. If it's on stdlib: Use ``<name>`` directly. If it's a class, just the\n   name is enough. If it's a method (``:meth:``) or attribute\n   (``:attr:``), dotted names may be used (e.g.\n   ``:meth:`str.to_lower`​``).\n\nExample: ``:class:`int`​``, ``:class:`str`​``, ``:class:`float`​``,\n``:class:`bool`​``\n\n2. If it's on the same file as the docstring or, for methods and\n   attributes, under the same class, then the name may also be specified\n   directly.\n\nExample: ``:class:`MyClass`​`` referring to a class in the same file;\n``:meth:`push`​`` referring to a method in the same class;\n``:meth:`MyClass.push`​`` referring to a method in a different class in\nthe same file; ``:attr:`color`​`` referring to an attribute in the same\nclass; ``:attr:`MyClass.color`​`` referring to an attribute in a\ndifferent class in the same file.\n\n3. If it's on a different file, then you may either use the full dotted\n   name (e.g. ``~manim.animations.Animation``) or simply use the\n   shortened way (``~.Animation``). Note that, if there is ambiguity,\n   then the full dotted name must be used where the actual class can't\n   be deduced. Also, note the ``~`` before the path - this is so that it\n   displays just ``Animation`` instead of the full location in the\n   rendering. It can be removed for disambiguation purposes only.\n\nExample: ``:class:`~.Animation`​``, ``:meth:`~.VMobject.set_color`​``,\n``:attr:`~.VMobject.color`​``\n\n4. If it's a class from a different module, specify the full dotted\n   syntax.\n\nExample: ``:class:`numpy.ndarray`​`` for a numpy ndarray.\n\nReference type specifications\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n**The following instructions refer to types of attributes, parameters,\nand return values.** When specifying a type mid-text, it does not\nnecessarily have to be typeset. However, if it's a class name, a method,\nor an enum's attribute/variant, then it is recommended to be typeset at\nleast on the first occurrence of the name so that the users can quickly\njump to the related documentation.\n\n1. Class names should be wrapped in ``:class:`path_goes_here`​``. See\n   examples in the subsection above.\n2. Method names should be wrapped in ``:meth:`path_goes_here`​``. See\n   examples in the subsection above.\n3. Attribute names should be wrapped in ``:attr:`path_goes_here`​``. See\n   examples in the subsection above.\n4. If ``None`` can also be specified, use ``Optional[type]``, where\n   ``type`` must follow the guidelines in the current section.\n\nExample: ``Optional[:class:`str`]`` means you can either specify a\n``str`` or ``None``.\n\n5. If more than one type is possible, use\n   ``Union[type_1, type_2, (...), type_n]``, where all the ``type_n``\n   must follow the guidelines in the current section. Note that, if one\n   of these types is ``None``, then the Union should be wrapped with\n   ``Optional`` instead.\n\nExample: ``Union[:class:`str`, :class:`int`]`` for either ``str`` or\n``int``. ``Optional[Union[:class:`int`, :class:`bool`]]`` for either\n``int``, ``bool`` or ``None``.\n\n6. **Dictionaries:** Use ``Dict[key_type, value_type]``, where\n   ``key_type`` and ``value_type`` must follow the guidelines in the\n   current section.\n\nExample: ``Dict[:class:`str`, :class:`~.Mobject`]`` is a dictionary that\nmaps strings to Mobjects.\n``Dict[:class:`str`, Union[:class:`int`, :class:`MyClass`]]`` is a\ndictionary that maps a string to either an int or an instance of\n``MyClass``.\n\n7. **If the parameter is a list:** Note that it is very rare to require\n   the parameter to be exactly a ``list`` type. One could usually\n   specify a ``tuple`` instead, for example. So, in order to cover all\n   cases, consider:\n\n   1. If the parameter only needs to be an ``Iterable``, i.e., if the\n      function only requires being able to iterate over this parameter's\n      value (e.g. can be a ``list``, ``tuple``, ``str``, but also\n      ``zip()``, ``iter()`` and so on), then specify\n      ``Iterable[type_here]``, where ``type_here`` is the type of the\n      iterable's yielded elements and should follow the format in the\n      present section (``Type specifications``).\n\n   Example: ``Iterable[:class:`str`]`` for any iterable of strings;\n   ``Iterable[:class:`~.Mobject`]`` for an iterable of Mobjects; etc.\n\n   2. If you require being able to index the parameter (i.e. ``x[n]``)\n      or retrieve its length (i.e. ``len(x)``), or even just pass it to\n      a function that requires any of those, then specify ``Sequence``,\n      which allows any list-like object to be specified (e.g. ``list``,\n      ``tuple``...)\n\n   Example: ``Sequence[:class:`str`]`` for a sequence of strings;\n   ``Sequence[Union[:class:`str`, :class:`int`]]`` for a sequence of\n   integers or strings.\n\n   3. If you EXPLICITLY REQUIRE it to be a ``list`` for some reason,\n      then use ``List[type]``, where ``type`` is the type that any\n      element in the list will have. It must follow the guidelines in\n      the current section.\n\n8. **If the return type is a list or tuple:** Specify ``List[type]`` for\n   a list, ``Tuple[type_a, type_b, (...), type_n]`` for a tuple (if the\n   elements are all different) or ``Tuple[type, ...]`` (if all elements\n   have the same type). Each ``type_n`` on those representations\n   corresponds to elements in the returned list/tuple and must follow\n   the guidelines in the current section.\n\nExample: ``List[Optional[:class:`str`]]`` for a list that returns\nelements that are either a ``str`` or ``None``;\n``Tuple[:class:`str`, :class:`int`]`` for a tuple of type\n``(str, int)``; ``Tuple[:class:`int`, ...]`` for a tuple of variable\nlength with only integers.\n"
  },
  {
    "path": "docs/source/contributing/docs/types.rst",
    "content": "===================\nChoosing Type Hints\n===================\nIn order to provide the best user experience,\nit's important that type hints are chosen correctly.\nWith the large variety of types provided by Manim, choosing\nwhich one to use can be difficult. This guide aims to\naid you in the process of choosing the right type for the scenario.\n\n\nThe first step is figuring out which category your type hint fits into.\n\nCoordinates\n-----------\nCoordinates encompass two main categories: points, and vectors.\n\n\nPoints\n~~~~~~\nThe purpose of points is pretty straightforward: they represent a point\nin space. For example:\n\n.. code-block:: python\n\n   def print_point2D(coord: Point2DLike) -> None:\n       x, y = coord\n       print(f\"Point at {x=},{y=}\")\n\n\n   def print_point3D(coord: Point3DLike) -> None:\n       x, y, z = coord\n       print(f\"Point at {x=},{y=},{z=}\")\n\n\n   def print_point_array(coords: Point2DLike_Array | Point3DLike_Array) -> None:\n       for coord in coords:\n           if len(coord) == 2:\n               # it's a Point2DLike\n               print_point2D(coord)\n           else:\n               # it's a Point3DLike\n               print_point3D(coord)\n\n   def shift_point_up(coord: Point3DLike) -> Point3D:\n       result = np.asarray(coord)\n       result += UP\n       print(f\"New point: {result}\")\n       return result\n\nNotice that the last function, ``shift_point_up()``, accepts a\n:class:`~.Point3DLike` as a parameter and returns a :class:`~.Point3D`. A\n:class:`~.Point3D` always represents a NumPy array consisting of 3 floats,\nwhereas a :class:`~.Point3DLike` can represent anything resembling a 3D point:\neither a NumPy array or a tuple/list of 3 floats, hence the ``Like`` word. The\nsame happens with :class:`~.Point2D`, :class:`~.Point2D_Array` and\n:class:`~.Point3D_Array`, and their ``Like`` counterparts\n:class:`~.Point2DLike`, :class:`~.Point2DLike_Array` and\n:class:`~.Point3DLike_Array`.\n\nThe rule for typing functions is: **make parameter types as broad as possible,\nand return types as specific as possible.** Therefore, for functions which are\nintended to be called by users, **we should always, if possible, accept**\n``Like`` **types as parameters and return NumPy, non-** ``Like`` **types.** The\nmain reason is to be more flexible with users who might want to pass tuples or\nlists as arguments rather than NumPy arrays, because it's more convenient. The\nlast function, ``shift_point_up()``, is an example of it.\n\nInternal functions which are *not* meant to be called by users may accept\nnon-``Like`` parameters if necessary.\n\nVectors\n~~~~~~~\nVectors share many similarities to points. However, they have a different\nconnotation. Vectors should be used to represent direction. For example,\nconsider this slightly contrived function:\n\n.. code-block:: python\n\n   M = TypeVar(\"M\", bound=Mobject)  # allow any mobject\n   def shift_mobject(mob: M, direction: Vector3D, scale_factor: float = 1) -> M:\n       return mob.shift(direction * scale_factor)\n\nHere we see an important example of the difference. ``direction`` should not be\ntyped as a :class:`~.Point3D`, because it represents a direction along\nwhich to shift a :class:`~.Mobject`, not a position in space.\n\nAs a general rule, if a parameter is called ``direction`` or ``axis``,\nit should be type hinted as some form of :class:`~.VectorND` or\n:class:`~.VectorNDLike`.\n\nColors\n------\nThe interface Manim provides for working with colors is :class:`.ManimColor`.\nThe main color types Manim supports are RGB, RGBA, and HSV. You will want\nto add type hints to a function depending on which type it uses. If any color will work,\nyou will need something like:\n\n.. code-block:: python\n\n   if TYPE_CHECKING:\n       from manim.utils.color import ParsableManimColor\n\n   # type hint stuff with ParsableManimColor\n\n\n\nBéziers\n-------\nManim internally represents a :class:`.Mobject` by a collection of points. In the case of :class:`.VMobject`,\nthe most commonly used subclass of :class:`.Mobject`, these points represent Bézier curves,\nwhich are a way of representing a curve using a sequence of points.\n\n.. note::\n\n   To learn more about Béziers, take a look at https://pomax.github.io/bezierinfo/\n\n\nManim supports two different renderers, which each have different representations of\nBéziers: Cairo uses cubic Bézier curves, while OpenGL uses quadratic Bézier curves.\n\nType hints like :class:`~.typing.BezierPoints` represent a single bezier curve, and :class:`~.typing.BezierPath`\nrepresents multiple Bézier curves. A :class:`~.typing.Spline` is when the Bézier curves in a :class:`~.typing.BezierPath`\nforms a single connected curve. Manim also provides more specific type aliases when working with\nquadratic or cubic curves, and they are prefixed with their respective type (e.g. :class:`~.typing.CubicBezierPoints`,\nis a :class:`~.typing.BezierPoints` consisting of exactly 4 points representing a cubic Bézier curve).\n\n\nFunctions\n---------\nThroughout the codebase, many different types of functions are used. The most obvious example\nis a rate function, which takes in a float and outputs a float (``Callable[[float], float]``).\nAnother example is for overriding animations. One will often need to map a :class:`.Mobject`\nto an overridden :class:`.Animation`, and for that we have the :class:`~.typing.FunctionOverride` type hint.\n\n:class:`~.typing.PathFuncType` and :class:`~.typing.MappingFunction` are more niche, but are related to moving objects\nalong a path, or applying functions. If you need to use it, you'll know.\n\n\nImages\n------\nThere are several representations of images in Manim. The most common is\nthe representation as a NumPy array of floats representing the pixels of an image.\nThis is especially common when it comes to the OpenGL renderer.\n\nThis is the use case of the :class:`~.typing.PixelArray` type hint. Sometimes, Manim may use ``PIL.Image.Image``,\nwhich is not the same as :class:`~.typing.PixelArray`. In this case, use the ``PIL.Image.Image`` typehint.\nOf course, if a more specific type of image is needed, it can be annotated as such.\n"
  },
  {
    "path": "docs/source/contributing/docs/typings.rst",
    "content": "==================\nTyping Conventions\n==================\n\n.. warning::\n   This section is still a work in progress.\n\nAdding type hints to functions and parameters\n---------------------------------------------\n\nManim is currently in the process of adding type hints into the library. In this\nsection, you will find information about the standards used and some general\nguidelines.\n\nIf you've never used type hints before, this is a good place to get started:\nhttps://realpython.com/python-type-checking/#hello-types.\n\nTyping standards\n~~~~~~~~~~~~~~~~\n\nManim uses `mypy`_ to type check its codebase. You will find a list of configuration values in the ``mypy.ini`` configuration file.\nTo be able to use the newest typing features not available in the lowest\nsupported Python version, make use of `typing_extensions`_.\n\nTo be able to use the new Union syntax (``|``) and builtins subscripting, use\nthe ``from __future__ import annotations`` import.\n\n.. _mypy: https://mypy-lang.org/\n.. _typing_extensions: https://pypi.org/project/typing-extensions/\n\nTyping guidelines\n~~~~~~~~~~~~~~~~~\n\n* Manim has a dedicated :mod:`~.typing` module where type aliases are provided.\n  Most of them may seem redundant, in particular the ones related to ``numpy``.\n  This is in anticipation of the support for shape type hinting\n  (`related issue <https://github.com/numpy/numpy/issues/16544>`_). Besides the\n  pending shape support, using the correct type aliases will help users understand\n  which shape should be used.\n\n* For typings of generic collections, check out `this <https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes>`_\n  link.\n\n* Always use a type hint of ``None`` for functions that does not return\n  a value (this also applies to ``__init__``), e.g.:\n\n.. code:: py\n\n    def height(self, value) -> None:\n        self.scale_to_fit_height(value)\n\n* For variables representing paths, use the ``StrPath`` or ``StrOrBytesPath``\n  type alias defined in the :mod:`~.typing` module.\n\n* ``*args`` and ``**kwargs`` shouldn't be left untyped (in most cases you can\n  use ``Any``).\n\n* Following `PEP 484 <https://peps.python.org/pep-0484/#the-numeric-tower>`_,\n  use ``float`` instead of ``int | float``.\n\n* Use ``x | y`` instead of ``Union[x, y]``\n\n* Mobjects have the typehint ``Mobject``, e.g.:\n\n.. code:: py\n\n    def match_color(self, mobject: \"Mobject\"):\n        \"\"\"Match the color with the color of another :class:`~.Mobject`.\"\"\"\n        return self.set_color(mobject.get_color())\n\n* Always parametrize generics (``list[int]`` instead of ``list``,\n  ``type[Any]`` instead of ``type``, etc.). This also applies to callables.\n\n.. code:: py\n\n    rate_func: Callable[[float], float] = lambda t: smooth(1 - t)\n\n* Use ``TypeVar`` when you want to \"link\" type hints as being the same type.\n  Consider ``Mobject.copy``, which returns a new instance of the same class.\n  It would be type-hinted as:\n\n.. code:: py\n\n    T = TypeVar(\"T\")\n\n\n    def copy(self: T) -> T: ...\n\n* Use ``typing.Iterable`` whenever the function works with *any* iterable, not a specific type.\n\n* Prefer ``numpy.typing.NDArray`` over ``numpy.ndarray``\n\n.. code:: py\n\n   import numpy as np\n\n   if TYPE_CHECKING:\n       import numpy.typing as npt\n\n\n   def foo() -> npt.NDArray[float]:\n       return np.array([1, 0, 1])\n\n* If a method returns ``self``, use ``typing_extensions.Self``.\n\n.. code:: py\n\n   if TYPE_CHECKING:\n       from typing_extensions import Self\n\n\n   class CustomMobject:\n       def set_color(self, color: ManimColor) -> Self:\n           ...\n           return self\n\n* If the function returns a container of a specific length each time, consider using ``tuple`` instead of ``list``.\n\n.. code:: py\n\n   def foo() -> tuple[float, float, float]:\n       return (0, 0, 0)\n\n* If a function works with a parameter as long as said parameter has a ``__getitem__``, ``__iter___`` and ``__len__`` method,\n  the typehint of the parameter should be ``collections.abc.Mapping``. If it also supports ``__setitem__`` and/or ``__delitem__``, it\n  should be marked as ``collections.abc.MutableMapping``.\n\n* Typehinting something as ``object`` means that only attributes available on every Python object should be accessed,\n  like ``__str__`` and so on. On the other hand, literally any attribute can be accessed on a variable with the ``Any`` typehint -\n  it's more freeing than the ``object`` typehint, and makes mypy stop typechecking the variable. Note that whenever possible,\n  try to keep typehints as specific as possible.\n\n* If objects are imported purely for type hint purposes, keep it under an ``if typing.TYPE_CHECKING`` guard, to prevent them from\n  being imported at runtime (helps library performance). Do not forget to use the ``from __future__ import annotations`` import to avoid having runtime ``NameError`` exceptions.\n\n.. code:: py\n\n   from typing import TYPE_CHECKING\n\n   if TYPE_CHECKING:\n       from manim.typing import Vector3D\n   # type stuff with Vector3D\n\nMissing Sections for typehints are:\n-----------------------------------\n\n* Mypy and numpy import errors: https://realpython.com/python-type-checking/#running-mypy\n* Explain ``mypy.ini`` (see above link)\n"
  },
  {
    "path": "docs/source/contributing/docs.rst",
    "content": "====================\nAdding Documentation\n====================\n\nBuilding the documentation\n--------------------------\n\nWhen you clone the Manim repository from GitHub, you can access the\n``docs/`` folder which contains the necessary files to build the\ndocumentation.\n\nTo build the docs locally, open a CLI, enter the ``docs/`` folder with the\n``cd`` command and execute the following depending on your OS:\n\n-   Windows: ``./make.bat html``\n-   macOS and Linux: ``make html``\n\nThe first time you build the docs, the process will take several\nminutes because it needs to generate all the ``.rst`` (reST:\nreStructured Text) files from scratch by reading and parsing all the\nManim content. The process becomes much shorter the next time, as it\nrebuilds only the parts which have changed.\n\n\nSphinx library and extensions\n-----------------------------\n\nManim uses `Sphinx <https://www.sphinx-doc.org>`_ for building the\ndocs. It also makes use of Sphinx extensions such as:\n\n-   `Autodoc: <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`_\n    imports Manim's Python source code, extracts its docstrings and\n    generates documentation from them.\n-   `Autosummary: <https://www.sphinx-doc.org/en/master/usage/extensions/autosummary.html>`_\n    a complement to Autodoc which adds a special directive ``autosummary``,\n    used in Manim to automatically document classes, methods,\n    attributes, functions, module-level variables and exceptions.\n    Autosummary makes use of `Jinja templates <https://jinja.palletsprojects.com/templates/>`_,\n    which Manim defines for autosummarizing classes and modules\n    inside ``docs/source/_templates/``.\n-   `Graphviz extension for Sphinx: <https://www.sphinx-doc.org/en/master/usage/extensions/graphviz.html>`_\n    embeds graphs generated by the `Graphviz <https://graphviz.org/>`_\n    module, which must be installed in order to render the\n    inheritance diagrams in the :doc:`/reference`.\n-   `Napoleon: <https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html>`_\n    enables Sphinx to read Google style docstrings and, in\n    particular for Manim, `NumPy style docstrings <https://numpydoc.readthedocs.io/en/latest/format.html>`_\n    - see :doc:`docs/docstrings` for more information.\n\n\nSphinx theme\n------------\n\nThe theme used for this website is `Furo <https://sphinx-themes.org/sample-sites/furo/>`_.\n\n\nCustom Sphinx directives\n------------------------\n\nManim implements **custom directives** for use with Autodoc and Autosummary, which\nare defined in :mod:`~.docbuild`:\n\n.. currentmodule:: manim.utils.docbuild\n\n.. autosummary::\n\n    :toctree: ../reference\n    autoaliasattr_directive\n    autocolor_directive\n    manim_directive\n\n\nIndex\n-----\n\n.. toctree::\n   :maxdepth: 2\n\n   docs/admonitions\n   docs/docstrings\n   docs/examples\n   docs/references\n   docs/typings\n   docs/types\n"
  },
  {
    "path": "docs/source/contributing/internationalization.rst",
    "content": "====================\nInternationalization\n====================\n\nThank you for your interest in localizing Manim! Please read the\ninstructions below to get started. You are also encouraged, though not\nrequired, to join our `Discord\nserver <https://manim.community/discord>`__.\n\nSigning up\n==========\n\nYou will first need to create an account for our project. Go to our\n`project homepage <https://translate.manim.community/>`__ and click the\nsign up button at the top right hand corner. Follow the instructions to\ncreate an account. After creating an account, you should return back to\nour homepage. Click the Manim project to contribute translations for the\nmain library.\n\nContributing\n============\n\n.. important::\n   Keep in mind that Manim is still a work in progress.\n   Tutorials and documentation are always subject to change.\n   When a developer implements a new feature, they are not forced to respect any translations.\n   This means that parts of the translation might become outdated over time.\n\nThat being said, improving the documentation and making it more accessible is still highly encouraged.\nAnd even if your work gets outdated and requires change, you or someone else can simply adjust the translation.\nYour efforts are not in vain!\n\n\nVoting\n------\n\nTo ensure that our translations are of good quality, we use\ncrowdsourcing and voting to approve good translations and reject bad\nones. The current threshold for a translation being accepted is 3 votes;\nthis may change as we gauge the level of activity in the community and\nthe quality of translations.\n\nTo vote on translations, first click on a language you would like to\nhelp with, then click the \"translate all\" button. You should then enter\nthe translation editor. Next to the search bar, you will see a\nfunnel-like icon - click it and select the \"Need to Be Voted\" option to\nsee translations that need to be voted on. You can then select a string\non the left sidebar, view the translations at the bottom and vote with\nthe + and - icons for good and poor translations respectively.\n\nTranslations\n------------\n\nYou can also help with contributing translations directly. Follow the\nsteps above to enter the translation editor (instead of clicking\n\"Translate all\", you may also choose to translate strings from a\nspecific file by clicking them). Crowdin's on-screen tutorial should\nguide you through the process.\n\nTranslation guidelines\n======================\n\nIn general, follow the conventions for technical writing in your target\nlanguage. You may want to refer to similar, high quality sources (eg.\nPython's documentation in your language) for guidance. Note that code\nblocks, code literals, names and pseudonyms should be left unchanged.\n\nProofreading\n============\n\nFor certain languages with a significant number of speakers within the\nManim Community, an additional step of proofreading is used after\ncrowdsourcing to further ensure the quality of our translations.\nProofreaders are trusted community members who will look over and give\nthe final approval on translations. If you would like to be a\nproofreader, please email translations@manim.community with the answers\nto the following questions:\n\n1. What is your Crowdin username?\n2. What is your Discord username (optional)?\n3. What is your GitHub username (optional)?\n4. List the languages you speak, and your level of fluency with them.\n5. What language(s) are you applying to be a proofreader for?\n6. Do you have any previous experience with translations?\n7. If yes, give us more details.\n8. How will you ensure the quality of translations, should you become a\n   proofreader?\n\nPlease note that you don't need to have prior translation experience to\nbe a proofreader, just a commitment to maintaining a good quality of\ntranslations.\n\nErrors\n======\n\nSource errors\n-------------\n\nIf you spot an error with a source string, report it to us by opening an\n:issue:`issue <new/choose>` on\nGitHub. Refrain from translating the string until the issue is resolved.\n"
  },
  {
    "path": "docs/source/contributing/performance.rst",
    "content": "=====================\nImproving performance\n=====================\n\nOne of Manim's main flaws as an animation library is its slow performance.\nAs of time of writing (January 2022), the library is still very unoptimized.\nAs such, we highly encourage contributors to help out in optimizing the code.\n\nProfiling\n=========\n\nBefore the library can be optimized, we first need to identify the bottlenecks\nin performance via profiling. There are numerous Python profilers available for\nthis purpose; some examples include cProfile and Scalene.\n\nRunning an animation as a script\n--------------------------------\n\nMost instructions for profilers assume you can run the python file directly as a\nscript from the command line. While Manim animations are usually run from the\ncommand-line, we can run them as scripts by adding something like the following\nto the bottom of the file:\n\n.. code-block:: python\n\n    with tempconfig({\"quality\": \"medium_quality\", \"disable_caching\": True}):\n        scene = SceneName()\n        scene.render()\n\nWhere ``SceneName`` is the name of the scene you want to run. You can then run the\nfile directly, and can thus follow the instructions for most profilers.\n\nAn example: profiling with cProfile and SnakeViz\n-------------------------------------------------\n\nInstall SnakeViz:\n\n.. code-block:: bash\n\n    pip install snakeviz\n\ncProfile is included with in Python's standard library and does not need to be installed.\n\nSuppose we want to profile ``SquareToCircle``. Then we add and save the following code\nto ``square_to_circle.py``:\n\n.. code-block:: python\n\n    from manim import *\n\n\n    class SquareToCircle(Scene):\n        def construct(self):\n            s = Square()\n            c = Circle()\n            self.add(s)\n            self.play(Transform(s, c))\n\n\n    with tempconfig({\"quality\": \"medium_quality\", \"disable_caching\": True}):\n        scene = SquareToCircle()\n        scene.render()\n\nNow run the following in the terminal:\n\n.. code-block:: bash\n\n   python -m cProfile -o square_to_circle.txt square_to_circle.py\n\nThis will create a file called ``square_to_circle.txt``.\n\nNow, we can run SnakeViz on the profile file:\n\n.. code-block:: bash\n\n   snakeviz square_to_circle.txt\n\nA browser window or tab will open with a visualization of the profile, which should\nlook something like this:\n\n.. image:: /_static/snakeviz.png\n"
  },
  {
    "path": "docs/source/contributing/testing.rst",
    "content": "============\nAdding Tests\n============\nIf you are adding new features to manim, you should add appropriate tests for them. Tests prevent\nmanim from breaking at each change by checking that no other\nfeature has been broken and/or been unintentionally modified.\n\n.. warning::\n\n   The full tests suite requires Cairo 1.18 in order to run all tests.\n   However, Cairo 1.18 may not be available from your package manager,\n   like ``apt``, and it is very likely that you have an older version installed,\n   e.g., 1.16. If you run tests with a version prior to 1.18,\n   many tests will be skipped. Those tests are not skipped in the online CI.\n\n   If you want to run all tests locally, you need to install Cairo 1.18 or above.\n   You can do so by compiling Cairo from source:\n\n   1. download ``cairo-1.18.0.tar.xz`` from\n      `here <https://www.cairographics.org/releases/>`_.\n      and uncompress it;\n   2. open the INSTALL file and follow the instructions (you might need to install\n      ``meson`` and ``ninja``);\n   3. run the tests suite and verify that the Cairo version is correct.\n\nHow Manim tests\n---------------\n\nManim uses pytest as its testing framework.\nTo start the testing process, go to the root directory of the project and run pytest in your terminal.\nAny errors that occur during testing will be displayed in the terminal.\n\nSome useful pytest flags:\n\n- ``-x`` will make pytest stop at the first failure it encounters\n\n- ``-s`` will make pytest display all the print messages (including those during scene generation, like DEBUG messages)\n\n- ``--skip_slow`` will skip the (arbitrarily) slow tests\n\n- ``--show_diff`` will show a visual comparison in case a unit test is failing.\n\n\nHow it Works\n~~~~~~~~~~~~\n\nAt the moment there are three types of tests:\n\n#. Unit Tests:\n\n   Tests for most of the basic functionalities of manim. For example, there a test for\n   ``Mobject``, that checks if it can be added to a Scene, etc.\n\n#. Graphical unit tests:\n   Because ``manim`` is a graphics library, we test frames. To do so, we create test scenes that render a specific feature.\n   When pytest runs, it compares the result of the test to the control data, either at 6 fps or just the last frame. If it matches, the tests\n   pass. If the test and control data differ, the tests fail. You can use ``--show_diff`` flag with ``pytest`` to visually\n   see the differences. The ``extract_frames.py`` script lets you see all the frames of a test.\n\n#. Videos format tests:\n\n   As Manim is a video library, we have to test videos as well. Unfortunately,\n   we cannot directly test video content as rendered videos can\n   differ slightly depending on the system (for reasons related to\n   ffmpeg). Therefore, we only compare video configuration values, exported in\n   .json.\n\nArchitecture\n------------\n\nThe ``manim/tests`` directory looks like this:\n\n::\n\n    .\n    ├── conftest.py\n    ├── control_data\n    │   ├── graphical_units_data\n    │   │   ├── creation\n    │   │   │   ├── DrawBorderThenFillTest.npy\n    │   │   │   ├── FadeInFromDownTest.npy\n    │   │   │   ├── FadeInFromLargeTest.npy\n    │   │   │   ├── FadeInFromTest.npy\n    │   │   │   ├── FadeInTest.npy\n    │   │   │   ├── ...\n    │   │   ├── geometry\n    │   │   │   ├── AnnularSectorTest.npy\n    │   │   │   ├── AnnulusTest.npy\n    │   │   │   ├── ArcBetweenPointsTest.npy\n    │   │   │   ├── ArcTest.npy\n    │   │   │   ├── CircleTest.npy\n    │   │   │   ├── CoordinatesTest.npy\n    │   │   │   ├── ...\n    │   │   ├── graph\n    │   │   │   ├── ...\n    |   |   |   | ...\n    │   └── videos_data\n    │       ├── SquareToCircleWithDefaultValues.json\n    │       └── SquareToCircleWithlFlag.json\n    ├── helpers\n    │   ├── graphical_units.py\n    │   ├── __init__.py\n    │   └── video_utils.py\n    ├── __init__.py\n    ├── test_camera.py\n    ├── test_config.py\n    ├── test_copy.py\n    ├── test_vectorized_mobject.py\n    ├── test_graphical_units\n    │   ├── conftest.py\n    │   ├── __init__.py\n    │   ├── test_creation.py\n    │   ├── test_geometry.py\n    │   ├── test_graph.py\n    │   ├── test_indication.py\n    │   ├── test_movements.py\n    │   ├── test_threed.py\n    │   ├── test_transform.py\n    │   └── test_updaters.py\n    ├── test_logging\n    │   ├── basic_scenes.py\n    │   ├── expected.txt\n    │   ├── testloggingconfig.cfg\n    │   └── test_logging.py\n    ├── test_scene_rendering\n    │   ├── conftest.py\n    │   ├── __init__.py\n    │   ├── simple_scenes.py\n    │   ├── standard_config.cfg\n    │   └── test_cli_flags.py\n    └── utils\n        ├── commands.py\n        ├── __init__.py\n        ├── testing_utils.py\n        └── video_tester.py\n       ...\n\nThe Main Directories\n--------------------\n\n- ``control_data/``:\n\n  The directory containing control data. ``control_data/graphical_units_data/`` contains the expected and correct frame data for graphical tests, and\n  ``control_data/videos_data/`` contains the .json files used to check videos.\n\n- ``test_graphical_units/``:\n\n  Contains graphical tests.\n\n- ``test_scene_rendering/``:\n\n  For tests that need to render a scene in some way, such as tests for CLI\n  flags (end-to-end tests).\n\n- ``utils/``:\n\n  Useful internal functions used by pytest.\n\n  .. note:: fixtures are not contained here, they are in ``conftest.py``.\n\n- ``helpers/``:\n\n  Helper functions for developers to setup graphical/video tests.\n\nAdding a New Test\n-----------------\n\nUnit Tests\n~~~~~~~~~~\n\nPytest determines which functions are tests by searching for files whose\nnames begin with \"test\\_\", and then within those files for functions\nbeginning with \"test\" and classes beginning with \"Test\". These kinds of\ntests must be in ``tests/`` (e.g. ``tests/test_container.py``).\n\nGraphical Unit Test\n~~~~~~~~~~~~~~~~~~~\n\nThe test must be written in the correct file (i.e. the file that corresponds to the appropriate category the feature belongs to) and follow the structure\nof unit tests.\n\nFor example, to test the ``Circle`` VMobject which resides in\n``manim/mobject/geometry.py``, add the CircleTest to\n``test/test_geometry.py``.\n\nThe name of the module is indicated by the variable __module_test__, that **must** be declared in any graphical test file. The module name is used to store the graphical control data.\n\n.. important::\n    You will need to use the ``frames_comparison`` decorator to create a test. The test function **must** accept a\n    parameter named ``scene`` that will be used like ``self`` in a standard ``construct`` method.\n\nHere's an example in ``test_geometry.py``:\n\n.. code:: python\n\n  from manim import *\n  from manim.utils.testing.frames_comparison import frames_comparison\n\n  __module_test__ = \"geometry\"\n\n\n  @frames_comparison\n  def test_circle(scene):\n      circle = Circle()\n      scene.play(Animation(circle))\n\nThe decorator can be used with or without parentheses. **By default, the test only tests the last frame. To enable multi-frame testing, you have to set ``last_frame=False`` in the parameters.**\n\n.. code:: python\n\n  @frames_comparison(last_frame=False)\n  def test_circle(scene):\n      circle = Circle()\n      scene.play(Animation(circle))\n\nYou can also specify, when needed, which base scene you need (ThreeDScene, for example) :\n\n.. code:: python\n\n  @frames_comparison(last_frame=False, base_scene=ThreeDScene)\n  def test_circle(scene):\n      circle = Circle()\n      scene.play(Animation(circle))\n\nFeel free to check the documentation of ``@frames_comparison`` for more.\n\nNote that tests name must follow the syntax ``test_<thing_to_test>``, otherwise pytest will not recognize it as a test.\n\n.. warning::\n  If you run pytest now, you will get a ``FileNotFound`` error. This is because\n  you have not created control data for your test.\n\nTo create the control data for your test, you have to use the flag ``--set_test`` along with pytest.\nFor the example above, it would be\n\n.. code-block:: bash\n\n    pytest test_geometry.py::test_circle --set_test -s\n\n(``-s`` is here to see manim logs, so you can see what's going on).\n\nIf you want to see all the control data frames (e.g. to make sure your test is doing what you want), use the\n``extract_frames.py`` script. The first parameter is the path to a ``.npz`` file and the second parameter is the\ndirectory you want the frames created. The frames will be named ``frame0.png``, ``frame1.png``, etc.\n\n.. code-block:: bash\n\n    python scripts/extract_frames.py tests/test_graphical_units/control_data/plot/axes.npz output\n\n\nPlease make sure to add the control data to git as soon as it is produced with ``git add <your-control-data.npz>``.\n\n\nVideos tests\n~~~~~~~~~~~~\n\nTo test videos generated, we use the decorator\n``tests.utils.videos_tester.video_comparison``:\n\n.. code:: python\n\n    @video_comparison(\n        \"SquareToCircleWithlFlag.json\", \"videos/simple_scenes/480p15/SquareToCircle.mp4\"\n    )\n    def test_basic_scene_l_flag(tmp_path, manim_cfg_file, simple_scenes_path):\n        scene_name = \"SquareToCircle\"\n        command = [\n            \"python\",\n            \"-m\",\n            \"manim\",\n            simple_scenes_path,\n            scene_name,\n            \"-l\",\n            \"--media_dir\",\n            str(tmp_path),\n        ]\n        out, err, exit_code = capture(command)\n        assert exit_code == 0, err\n\n.. note:: ``assert exit*\\ code == 0, err`` is used in case of the command fails\n  to run. The decorator takes two arguments: json name and the path\n  to where the video should be generated, starting from the ``media/`` dir.\n\nNote the fixtures here:\n\n- tmp_path is a pytest fixture to get a tmp_path. Manim will output here, according to the flag ``--media_dir``.\n\n- ``manim_cfg_file`` fixture that return a path pointing to ``test_scene_rendering/standard_config.cfg``. It's just to shorten the code, in the case multiple tests need to use this cfg file.\n\n- ``simple_scenes_path`` same as above, except for ``test_scene_rendering/simple_scene.py``\n\nYou have to generate a ``.json`` file first to be able to test your video. To\ndo that, use ``helpers.save_control_data_from_video``.\n\nFor instance, a test that will check if the l flag works properly will first\nrequire rendering a video using the -l flag from a scene. Then we will test\n(in this case, SquareToCircle), that lives in\n``test_scene_rendering/simple_scene.py``. Change directories to ``tests/``,\ncreate a file (e.g. ``create\\_data.py``) that you will remove as soon as\nyou're done. Then run:\n\n.. code:: python\n\n    save_control_data_from_video(\"<path-to-video>\", \"SquareToCircleWithlFlag.json\")\n\nRunning this will save\n``control_data/videos_data/SquareToCircleWithlFlag.json``, which will\nlook like this:\n\n.. code:: json\n\n    {\n        \"name\": \"SquareToCircleWithlFlag\",\n        \"config\": {\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"1.000000\",\n            \"nb_frames\": \"15\"\n        }\n    }\n\nIf you have any questions, please don't hesitate to ask on `Discord\n<https://www.manim.community/discord/>`_, in your pull request, or in an issue.\n"
  },
  {
    "path": "docs/source/contributing.rst",
    "content": "############\nContributing\n############\n\n.. important:: Manim is currently undergoing a major refactor. In general,\n   contributions implementing new features will not be accepted in this period.\n   Other contributions unrelated to cleaning up the codebase may also take a longer\n   period of time to be reviewed. This guide may quickly become outdated quickly; we\n   highly recommend joining our `Discord server <https://www.manim.community/discord/>`__\n   to discuss any potential contributions and keep up to date with the latest developments.\n\nThank you for your interest in contributing to Manim! However you have decided to contribute\nor interact with the community, please always be civil and respect other\nmembers of the community. If you haven't read our :doc:`code of conduct<conduct>`,\ndo so here. Manim is Free and Open Source Software (FOSS) for mathematical\nanimations. As such, **we welcome everyone** who is interested in\nmathematics, pedagogy, computer animations, open-source,\nsoftware development, and beyond. Manim accepts many kinds of contributions,\nsome are detailed below:\n\n*  Code maintenance and development\n*  DevOps\n*  Documentation\n*  Developing educational content & narrative documentation\n*  Plugins to extend Manim functionality\n*  Testing (graphical, unit & video)\n*  Website design and development\n*  Translating documentation and docstrings\n\nTo get an overview of what our community is currently working on, check out\n`our development project board <https://github.com/orgs/ManimCommunity/projects/7/views/1>`__.\n\n.. note::\n   Please ensure that you are reading the latest version of this guide by ensuring that \"latest\" is selected in the version switcher.\n\n\n\nContributing can be confusing, so here are a few guides:\n\n.. toctree::\n   :maxdepth: 3\n\n   contributing/development\n   contributing/docs\n   contributing/testing\n   contributing/performance\n   contributing/internationalization\n"
  },
  {
    "path": "docs/source/examples.rst",
    "content": "###############\nExample Gallery\n###############\n\nThis gallery contains a collection of best practice code snippets\ntogether with their corresponding video/image output, illustrating\ndifferent functionalities all across the library.\nThese are all under the MIT license, so feel free to copy & paste them to your projects.\nEnjoy this taste of Manim!\n\n.. tip::\n\n   This gallery is not the only place in our documentation where you can see explicit\n   code and video examples: there are many more in our\n   :doc:`reference manual </reference>` -- see, for example, our documentation for\n   the modules :mod:`~.tex_mobject`, :mod:`~.geometry`, :mod:`~.moving_camera_scene`,\n   and many more.\n\n   Check out our `interactive Jupyter environment <https://mybinder.org/v2/gh/ManimCommunity/jupyter_examples/HEAD?filepath=basic_example_scenes.ipynb>`_\n   which allows running the examples online, without requiring a local\n   installation.\n\n   Also, visit our `Twitter <https://twitter.com/manim_community/>`_ for more\n   *manimations*!\n\n\n\nBasic Concepts\n==============\n\n.. manim:: ManimCELogo\n    :save_last_frame:\n    :ref_classes: MathTex Circle Square Triangle\n\n    class ManimCELogo(Scene):\n        def construct(self):\n            self.camera.background_color = \"#ece6e2\"\n            logo_green = \"#87c2a5\"\n            logo_blue = \"#525893\"\n            logo_red = \"#e07a5f\"\n            logo_black = \"#343434\"\n            ds_m = MathTex(r\"\\mathbb{M}\", fill_color=logo_black).scale(7)\n            ds_m.shift(2.25 * LEFT + 1.5 * UP)\n            circle = Circle(color=logo_green, fill_opacity=1).shift(LEFT)\n            square = Square(color=logo_blue, fill_opacity=1).shift(UP)\n            triangle = Triangle(color=logo_red, fill_opacity=1).shift(RIGHT)\n            logo = VGroup(triangle, square, circle, ds_m)  # order matters\n            logo.move_to(ORIGIN)\n            self.add(logo)\n\n\n\n.. manim:: BraceAnnotation\n    :save_last_frame:\n    :ref_classes: Brace\n    :ref_methods: Brace.get_text Brace.get_tex\n\n    class BraceAnnotation(Scene):\n        def construct(self):\n            dot = Dot([-2, -1, 0])\n            dot2 = Dot([2, 1, 0])\n            line = Line(dot.get_center(), dot2.get_center()).set_color(ORANGE)\n            b1 = Brace(line)\n            b1text = b1.get_text(\"Horizontal distance\")\n            b2 = Brace(line, direction=line.copy().rotate(PI / 2).get_unit_vector())\n            b2text = b2.get_tex(\"x-x_1\")\n            self.add(line, dot, dot2, b1, b2, b1text, b2text)\n\n.. manim:: VectorArrow\n    :save_last_frame:\n    :ref_classes: Dot Arrow NumberPlane Text\n\n    class VectorArrow(Scene):\n        def construct(self):\n            dot = Dot(ORIGIN)\n            arrow = Arrow(ORIGIN, [2, 2, 0], buff=0)\n            numberplane = NumberPlane()\n            origin_text = Text('(0, 0)').next_to(dot, DOWN)\n            tip_text = Text('(2, 2)').next_to(arrow.get_end(), RIGHT)\n            self.add(numberplane, dot, arrow, origin_text, tip_text)\n\n.. manim:: GradientImageFromArray\n    :save_last_frame:\n    :ref_classes: ImageMobject\n\n    class GradientImageFromArray(Scene):\n        def construct(self):\n            n = 256\n            imageArray = np.uint8(\n                [[i * 256 / n for i in range(0, n)] for _ in range(0, n)]\n            )\n            image = ImageMobject(imageArray).scale(2)\n            image.background_rectangle = SurroundingRectangle(image, color=GREEN)\n            self.add(image, image.background_rectangle)\n\n.. manim:: BooleanOperations\n    :ref_classes: Union Intersection Exclusion Difference\n\n    class BooleanOperations(Scene):\n        def construct(self):\n            ellipse1 = Ellipse(\n                width=4.0, height=5.0, fill_opacity=0.5, color=BLUE, stroke_width=10\n            ).move_to(LEFT)\n            ellipse2 = ellipse1.copy().set_color(color=RED).move_to(RIGHT)\n            bool_ops_text = MarkupText(\"<u>Boolean Operation</u>\").next_to(ellipse1, UP * 3)\n            ellipse_group = Group(bool_ops_text, ellipse1, ellipse2).move_to(LEFT * 3)\n            self.play(FadeIn(ellipse_group))\n\n            i = Intersection(ellipse1, ellipse2, color=GREEN, fill_opacity=0.5)\n            self.play(i.animate.scale(0.25).move_to(RIGHT * 5 + UP * 2.5))\n            intersection_text = Text(\"Intersection\", font_size=23).next_to(i, UP)\n            self.play(FadeIn(intersection_text))\n\n            u = Union(ellipse1, ellipse2, color=ORANGE, fill_opacity=0.5)\n            union_text = Text(\"Union\", font_size=23)\n            self.play(u.animate.scale(0.3).next_to(i, DOWN, buff=union_text.height * 3))\n            union_text.next_to(u, UP)\n            self.play(FadeIn(union_text))\n\n            e = Exclusion(ellipse1, ellipse2, color=YELLOW, fill_opacity=0.5)\n            exclusion_text = Text(\"Exclusion\", font_size=23)\n            self.play(e.animate.scale(0.3).next_to(u, DOWN, buff=exclusion_text.height * 3.5))\n            exclusion_text.next_to(e, UP)\n            self.play(FadeIn(exclusion_text))\n\n            d = Difference(ellipse1, ellipse2, color=PINK, fill_opacity=0.5)\n            difference_text = Text(\"Difference\", font_size=23)\n            self.play(d.animate.scale(0.3).next_to(u, LEFT, buff=difference_text.height * 3.5))\n            difference_text.next_to(d, UP)\n            self.play(FadeIn(difference_text))\n\n\nAnimations\n==========\n\n.. manim:: PointMovingOnShapes\n    :ref_classes: Circle Dot Line GrowFromCenter Transform MoveAlongPath Rotating\n\n    class PointMovingOnShapes(Scene):\n        def construct(self):\n            circle = Circle(radius=1, color=BLUE)\n            dot = Dot()\n            dot2 = dot.copy().shift(RIGHT)\n            self.add(dot)\n\n            line = Line([3, 0, 0], [5, 0, 0])\n            self.add(line)\n\n            self.play(GrowFromCenter(circle))\n            self.play(Transform(dot, dot2))\n            self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=linear)\n            self.play(Rotating(dot, about_point=[2, 0, 0]), run_time=1.5)\n            self.wait()\n\n.. manim:: MovingAround\n    :ref_methods: Mobject.shift VMobject.set_fill Mobject.scale Mobject.rotate\n\n    class MovingAround(Scene):\n        def construct(self):\n            square = Square(color=BLUE, fill_opacity=1)\n\n            self.play(square.animate.shift(LEFT))\n            self.play(square.animate.set_fill(ORANGE))\n            self.play(square.animate.scale(0.3))\n            self.play(square.animate.rotate(0.4))\n\n.. manim:: MovingAngle\n    :ref_classes: Angle\n    :ref_methods: Mobject.rotate\n\n    class MovingAngle(Scene):\n        def construct(self):\n            rotation_center = LEFT\n\n            theta_tracker = ValueTracker(110)\n            line1 = Line(LEFT, RIGHT)\n            line_moving = Line(LEFT, RIGHT)\n            line_ref = line_moving.copy()\n            line_moving.rotate(\n                theta_tracker.get_value() * DEGREES, about_point=rotation_center\n            )\n            a = Angle(line1, line_moving, radius=0.5, other_angle=False)\n            tex = MathTex(r\"\\theta\").move_to(\n                Angle(\n                    line1, line_moving, radius=0.5 + 3 * SMALL_BUFF, other_angle=False\n                ).point_from_proportion(0.5)\n            )\n\n            self.add(line1, line_moving, a, tex)\n            self.wait()\n\n            line_moving.add_updater(\n                lambda x: x.become(line_ref.copy()).rotate(\n                    theta_tracker.get_value() * DEGREES, about_point=rotation_center\n                )\n            )\n\n            a.add_updater(\n                lambda x: x.become(Angle(line1, line_moving, radius=0.5, other_angle=False))\n            )\n            tex.add_updater(\n                lambda x: x.move_to(\n                    Angle(\n                        line1, line_moving, radius=0.5 + 3 * SMALL_BUFF, other_angle=False\n                    ).point_from_proportion(0.5)\n                )\n            )\n\n            self.play(theta_tracker.animate.set_value(40))\n            self.play(theta_tracker.animate.increment_value(140))\n            self.play(tex.animate.set_color(RED), run_time=0.5)\n            self.play(theta_tracker.animate.set_value(350))\n\n.. tip::\n\n   You can use multiple ValueTrackers simultaneously.\n\n.. manim:: MovingDots\n\n    class MovingDots(Scene):\n        def construct(self):\n            d1,d2=Dot(color=BLUE),Dot(color=GREEN)\n            dg=VGroup(d1,d2).arrange(RIGHT,buff=1)\n            l1=Line(d1.get_center(),d2.get_center()).set_color(RED)\n            x=ValueTracker(0)\n            y=ValueTracker(0)\n            d1.add_updater(lambda z: z.set_x(x.get_value()))\n            d2.add_updater(lambda z: z.set_y(y.get_value()))\n            l1.add_updater(lambda z: z.become(Line(d1.get_center(),d2.get_center())))\n            self.add(d1,d2,l1)\n            self.play(x.animate.set_value(5))\n            self.play(y.animate.set_value(4))\n            self.wait()\n\n.. manim:: MovingGroupToDestination\n\n    class MovingGroupToDestination(Scene):\n        def construct(self):\n            group = VGroup(Dot(LEFT), Dot(ORIGIN), Dot(RIGHT, color=RED), Dot(2 * RIGHT)).scale(1.4)\n            dest = Dot([4, 3, 0], color=YELLOW)\n            self.add(group, dest)\n            self.play(group.animate.shift(dest.get_center() - group[2].get_center()))\n            self.wait(0.5)\n\n.. manim:: MovingFrameBox\n    :ref_modules: manim.mobject.svg.tex_mobject\n    :ref_classes: MathTex SurroundingRectangle\n\n    class MovingFrameBox(Scene):\n        def construct(self):\n            text=MathTex(\n                \"\\\\frac{d}{dx}f(x)g(x)=\",\"f(x)\\\\frac{d}{dx}g(x)\",\"+\",\n                \"g(x)\\\\frac{d}{dx}f(x)\"\n            )\n            self.play(Write(text))\n            framebox1 = SurroundingRectangle(text[1], buff = .1)\n            framebox2 = SurroundingRectangle(text[3], buff = .1)\n            self.play(\n                Create(framebox1),\n            )\n            self.wait()\n            self.play(\n                ReplacementTransform(framebox1,framebox2),\n            )\n            self.wait()\n\n.. manim:: RotationUpdater\n    :ref_methods: Mobject.add_updater Mobject.remove_updater\n\n    class RotationUpdater(Scene):\n        def construct(self):\n            def updater_forth(mobj, dt):\n                mobj.rotate_about_origin(dt)\n            def updater_back(mobj, dt):\n                mobj.rotate_about_origin(-dt)\n            line_reference = Line(ORIGIN, LEFT).set_color(WHITE)\n            line_moving = Line(ORIGIN, LEFT).set_color(YELLOW)\n            line_moving.add_updater(updater_forth)\n            self.add(line_reference, line_moving)\n            self.wait(2)\n            line_moving.remove_updater(updater_forth)\n            line_moving.add_updater(updater_back)\n            self.wait(2)\n            line_moving.remove_updater(updater_back)\n            self.wait(0.5)\n\n.. manim:: PointWithTrace\n    :ref_classes: Rotating\n    :ref_methods: VMobject.set_points_as_corners Mobject.add_updater\n\n    class PointWithTrace(Scene):\n        def construct(self):\n            path = VMobject()\n            dot = Dot()\n            path.set_points_as_corners([dot.get_center(), dot.get_center()])\n            def update_path(path):\n                previous_path = path.copy()\n                previous_path.add_points_as_corners([dot.get_center()])\n                path.become(previous_path)\n            path.add_updater(update_path)\n            self.add(path, dot)\n            self.play(Rotating(dot, angle=PI, about_point=RIGHT, run_time=2))\n            self.wait()\n            self.play(dot.animate.shift(UP))\n            self.play(dot.animate.shift(LEFT))\n            self.wait()\n\n\nPlotting with Manim\n===================\n\n.. manim:: SinAndCosFunctionPlot\n    :save_last_frame:\n    :ref_modules: manim.mobject.coordinate_systems\n    :ref_classes: MathTex\n    :ref_methods: Axes.plot Axes.get_vertical_line_to_graph Axes.input_to_graph_point Axes.get_axis_labels\n\n    class SinAndCosFunctionPlot(Scene):\n        def construct(self):\n            axes = Axes(\n                x_range=[-10, 10.3, 1],\n                y_range=[-1.5, 1.5, 1],\n                x_length=10,\n                axis_config={\"color\": GREEN},\n                x_axis_config={\n                    \"numbers_to_include\": np.arange(-10, 10.01, 2),\n                    \"numbers_with_elongated_ticks\": np.arange(-10, 10.01, 2),\n                },\n                tips=False,\n            )\n            axes_labels = axes.get_axis_labels()\n            sin_graph = axes.plot(lambda x: np.sin(x), color=BLUE)\n            cos_graph = axes.plot(lambda x: np.cos(x), color=RED)\n\n            sin_label = axes.get_graph_label(\n                sin_graph, \"\\\\sin(x)\", x_val=-10, direction=UP / 2\n            )\n            cos_label = axes.get_graph_label(cos_graph, label=\"\\\\cos(x)\")\n\n            vert_line = axes.get_vertical_line(\n                axes.i2gp(TAU, cos_graph), color=YELLOW, line_func=Line\n            )\n            line_label = axes.get_graph_label(\n                cos_graph, r\"x=2\\pi\", x_val=TAU, direction=UR, color=WHITE\n            )\n\n            plot = VGroup(axes, sin_graph, cos_graph, vert_line)\n            labels = VGroup(axes_labels, sin_label, cos_label, line_label)\n            self.add(plot, labels)\n\n\n\n.. manim:: ArgMinExample\n\n   class ArgMinExample(Scene):\n       def construct(self):\n           ax = Axes(\n               x_range=[0, 10], y_range=[0, 100, 10], axis_config={\"include_tip\": False}\n           )\n           labels = ax.get_axis_labels(x_label=\"x\", y_label=\"f(x)\")\n\n           t = ValueTracker(0)\n\n           def func(x):\n               return 2 * (x - 5) ** 2\n           graph = ax.plot(func, color=MAROON)\n\n           initial_point = [ax.coords_to_point(t.get_value(), func(t.get_value()))]\n           dot = Dot(point=initial_point)\n\n           dot.add_updater(lambda x: x.move_to(ax.c2p(t.get_value(), func(t.get_value()))))\n           x_space = np.linspace(*ax.x_range[:2],200)\n           minimum_index = func(x_space).argmin()\n\n           self.add(ax, labels, graph, dot)\n           self.play(t.animate.set_value(x_space[minimum_index]))\n           self.wait()\n\n.. manim:: GraphAreaPlot\n    :save_last_frame:\n    :ref_modules: manim.mobject.coordinate_systems\n    :ref_methods: Axes.plot Axes.get_vertical_line_to_graph Axes.get_area Axes.get_axis_labels\n\n    class GraphAreaPlot(Scene):\n        def construct(self):\n            ax = Axes(\n                x_range=[0, 5],\n                y_range=[0, 6],\n                x_axis_config={\"numbers_to_include\": [2, 3]},\n                tips=False,\n            )\n\n            labels = ax.get_axis_labels()\n\n            curve_1 = ax.plot(lambda x: 4 * x - x ** 2, x_range=[0, 4], color=BLUE_C)\n            curve_2 = ax.plot(\n                lambda x: 0.8 * x ** 2 - 3 * x + 4,\n                x_range=[0, 4],\n                color=GREEN_B,\n            )\n\n            line_1 = ax.get_vertical_line(ax.input_to_graph_point(2, curve_1), color=YELLOW)\n            line_2 = ax.get_vertical_line(ax.i2gp(3, curve_1), color=YELLOW)\n\n            riemann_area = ax.get_riemann_rectangles(curve_1, x_range=[0.3, 0.6], dx=0.03, color=BLUE, fill_opacity=0.5)\n            area = ax.get_area(curve_2, [2, 3], bounded_graph=curve_1, color=GREY, opacity=0.5)\n\n            self.add(ax, labels, curve_1, curve_2, line_1, line_2, riemann_area, area)\n\n.. manim:: PolygonOnAxes\n    :ref_classes: Axes Polygon\n\n    class PolygonOnAxes(Scene):\n        def get_rectangle_corners(self, bottom_left, top_right):\n            return [\n                (top_right[0], top_right[1]),\n                (bottom_left[0], top_right[1]),\n                (bottom_left[0], bottom_left[1]),\n                (top_right[0], bottom_left[1]),\n            ]\n\n        def construct(self):\n            ax = Axes(\n                x_range=[0, 10],\n                y_range=[0, 10],\n                x_length=6,\n                y_length=6,\n                axis_config={\"include_tip\": False},\n            )\n\n            t = ValueTracker(5)\n            k = 25\n\n            graph = ax.plot(\n                lambda x: k / x,\n                color=YELLOW_D,\n                x_range=[k / 10, 10.0, 0.01],\n                use_smoothing=False,\n            )\n\n            def get_rectangle():\n                polygon = Polygon(\n                    *[\n                        ax.c2p(*i)\n                        for i in self.get_rectangle_corners(\n                            (0, 0), (t.get_value(), k / t.get_value())\n                        )\n                    ]\n                )\n                polygon.stroke_width = 1\n                polygon.set_fill(BLUE, opacity=0.5)\n                polygon.set_stroke(YELLOW_B)\n                return polygon\n\n            polygon = always_redraw(get_rectangle)\n\n            dot = Dot()\n            dot.add_updater(lambda x: x.move_to(ax.c2p(t.get_value(), k / t.get_value())))\n            dot.set_z_index(10)\n\n            self.add(ax, graph, dot)\n            self.play(Create(polygon))\n            self.play(t.animate.set_value(10))\n            self.play(t.animate.set_value(k / 10))\n            self.play(t.animate.set_value(5))\n\n\n.. manim:: HeatDiagramPlot\n    :save_last_frame:\n    :ref_modules: manim.mobject.coordinate_systems\n    :ref_methods: Axes.plot_line_graph Axes.get_axis_labels\n\n    class HeatDiagramPlot(Scene):\n        def construct(self):\n            ax = Axes(\n                x_range=[0, 40, 5],\n                y_range=[-8, 32, 5],\n                x_length=9,\n                y_length=6,\n                x_axis_config={\"numbers_to_include\": np.arange(0, 40, 5)},\n                y_axis_config={\"numbers_to_include\": np.arange(-5, 34, 5)},\n                tips=False,\n            )\n            labels = ax.get_axis_labels(\n                x_label=Tex(r\"$\\Delta Q$\"), y_label=Tex(r\"T[$^\\circ C$]\")\n            )\n\n            x_vals = [0, 8, 38, 39]\n            y_vals = [20, 0, 0, -5]\n            graph = ax.plot_line_graph(x_values=x_vals, y_values=y_vals)\n\n            self.add(ax, labels, graph)\n\n\nSpecial Camera Settings\n=======================\n\n.. manim:: FollowingGraphCamera\n    :ref_modules: manim.scene.moving_camera_scene\n    :ref_classes: MovingCameraScene MoveAlongPath Restore\n    :ref_methods: Axes.plot Mobject.add_updater\n\n\n    class FollowingGraphCamera(MovingCameraScene):\n        def construct(self):\n            self.camera.frame.save_state()\n\n            # create the axes and the curve\n            ax = Axes(x_range=[-1, 10], y_range=[-1, 10])\n            graph = ax.plot(lambda x: np.sin(x), color=BLUE, x_range=[0, 3 * PI])\n\n            # create dots based on the graph\n            moving_dot = Dot(ax.i2gp(graph.t_min, graph), color=ORANGE)\n            dot_1 = Dot(ax.i2gp(graph.t_min, graph))\n            dot_2 = Dot(ax.i2gp(graph.t_max, graph))\n\n            self.add(ax, graph, dot_1, dot_2, moving_dot)\n            self.play(self.camera.frame.animate.scale(0.5).move_to(moving_dot))\n\n            def update_curve(mob):\n                mob.move_to(moving_dot.get_center())\n\n            self.camera.frame.add_updater(update_curve)\n            self.play(MoveAlongPath(moving_dot, graph, rate_func=linear))\n            self.camera.frame.remove_updater(update_curve)\n\n            self.play(Restore(self.camera.frame))\n\n.. manim:: MovingZoomedSceneAround\n    :ref_modules: manim.scene.zoomed_scene\n    :ref_classes: ZoomedScene BackgroundRectangle UpdateFromFunc\n    :ref_methods: Mobject.add_updater ZoomedScene.get_zoomed_display_pop_out_animation\n\n    class MovingZoomedSceneAround(ZoomedScene):\n    # contributed by TheoremofBeethoven, www.youtube.com/c/TheoremofBeethoven\n        def __init__(self, **kwargs):\n            ZoomedScene.__init__(\n                self,\n                zoom_factor=0.3,\n                zoomed_display_height=1,\n                zoomed_display_width=6,\n                image_frame_stroke_width=20,\n                zoomed_camera_config={\n                    \"default_frame_stroke_width\": 3,\n                    },\n                **kwargs\n            )\n\n        def construct(self):\n            dot = Dot().shift(UL * 2)\n            image = ImageMobject(np.uint8([[0, 100, 30, 200],\n                                           [255, 0, 5, 33]]))\n            image.height = 7\n            frame_text = Text(\"Frame\", color=PURPLE, font_size=67)\n            zoomed_camera_text = Text(\"Zoomed camera\", color=RED, font_size=67)\n\n            self.add(image, dot)\n            zoomed_camera = self.zoomed_camera\n            zoomed_display = self.zoomed_display\n            frame = zoomed_camera.frame\n            zoomed_display_frame = zoomed_display.display_frame\n\n            frame.move_to(dot)\n            frame.set_color(PURPLE)\n            zoomed_display_frame.set_color(RED)\n            zoomed_display.shift(DOWN)\n\n            zd_rect = BackgroundRectangle(zoomed_display, fill_opacity=0, buff=MED_SMALL_BUFF)\n            self.add_foreground_mobject(zd_rect)\n\n            unfold_camera = UpdateFromFunc(zd_rect, lambda rect: rect.replace(zoomed_display))\n\n            frame_text.next_to(frame, DOWN)\n\n            self.play(Create(frame), FadeIn(frame_text, shift=UP))\n            self.activate_zooming()\n\n            self.play(self.get_zoomed_display_pop_out_animation(), unfold_camera)\n            zoomed_camera_text.next_to(zoomed_display_frame, DOWN)\n            self.play(FadeIn(zoomed_camera_text, shift=UP))\n            # Scale in        x   y  z\n            scale_factor = [0.5, 1.5, 0]\n            self.play(\n                frame.animate.scale(scale_factor),\n                zoomed_display.animate.scale(scale_factor),\n                FadeOut(zoomed_camera_text),\n                FadeOut(frame_text)\n            )\n            self.wait()\n            self.play(ScaleInPlace(zoomed_display, 2))\n            self.wait()\n            self.play(frame.animate.shift(2.5 * DOWN))\n            self.wait()\n            self.play(self.get_zoomed_display_pop_out_animation(), unfold_camera, rate_func=lambda t: smooth(1 - t))\n            self.play(Uncreate(zoomed_display_frame), FadeOut(frame))\n            self.wait()\n\n.. manim:: FixedInFrameMObjectTest\n    :save_last_frame:\n    :ref_classes: ThreeDScene\n    :ref_methods: ThreeDScene.set_camera_orientation ThreeDScene.add_fixed_in_frame_mobjects\n\n    class FixedInFrameMObjectTest(ThreeDScene):\n        def construct(self):\n            axes = ThreeDAxes()\n            self.set_camera_orientation(phi=75 * DEGREES, theta=-45 * DEGREES)\n            text3d = Text(\"This is a 3D text\")\n            self.add_fixed_in_frame_mobjects(text3d)\n            text3d.to_corner(UL)\n            self.add(axes)\n            self.wait()\n\n.. manim:: ThreeDLightSourcePosition\n    :save_last_frame:\n    :ref_classes: ThreeDScene ThreeDAxes Surface\n    :ref_methods: ThreeDScene.set_camera_orientation\n\n    class ThreeDLightSourcePosition(ThreeDScene):\n        def construct(self):\n            axes = ThreeDAxes()\n            sphere = Surface(\n                lambda u, v: np.array([\n                    1.5 * np.cos(u) * np.cos(v),\n                    1.5 * np.cos(u) * np.sin(v),\n                    1.5 * np.sin(u)\n                ]), v_range=[0, TAU], u_range=[-PI / 2, PI / 2],\n                checkerboard_colors=[RED_D, RED_E], resolution=(15, 32)\n            )\n            self.renderer.camera.light_source.move_to(3*IN) # changes the source of the light\n            self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n            self.add(axes, sphere)\n\n\n.. manim:: ThreeDCameraRotation\n    :ref_classes: ThreeDScene ThreeDAxes\n    :ref_methods: ThreeDScene.begin_ambient_camera_rotation ThreeDScene.stop_ambient_camera_rotation\n\n    class ThreeDCameraRotation(ThreeDScene):\n        def construct(self):\n            axes = ThreeDAxes()\n            circle=Circle()\n            self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n            self.add(circle,axes)\n            self.begin_ambient_camera_rotation(rate=0.1)\n            self.wait()\n            self.stop_ambient_camera_rotation()\n            self.move_camera(phi=75 * DEGREES, theta=30 * DEGREES)\n            self.wait()\n\n.. manim:: ThreeDCameraIllusionRotation\n    :ref_classes: ThreeDScene ThreeDAxes\n    :ref_methods: ThreeDScene.begin_3dillusion_camera_rotation ThreeDScene.stop_3dillusion_camera_rotation\n\n    class ThreeDCameraIllusionRotation(ThreeDScene):\n        def construct(self):\n            axes = ThreeDAxes()\n            circle=Circle()\n            self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n            self.add(circle,axes)\n            self.begin_3dillusion_camera_rotation(rate=2)\n            self.wait(PI/2)\n            self.stop_3dillusion_camera_rotation()\n\n.. manim:: ThreeDSurfacePlot\n   :save_last_frame:\n   :ref_classes: ThreeDScene Surface\n\n   class ThreeDSurfacePlot(ThreeDScene):\n       def construct(self):\n           resolution_fa = 24\n           self.set_camera_orientation(phi=75 * DEGREES, theta=-30 * DEGREES)\n\n           def param_gauss(u, v):\n               x = u\n               y = v\n               sigma, mu = 0.4, [0.0, 0.0]\n               d = np.linalg.norm(np.array([x - mu[0], y - mu[1]]))\n               z = np.exp(-(d ** 2 / (2.0 * sigma ** 2)))\n               return np.array([x, y, z])\n\n           gauss_plane = Surface(\n               param_gauss,\n               resolution=(resolution_fa, resolution_fa),\n               v_range=[-2, +2],\n               u_range=[-2, +2]\n           )\n\n           gauss_plane.scale(2, about_point=ORIGIN)\n           gauss_plane.set_style(fill_opacity=1,stroke_color=GREEN)\n           gauss_plane.set_fill_by_checkerboard(ORANGE, BLUE, opacity=0.5)\n           axes = ThreeDAxes()\n           self.add(axes,gauss_plane)\n\n\n\n\nAdvanced Projects\n=================\n\n.. manim:: OpeningManim\n    :ref_classes: Tex MathTex Write FadeIn LaggedStart NumberPlane Create\n    :ref_methods: NumberPlane.prepare_for_nonlinear_transform\n\n    class OpeningManim(Scene):\n        def construct(self):\n            title = Tex(r\"This is some \\LaTeX\")\n            basel = MathTex(r\"\\sum_{n=1}^\\infty \\frac{1}{n^2} = \\frac{\\pi^2}{6}\")\n            VGroup(title, basel).arrange(DOWN)\n            self.play(\n                Write(title),\n                FadeIn(basel, shift=DOWN),\n            )\n            self.wait()\n\n            transform_title = Tex(\"That was a transform\")\n            transform_title.to_corner(UP + LEFT)\n            self.play(\n                Transform(title, transform_title),\n                LaggedStart(*[FadeOut(obj, shift=DOWN) for obj in basel]),\n            )\n            self.wait()\n\n            grid = NumberPlane()\n            grid_title = Tex(\"This is a grid\", font_size=72)\n            grid_title.move_to(transform_title)\n\n            self.add(grid, grid_title)  # Make sure title is on top of grid\n            self.play(\n                FadeOut(title),\n                FadeIn(grid_title, shift=UP),\n                Create(grid, run_time=3, lag_ratio=0.1),\n            )\n            self.wait()\n\n            grid_transform_title = Tex(\n                r\"That was a non-linear function \\\\ applied to the grid\"\n            )\n            grid_transform_title.move_to(grid_title, UL)\n            grid.prepare_for_nonlinear_transform()\n            self.play(\n                grid.animate.apply_function(\n                    lambda p: p\n                              + np.array(\n                        [\n                            np.sin(p[1]),\n                            np.sin(p[0]),\n                            0,\n                        ]\n                    )\n                ),\n                run_time=3,\n            )\n            self.wait()\n            self.play(Transform(grid_title, grid_transform_title))\n            self.wait()\n\n.. manim:: SineCurveUnitCircle\n    :ref_classes: MathTex Circle Dot Line VGroup\n    :ref_methods: Mobject.add_updater Mobject.remove_updater\n    :ref_functions: always_redraw\n\n    class SineCurveUnitCircle(Scene):\n        # contributed by heejin_park, https://infograph.tistory.com/230\n        def construct(self):\n            self.show_axis()\n            self.show_circle()\n            self.move_dot_and_draw_curve()\n            self.wait()\n\n        def show_axis(self):\n            x_start = np.array([-6,0,0])\n            x_end = np.array([6,0,0])\n\n            y_start = np.array([-4,-2,0])\n            y_end = np.array([-4,2,0])\n\n            x_axis = Line(x_start, x_end)\n            y_axis = Line(y_start, y_end)\n\n            self.add(x_axis, y_axis)\n            self.add_x_labels()\n\n            self.origin_point = np.array([-4,0,0])\n            self.curve_start = np.array([-3,0,0])\n\n        def add_x_labels(self):\n            x_labels = [\n                MathTex(r\"\\pi\"), MathTex(r\"2 \\pi\"),\n                MathTex(r\"3 \\pi\"), MathTex(r\"4 \\pi\"),\n            ]\n\n            for i in range(len(x_labels)):\n                x_labels[i].next_to(np.array([-1 + 2*i, 0, 0]), DOWN)\n                self.add(x_labels[i])\n\n        def show_circle(self):\n            circle = Circle(radius=1)\n            circle.move_to(self.origin_point)\n            self.add(circle)\n            self.circle = circle\n\n        def move_dot_and_draw_curve(self):\n            orbit = self.circle\n            origin_point = self.origin_point\n\n            dot = Dot(radius=0.08, color=YELLOW)\n            dot.move_to(orbit.point_from_proportion(0))\n            self.t_offset = 0\n            rate = 0.25\n\n            def go_around_circle(mob, dt):\n                self.t_offset += (dt * rate)\n                # print(self.t_offset)\n                mob.move_to(orbit.point_from_proportion(self.t_offset % 1))\n\n            def get_line_to_circle():\n                return Line(origin_point, dot.get_center(), color=BLUE)\n\n            def get_line_to_curve():\n                x = self.curve_start[0] + self.t_offset * 4\n                y = dot.get_center()[1]\n                return Line(dot.get_center(), np.array([x,y,0]), color=YELLOW_A, stroke_width=2 )\n\n\n            self.curve = VGroup()\n            self.curve.add(Line(self.curve_start,self.curve_start))\n            def get_curve():\n                last_line = self.curve[-1]\n                x = self.curve_start[0] + self.t_offset * 4\n                y = dot.get_center()[1]\n                new_line = Line(last_line.get_end(),np.array([x,y,0]), color=YELLOW_D)\n                self.curve.add(new_line)\n\n                return self.curve\n\n            dot.add_updater(go_around_circle)\n\n            origin_to_circle_line = always_redraw(get_line_to_circle)\n            dot_to_curve_line = always_redraw(get_line_to_curve)\n            sine_curve_line = always_redraw(get_curve)\n\n            self.add(dot)\n            self.add(orbit, origin_to_circle_line, dot_to_curve_line, sine_curve_line)\n            self.wait(8.5)\n\n            dot.remove_updater(go_around_circle)\n"
  },
  {
    "path": "docs/source/faq/general.md",
    "content": "# FAQ: General Usage\n\n## Why does Manim say that \"there are no scenes inside that module\"?\n\nThere are two main reasons why this error appears: if you have edited\nthe file containing your `Scene` class and forgot to save it, or if you\nhave accidentally passed the name of a wrong file to `manim`, this is\na likely outcome. Check that you have spelled everything correctly.\n\nOtherwise, you are likely mixing up Manim versions. See {ref}`this FAQ answer <different-versions>`\nfor an explanation regarding why there are different versions. Under the\nassumption that you are trying to use the `manim` executable from the terminal to run\na scene that has been written for the community version (i.e., there is\n`from manim import *`, or more specifically `from manim import Scene`),\nthen this error indicates that the `manim` executable has been overwritten\nby the one provided by `manimgl` (unfortunately, both `manim` and `manimgl`\nprovide a `manim` executable).\n\nYou can check whether this is the case by running `manim --version`, the output of\nthe community maintained version starts with `Manim Community v...`. If this is not\nthe case, you are running `manimgl`.\n\nYou can resolve this by either of the following steps:\n- Un- and reinstalling `manim`,\n- using the `manimce` executable in place of the `manim` one,\n- or replacing the call to the executable with a direct call to the\n  Python module via `python -m manim`.\n\n---\n\n## No matter what code I put in my file, Manim only renders a black frame! Why?\n\nIf you are using the usual pattern to write a `Scene`, i.e.,\n```python\nclass MyAwesomeScene(Scene):\n    def construct(self):\n        ...\n        # your animation code\n```\nthen double check whether you have spelled `construct` correctly.\nIf the method containing your code is not called `construct` (or\nif you are not calling a different, custom method from `construct`),\nManim will not call your method and simply output a black frame.\n\n---\n\n## What are the default measurements for Manim's scene?\n\nThe scene measures 8 units in height and has a default ratio of 16:9,\nwhich means that it measures {math}`8 \\cdot 16 / 9 = 14 + 2/9` units in width.\nThe origin is in the center of the scene, which means that, for example, the\nupper left corner of the scene has coordinates `[-7-1/9, 4, 0]`.\n\n---\n\n## How do I find out which keyword arguments I can pass when creating a `Mobject`?\n\nLet us consider a specific example, like the {class}`.Circle` class. When looking\nat its documentation page, only two specific keyword arguments are listed\n(`radius`, and `color`). Besides these concrete arguments, there is also a\ncatchall `**kwargs` argument which captures all other arguments that are passed\nto `Circle`, and passes them on to the base class of {class}`.Circle`, {class}`.Arc`.\n\nThe same holds for {class}`.Arc`: some arguments are explicitly documented, and\nthere is again a catchall `**kwargs` argument that passes unprocessed arguments\nto the next base class -- and so on.\n\nThe most important keyword arguments relevant to styling your mobjects are the\nones that are documented for the base classes {class}`.VMobject` and\n{class}`.Mobject`.\n\n---\n\n## Can Manim render a video with transparent background?\n\nYes: simply pass the CLI flag `-t` (or its long form `--transparent`).\nNote that the default video file format does not support transparency,\nwhich is why Manim will output a `.mov` instead of a `.mp4` when\nrendering with a transparent background. Other movie file formats\nthat support transparency can be obtained by passing\n`--format=webm` or `--format=gif`.\n\n---\n\n## I have watched a video where a creator ran command X, but it does not work for me. Why?\n\nThe video you have been watching is likely outdated. If you want to follow\nalong, you either need to use the same version used in the video, or\nmodify the code (in many cases it is just a method having been renamed etc.)\naccordingly. Check the video description, in some cases creators point out\nwhether changes need to be applied to the code shown in the video.\n\n---\n\n## When using `Tex` or `MathTex`, some letters are missing. How can I fix this?\n\nIt is possible that you have to (re)build some fonts used by LaTeX. For\nsome distributions, you can do this manually by running\n```bash\nfmtutil -sys --all\n```\nWe recommend consulting the documentation of your LaTeX distribution\nfor more information.\n\n---\n\n## I want to translate some code from `manimgl` to `manim`, what do I do with `CONFIG` dictionaries?\n\nThe community-maintained version has dropped the use of `CONFIG` dictionaries very\nearly, with {doc}`version v0.2.0 </changelog/0.2.0-changelog>` released in\nJanuary 2021.\n\nBefore that, Manim's classes basically processed `CONFIG` dictionaries\nby mimicking inheritance (to properly process `CONFIG` dictionaries set\nby parent classes) and then assigning all of the key-value-pairs in the\ndictionary as attributes of the corresponding object.\n\nIn situations where there is not much inheritance going on,\nor for any custom setting, you should set these attributes yourself.\nFor example, for an old-style `Scene` with custom attributes like\n\n```python\nclass OldStyle(Scene):\n    CONFIG = {\"a\": 1, \"b\": 2}\n```\n\nshould be written as\n\n```python\nclass NewStyle(Scene):\n    a = 1\n    b = 2\n```\n\nIn situations where values should be properly inherited, the arguments\nshould be added to the initialization function of the class. An old-style\nmobject `Thing` could look like\n\n```python\nclass Thing(VMobject):\n    CONFIG = {\n        \"stroke_color\": RED,\n        \"fill_opacity\": 0.7,\n        \"my_awesome_argument\": 42,\n    }\n```\n\nwhere `stroke_color` and `fill_opacity` are arguments that concern the\nparent class of `Thing`, and `my_awesome_argument` is a custom argument\nthat only concerns `Thing`. A version without `CONFIG` could look like this:\n\n```python\nclass Thing(VMobject):\n    def __init__(\n        self, stroke_color=RED, fill_opacity=0.7, my_awesome_argument=42, **kwargs\n    ):\n        self.my_awesome_argument = my_awesome_argument\n        super().__init__(stroke_color=stroke_color, fill_opacity=fill_opacity, **kwargs)\n```\n\n---\n\n## My installation does not support converting PDF to SVG, help?\n\nThis is an issue with `dvisvgm`, the tool shipped with LaTeX that\ntransforms LaTeX output to a `.svg` file that\nManim can parse.\n\nFirst, make sure your ``dvisvgm`` version is at least 2.4 by\nchecking the output of\n\n```bash\ndvisvgm --version\n```\n\nIf you do not know how to update `dvisvgm`, please refer to your\nLaTeX distributions documentation (or the documentation of your\noperating system, if `dvisvgm` was installed as a system package).\n\nSecond, check whether your ``dvisvgm`` supports PostScript specials. This is\nneeded to convert from PDF to SVG. Run:\n\n```bash\ndvisvgm -l\n```\n\nIf the output to this command does **not** contain `ps  dvips PostScript specials`,\nthis is a bad sign. In this case, run\n\n```bash\ndvisvgm -h\n```\n\nIf the output does **not** contain `--libgs=filename`, this means your\n`dvisvgm` does not currently support PostScript. You must get another binary.\n\nIf, however, `--libgs=filename` appears in the help, that means that your\n`dvisvgm` needs the Ghostscript library to support PostScript. Search for\n`libgs.so` (on Linux, probably in `/usr/local/lib` or `/usr/lib`) or\n`gsdll32.dll` (on 32-bit Windows, probably in `C:\\windows\\system32`) or\n`gsdll64.dll` (on 64-bit Windows, also probably in `C:\\windows\\system32`)\nor `libgsl.dylib` (on MacOS, probably in `/usr/local/lib` or\n`/opt/local/lib`). Please look carefully, as the file might be located\nelsewhere, e.g. in the directory where Ghostscript is installed.\n\nWhen you have found the library, try (on MacOS or Linux)\n\n```bash\nexport LIBGS=<path to your library including the file name>\ndvisvgm -l\n```\n\nor (on Windows)\n\n```bat\nset LIBGS=<path to your library including the file name>\ndvisvgm -l\n```\n\nYou should now see `ps    dvips PostScript specials` in the output. Refer to\nyour operating system's documentation to find out how you can set or export the\nenvironment variable ``LIBGS`` automatically whenever you open a shell.\n\nAs a last check, you can run\n\n```bash\ndvisvgm -V1\n```\n\n(while still having `LIBGS` set to the correct path, of course.) If `dvisvgm`\ncan find your Ghostscript installation, it will be shown in the output together\nwith the version number.\n\nIf you do not have the necessary library on your system, please refer to your\noperating system's documentation to find out where you can get it and how you\nhave to install it.\n\nIf you are unable to solve your problem, check out the\n[dvisvgm FAQ](https://dvisvgm.de/FAQ/).\n\n---\n\n## Where can I find more resources for learning Manim?\n\nIn our [Discord server](https://manim.community/discord), we have the community-maintained\n`#beginner-resources` channel in which links to helpful learning resources are collected.\nYou are welcome to join our Discord and take a look yourself! If you have found some\nguides or tutorials yourself that are not on our list yet, feel free to add them!\n"
  },
  {
    "path": "docs/source/faq/help.md",
    "content": "# FAQ: Getting Help\n\n## How do I animate X? Why do I get error Y? Can someone help me?\n\nBefore asking the community, please make sure that the issue you are having\nis not already discussed in our {doc}`FAQ section </faq/index>` sufficiently\nwell so that you can resolve the problem yourself. You can also try to\nuse your favorite search engine, if you are lucky you might find a blog post,\na question on [StackOverflow](https://stackoverflow.com/questions/tagged/manim),\nor a post in the [r/manim subreddit](https://reddit.com/r/manim).\n\nIf this is not the case, please take a moment to properly prepare your question:\nthe better you manage to explain what exactly it is you are struggling with,\nthe more efficient people will be able to help you. Regardless of the platform\nyou choose in the next step, StackOverflow has a good guide on\n[asking good questions](https://stackoverflow.com/help/how-to-ask).\n\nAs soon as you have a good idea of what exactly you want to ask, pick one of the\nfollowing communication channels:\n\n- The community is most active [in our Discord server](https://manim.community/discord/).\n  Click the link to join, then pick one of the `#manim-help` channels in the sidebar,\n  and post your question there. If you are comfortable with using Discord, try to search\n  for your problem using the search function of our server; perhaps people have been\n  talking about it before!\n- We are also monitoring questions on\n  [StackOverflow](https://stackoverflow.com/questions/tagged/manim) that are tagged\n  with `manim`.\n- Many people are also active in our [r/manim subreddit](https://reddit.com/r/manim),\n  feel free to post there if you are an avid Redditor -- but be aware that Discord\n  or StackOverflow might be better choices.\n- And finally, you can also start a new [discussion on GitHub](https://github.com/ManimCommunity/manim/discussions)\n  if you dislike all other options.\n\nIn all of these channels, please make sure to abide by Manim's\n{doc}`Code of Conduct </conduct>` -- in short, be *excellent* to one another:\nbe friendly and patient, considerate, and respectful.\n\n---\n\n## What should I do if nobody answers my question?\n\nTry and see whether your question can be improved: did you include all relevant\ninformation (in case of errors: the full stack trace, the code that you were\nrendering, and the command you used to run Manim?). In case you used a very long\nexample, is it possible to construct a more minimal version that has the same\n(faulty) behavior?\n\nIf you posted in one of our help channels on Discord and your question got buried,\nyou are allowed to ping the `@Manim Helper` role to bring it to the attention of\nthe volunteers who are willing to take a look. Please refrain from pinging the role\nimmediately when asking your question for the first time, this is considered impolite.\n\nYou can also try to post your question to a different channel if you feel that you\nare not having any success with your initial choice -- but please do not spam your\nquestion in all of our communication channels (and in particular for Discord:\nplease don't use multiple help channels at once).\n\nIn the end, it is as for most open-source projects: our community members are\nvolunteers. If you do not receive a quick answer to your question, it may be\nbecause nobody knows the answer, or because your question is not clear enough,\nor it could be that everyone who can help you with your problem is busy doing\nother things.\n\n---\n\n## The library does not behave as documented, or something broke in a new release. What should I do?\n\nSounds like you have found a bug. One of the best ways of contributing to the\ndevelopment of Manim is by reporting it!\n\nCheck our list of known issues and feature requests\n[in our GitHub repository](https://github.com/ManimCommunity/manim/issues). If the\nproblem you have found is not listed there yet (use the search function; also check\nwhether there is a corresponding closed issue, it is possible that your problem\nhas already been resolved and will be fixed with the next release), please consider\nthe following steps to submit a new issue.\n\n```{note}\nIf you are unsure whether or not you should file a new issue for some odd behavior\nthat you found, feel free to ask the community developers, preferably in one of\nour `#manim-dev` channels in [our Discord](https://manim.community/discord/).\n```\n\n1. Make sure you are running the latest released version of Manim, your problem\n   might otherwise already be fixed in a more recent version. Check the\n   {doc}`/changelog` for a full list of changes between Manim releases.\n\n2. Choose the correct category for your report when\n   [creating a new issue](https://github.com/ManimCommunity/manim/issues/new/choose).\n   We have dedicated issue templates for *bug reports*, *feature requests*, and\n   *installation issues*. If your report falls into one of these\n   categories, read the issue template carefully! Instructions are given in the\n   `<!-- ... -->` sections of the text field. If you want to suggest a new feature\n   without concrete implementation details, see\n   {ref}`the instructions given in this answer <creating-suggestions>`.\n\n3. For bug reports: prepare a minimal example that can be used to illustrate the\n   issue. Examples with hundreds of lines are very inefficient and tedious to debug.\n   Your problem needs to be reproducible for others, so please make sure to prepare\n   a suitable example.\n\n4. This is mentioned in the bug report template as well, but it is very important:\n   if you report that some code raises an error, make sure to include the full\n   terminal output, from the command you used to run the library up to and including\n   the last line with the error message. Read carefully: if the message mentions\n   that there is another relevant log file, include this other file as well!\n\n---\n\n(creating-suggestions)=\n## I have an idea for a really cool feature that should be implemented, where should I share my idea?\n\nNew suggestions and proposals should be made by\n[creating a new discussion](https://github.com/ManimCommunity/manim/discussions/new?category=suggestions-and-proposals)\nin the [*Suggestions and Proposals* category](https://github.com/ManimCommunity/manim/discussions/categories/suggestions-and-proposals)\nin our GitHub repository. Once the raw idea has been formed into a more concrete,\nimplementable proposal that is supported by the community, and someone has expressed\ninterest in working on the new feature, a corresponding\n[issue](https://github.com/ManimCommunity/manim/issues) will be created. Do **not** create\nissues for suggesting new features directly, they will be closed down.\n"
  },
  {
    "path": "docs/source/faq/index.rst",
    "content": "Frequently Asked Questions\n==========================\n\n.. toctree::\n   :caption: Table of Contents\n   :maxdepth: 2\n   :glob:\n\n   *\n"
  },
  {
    "path": "docs/source/faq/installation.md",
    "content": "# FAQ: Installation\n\n(different-versions)=\n## Why are there different versions of Manim?\n\nManim was originally created by Grant Sanderson as a personal project and for use\nin his YouTube channel,\n[3Blue1Brown](https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw).\nAs his channel gained popularity, many grew to like the style of his animations and\nwanted to use manim for their own projects. However, as manim was only intended for\npersonal use, it was very difficult for other users to install and use it.\n\nIn late 2019, Grant started working on faster OpenGL rendering in a new branch,\nknown as the `shaders` branch. In mid-2020, a group of developers forked it into what is\nnow the community edition; this is the version documented on this website.\nIn early 2021, Grant merged the shaders branch back into master, making it the default branch in his repository -- and this is what `manimgl` is.\nThe old version, before merging the `shaders` branch is sometimes referred to as\n`ManimCairo` and is, at this point, only useful for one singular purpose: rendering\nGrant's old videos locally on your machine. It is still available in his GitHub\nrepository in form of the `cairo-backend` branch.\n\nTo summarize:\n- [**Manim**, or **ManimCE**](https://manim.community) refers to the community\n  maintained version of the library. This is the version documented on this website;\n  the package name on PyPI is [`manim`](https://pypi.org/project/manim/).\n- [ManimGL](https://github.com/3b1b/manim) is the latest released version of the\n  version of the library developed by Grant \"3b1b\" Sanderson. It has more experimental\n  features and breaking changes between versions are not documented. Check out\n  its documentation [here](https://3b1b.github.io/manim/index.html); on PyPI the\n  package name is [`manimgl`](https://pypi.org/project/manimgl/).\n- [ManimCairo](https://github.com/3b1b/manim/tree/cairo-backend) is the name that\n  is sometimes used for the old, pre-OpenGL version of `manimgl`. The latest version\n  of it is available [on PyPI as `manimlib`](https://pypi.org/project/manimgl/),\n  but note that if you intend to use it to compile some old project of Grant,\n  you will likely have to install the exact version from the time the project\n  was created from source.\n\n---\n\n## Which version should I use?\n\nWe recommend the community maintained version especially for beginners. It has been\ndeveloped to be more stable, better tested and documented (!), and quicker to respond\nto community contributions. It is also perfectly reasonable to start learning with the\ncommunity maintained version and then switch to a different version later on.\n\nIf you do not care so much about documentation or stability, and would like to use\nthe exact same version that Grant is using, then use ManimGL.\n\nAnd as mentioned above, ManimCairo should only be used for (re)rendering old\n3Blue1Brown projects (basically 2019 and before).\n\n---\n\n## What are the differences between Manim, ManimGL, ManimCairo? Can I tell for which version a scene was written for?\n\nYou can! The thing that usually gives it away is the `import` statement\nat the top of the file; depending on how the code imports Manim you can tell\nfor which version of the code it was written for:\n\n- If the code imports from `manim` (i.e., `from manim import *`, `import manim as mn`, etc.),\n  then the code you are reading is supposed to be run with the community maintained version.\n- If the import reads `import manimlib` (or `from manimlib import *`), you are likely\n  reading a file to be rendered with ManimGL.\n- And if the import reads `from manimlib.imports import *`, or perhaps even\n  `from big_ol_pile_of_manim_imports import *` you are reading a snippet that is\n  supposed to be rendered with an early, or very early version of ManimCairo, respectively.\n\n---\n\n## How do I know which version of Manim I have installed?\n\nAssuming you can run `manim` in your terminal and there is some output, check the\nfirst line of the text being produced. If you are using the community maintained\nversion, the first line of any output will be `Manim Community <version number>`.\nIf it does not say that, you are likely using ManimGL.\n\nYou can also check the list of packages you have installed: if typing `python`\nin your terminal spawns the interpreter that corresponds to the Python\ninstallation you use (might also be `py`, or `python3`, depending on your\noperating system), running `python -m pip list` will print a list of all\ninstalled packages. Check whether `manim` or `manimgl` appear in that list.\n\nSimilarly, you can use `python -m pip install <package name>` and\n`python -m pip uninstall <package name>` to install and uninstall\npackages from that list, respectively.\n\n---\n\n## I am following the video guide X to install Manim, but some step fails. What do I do?\n\nIt is only natural that there are many video guides on installing Manim\nout there, given that Manim is a library used for creating videos. Unfortunately\nhowever, (YouTube) videos can't be updated easily (without uploading a new one, that is)\nwhen some step in the installation process changes, and so there are many\n**severely outdated** resources out there.\n\nThis is why we strongly recommend following our\n{doc}`written installation guide </installation>` to guide you through the process.\nIn case you prefer using a video guide regardless, please check whether the\ncreator whose guide you have been watching has made a more recent version available,\nand otherwise please contact them directly. Asking for help in the community will\nlikely lead to being suggested to follow our written guide.\n\n---\n\n## Why does ManimPango fail to install when running `pip install manim`?\n\nThis most likely means that pip was not able to use our pre-built wheels\nof the `manimpango` dependency. Let us know (via\n[Discord](https://www.manim.community/discord/) or by opening a\n[new issue on GitHub](https://github.com/ManimCommunity/ManimPango/issues/new))\nwhich architecture you would like to see supported, and we'll see what we\ncan do about it.\n\nTo fix errors when installing `manimpango`, you need to make sure you\nhave all the necessary build requirements. Check out the detailed\ninstructions given in [the BUILDING section](https://github.com/ManimCommunity/ManimPango#BUILDING)\nof [ManimPango's README](https://github.com/ManimCommunity/ManimPango).\n\n---\n\n(not-on-path)=\n## I am using Windows and get the error `X is not recognized as an internal or external command, operable program or batch file`\n\nIf you have followed {doc}`our local installation instructions </installation/uv>` and\nhave not activated the corresponding virtual environment, make sure to use `uv run manim ...`\ninstead of just `manim` (or activate the virtual environment by following the instructions\nprinted when running `uv venv`).\n\nOtherwise there is a problem with the directories where your system is looking for\nexecutables (the `PATH` variable).\nIf `python` is recognized, you can try running\ncommands by prepending `python -m`. That is, `manim` becomes `python -m manim`,\nand `pip` becomes `python -m pip`.\n\nOtherwise see\n[this StackExchange answer](https://superuser.com/questions/143119/how-do-i-add-python-to-the-windows-path/143121#143121)\nto get help with editing the `PATH` variable manually.\n\n---\n\n## I have tried using Chocolatey (`choco install manimce`) to install Manim, but it failed!\n\nMake sure that you were running the command with administrator permissions,\notherwise there can be problems. If this is not the issue, read Chocolatey's\noutput carefully, it should mention a `.log` file containing information why\nthe process failed.\n\nYou are welcome to take this file (and any other input you feel might be\nrelevant) and submit it to Manim's community to ask for help with\nyour problem. See the {doc}`FAQ on getting help </faq/help>` for instructions.\n\n---\n\n## On Windows, when typing `python` or `python3` the Windows store is opened, can I fix this?\n\nYes: you can remove these aliases with these steps:\n\n1. Go to the Windows Setting.\n2. Under *Apps and Features* you will find application execution aliases.\n3. Within this menu, disable the alias(es) that are causing the issue\n   (`python` and/or `python3`).\n\n---\n\n## I am using Anaconda and get an `ImportError` mentioning that some Symbol is not found.\n\nThis is because Anaconda environments come with their own preinstalled\nversion of `cairo` which is not compatible with the version of `pycairo`\nrequired by Manim. Usually it can be fixed by running\n\n```bash\nconda install -c conda-forge pycairo\n```\n\n---\n\n## How can I fix the error that `manimpango/cmanimpango.c` could not be found when trying to install Manim?\n\nThis occasionally happens when your system has to build a wheel for\n[ManimPango](https://github.com/ManimCommunity/ManimPango) locally because there\nis no compatible version for your architecture available on PyPI.\n\nVery often, the problem is resolved by installing Cython (e.g., via\n`pip3 install Cython`) and then trying to reinstall Manim. If this\ndoes not fix it:\n\n- Make sure that you have installed all build dependencies mentioned\n  in [ManimPango's README](https://github.com/ManimCommunity/ManimPango),\n- and if you still run into troubles after that, please reach out to\n  us as described in the {doc}`Getting Help FAQs </faq/help>`.\n"
  },
  {
    "path": "docs/source/faq/internals.md",
    "content": "# Where can I learn more about Manim's internal structure?\n\nEfforts to document the internal structure of Manim is ongoing on our\n[wiki](https://github.com/ManimCommunity/manim/wiki/Developer-documentation-(WIP)).\n\nKeep in mind that since this is a work in progress, the information you find may be\nincomplete, outdated or even wrong. Still, it should serve as a good starting point.\nThe wiki is open for anyone to edit, feel free to add information or even questions\ndirectly on the wiki pages.\n"
  },
  {
    "path": "docs/source/faq/opengl.md",
    "content": "# FAQ: OpenGL rendering\n\n## Are there any resources on how the OpenGL renderer in the community maintained version can be used?\n\nYes. Unfortunately, at this point, the official online documentation does\nnot contain the relevant base classes like `OpenGLMobject` and `OpenGLVMobject`\nor specific OpenGL classes like `OpenGLSurface`, but documentation for some of\nthem is available in form of docstrings\n[in the source code](https://github.com/ManimCommunity/manim/tree/main/manim/mobject/opengl).\n\nFurthermore, [this user guide by *aquabeam*](https://web.archive.org/web/20250708135737/https://www.aquabeam.me/manim/opengl_guide/)\ncan be helpful to get started using the OpenGL renderer.\n\n---\n\n## I am trying to run an interactive scene with `--renderer=opengl` and `Scene.interactive_embed`, but an error (`sqlite3.ProgrammingError`) is raised. How can I fix this?\n\nThis seems to be an issue with a recent IPython release,\nin our experience it helps to downgrade the installed `IPython`\npackage to `8.0.1`: `pip install IPython==8.0.1`.\n"
  },
  {
    "path": "docs/source/guides/add_voiceovers.rst",
    "content": "###########################\nAdding Voiceovers to Videos\n###########################\n\nCreating a full-fledged video with voiceovers is a bit more involved than\ncreating purely visual Manim scenes. One has to use `a video editing\nprogram <https://en.wikipedia.org/wiki/List_of_video_editing_software>`__\nto add the voiceovers after the video has been rendered. This process\ncan be difficult and time-consuming, since it requires a lot of planning\nand preparation.\n\nTo ease the process of adding voiceovers to videos, we have created\n`Manim Voiceover <https://voiceover.manim.community>`__, a plugin\nthat lets you add voiceovers to scenes directly in Python. To install it, run\n\n.. code-block:: bash\n\n    pip install \"manim-voiceover[azure,gtts]\"\n\nVisit `the installation page <https://voiceover.manim.community/en/latest/installation.html>`__\nfor more details on how to install Manim Voiceover.\n\nBasic Usage\n###########\n\nManim Voiceover lets you ...\n\n- Add voiceovers to Manim videos directly in Python, without having to use a video editor.\n- Record voiceovers with your microphone during rendering through a simple command line interface.\n- Develop animations with auto-generated AI voices from various free and proprietary services.\n\nIt provides a very simple API that lets you specify your voiceover script\nand then record it during rendering:\n\n.. code-block:: python\n\n    from manim import *\n    from manim_voiceover import VoiceoverScene\n    from manim_voiceover.services.recorder import RecorderService\n\n\n    # Simply inherit from VoiceoverScene instead of Scene to get all the\n    # voiceover functionality.\n    class RecorderExample(VoiceoverScene):\n        def construct(self):\n            # You can choose from a multitude of TTS services,\n            # or in this example, record your own voice:\n            self.set_speech_service(RecorderService())\n\n            circle = Circle()\n\n            # Surround animation sections with with-statements:\n            with self.voiceover(text=\"This circle is drawn as I speak.\") as tracker:\n                self.play(Create(circle), run_time=tracker.duration)\n                # The duration of the animation is received from the audio file\n                # and passed to the tracker automatically.\n\n            # This part will not start playing until the previous voiceover is finished.\n            with self.voiceover(text=\"Let's shift it to the left 2 units.\") as tracker:\n                self.play(circle.animate.shift(2 * LEFT), run_time=tracker.duration)\n\nTo get started with Manim Voiceover,\nvisit the `Quick Start Guide <https://voiceover.manim.community/en/latest/quickstart.html>`__.\n\nVisit the `Example Gallery <https://voiceover.manim.community/en/latest/examples.html>`__\nto see some examples of Manim Voiceover in action.\n"
  },
  {
    "path": "docs/source/guides/configuration.rst",
    "content": "Configuration\n#############\n\nManim provides an extensive configuration system that allows it to adapt to\nmany different use cases.  There are many configuration options that can be\nconfigured at different times during the scene rendering process.  Each option\ncan be configured programmatically via `the ManimConfig class`_, at the time\nof command invocation via `command-line arguments`_, or at the time the library\nis first imported via `the config files`_.\n\nThe most common, simplest, and recommended way to configure Manim is\nvia the command-line interface (CLI), which is described directly below.\n\nCommand-line arguments\n**********************\n\nBy far the most commonly used command in the CLI is the ``render`` command,\nwhich is used to render scene(s) to an output file.\nIt is used with the following arguments:\n\n.. program-output:: manim render --help\n   :ellipsis: 9\n\nHowever, since Manim defaults to the :code:`render` command whenever no command\nis specified, the following form is far more common and can be used instead:\n\n.. code-block:: bash\n\n   manim [OPTIONS] FILE [SCENES]\n\nAn example of using the above form is:\n\n.. code-block:: bash\n\n   manim -qm file.py SceneOne\n\nThis asks Manim to search for a Scene class called :code:`SceneOne` inside the\nfile ``file.py`` and render it with medium quality (specified by the ``-qm`` flag).\n\nAnother frequently used flag is ``-p`` (\"preview\"), which makes manim\nopen the rendered video after it's done rendering.\n\n.. note:: The ``-p`` flag does not change any properties of the global\n          ``config`` dict.  The ``-p`` flag is only a command-line convenience.\n\nAdvanced examples\n=================\n\nTo render a scene in high quality, but only output the last frame of the scene\ninstead of the whole video, you can execute\n\n.. code-block:: bash\n\n   manim -sqh <file.py> SceneName\n\nThe following example specifies the output file name (with the :code:`-o`\nflag), renders only the first ten animations (:code:`-n` flag) with a white\nbackground (:code:`-c` flag), and saves the animation as a ``.gif`` instead of as a\n``.mp4`` file (``--format=gif`` flag).  It uses the default quality and does not try to\nopen the file after it is rendered.\n\n.. code-block:: bash\n\n   manim -o myscene --format=gif -n 0,10 -c WHITE <file.py> SceneName\n\nA list of all CLI flags\n========================\n\n.. command-output:: manim --help\n.. command-output:: manim render --help\n.. command-output:: manim cfg --help\n.. command-output:: manim plugins --help\n\nThe ManimConfig class\n*********************\n\nThe most direct way of configuring Manim is through the global ``config`` object,\nwhich is an instance of :class:`.ManimConfig`.  Each property of this class is\na config option that can be accessed either with standard attribute syntax or\nwith dict-like syntax:\n\n.. code-block:: pycon\n\n   >>> from manim import *\n   >>> config.background_color = WHITE\n   >>> config[\"background_color\"] = WHITE\n\n.. note:: The former is preferred; the latter is provided for backwards\n          compatibility.\n\nMost classes, including :class:`.Camera`, :class:`.Mobject`, and\n:class:`.Animation`, read some of their default configuration from the global\n``config``.\n\n.. code-block:: pycon\n\n   >>> Camera({}).background_color\n   <Color white>\n   >>> config.background_color = RED  # 0xfc6255\n   >>> Camera({}).background_color\n   <Color #fc6255>\n\n:class:`.ManimConfig` is designed to keep internal consistency.  For example,\nsetting ``frame_y_radius`` will affect ``frame_height``:\n\n.. code-block:: pycon\n\n    >>> config.frame_height\n    8.0\n    >>> config.frame_y_radius = 5.0\n    >>> config.frame_height\n    10.0\n\nThe global ``config`` object is meant to be the single source of truth for all\nconfig options.  All of the other ways of setting config options ultimately\nchange the values of the global ``config`` object.\n\nThe following example illustrates the video resolution chosen for examples\nrendered in our documentation with a reference frame.\n\n.. manim:: ShowScreenResolution\n    :save_last_frame:\n\n    class ShowScreenResolution(Scene):\n        def construct(self):\n            pixel_height = config[\"pixel_height\"]  #  1080 is default\n            pixel_width = config[\"pixel_width\"]  # 1920 is default\n            frame_width = config[\"frame_width\"]\n            frame_height = config[\"frame_height\"]\n            self.add(Dot())\n            d1 = Line(frame_width * LEFT / 2, frame_width * RIGHT / 2).to_edge(DOWN)\n            self.add(d1)\n            self.add(Text(str(pixel_width)).next_to(d1, UP))\n            d2 = Line(frame_height * UP / 2, frame_height * DOWN / 2).to_edge(LEFT)\n            self.add(d2)\n            self.add(Text(str(pixel_height)).next_to(d2, RIGHT))\n\n\nThe config files\n****************\n\nAs the last example shows, executing Manim from the command line may involve\nusing many flags simultaneously.  This may become a nuisance if you must\nexecute the same script many times in a short time period, for example, when\nmaking small incremental tweaks to your scene script.  For this reason, Manim\ncan also be configured using a configuration file.  A configuration file is a\nfile ending with the suffix ``.cfg``.\n\nTo use a local configuration file when rendering your scene, you must create a\nfile with the name ``manim.cfg`` in the same directory as your scene code.\n\n.. warning:: The config file **must** be named ``manim.cfg``. Currently, Manim\n             does not support config files with any other name.\n\nThe config file must start with the section header ``[CLI]``.  The\nconfiguration options under this header have the same name as the CLI flags\nand serve the same purpose.  Take, for example, the following config file.\n\n.. code-block:: ini\n\n   [CLI]\n   # my config file\n   output_file = myscene\n   save_as_gif = True\n   background_color = WHITE\n\nConfig files are parsed with the standard python library ``configparser``. In\nparticular, they will ignore any line that starts with a pound symbol ``#``.\n\nNow, executing the following command\n\n.. code-block:: bash\n\n   manim -o myscene -i -c WHITE <file.py> SceneName\n\nis equivalent to executing the following command, provided that ``manim.cfg``\nis in the same directory as <file.py>,\n\n.. code-block:: bash\n\n   manim <file.py> SceneName\n\n.. tip:: The names of the configuration options admissible in config files are\n         exactly the same as the **long names** of the corresponding command-\n         line flags.  For example, the ``-c`` and ``--background_color`` flags\n         are interchangeable, but the config file only accepts\n         :code:`background_color` as an admissible option.\n\nSince config files are meant to replace CLI flags, all CLI flags can be set via\na config file.  Moreover, any config option can be set via a config file,\nwhether or not it has an associated CLI flag.  See the bottom of this document\nfor a list of all CLI flags and config options.\n\nManim will look for a ``manim.cfg`` config file in the same directory as the\nfile being rendered, and **not** in the directory of execution.  For example,\n\n.. code-block:: bash\n\n   manim -o myscene -i -c WHITE <path/to/file.py> SceneName\n\nwill use the config file found in ``path/to/file.py``, if any.  It will **not**\nuse the config file found in the current working directory, even if it exists.\nIn this way, the user may keep different config files for different scenes or\nprojects, and execute them with the right configuration from anywhere in the\nsystem.\n\nThe file described here is called the **folder-wide** config file because it\naffects all scene scripts found in the same folder.\n\n\nThe user config file\n====================\n\nAs explained in the previous section, a :code:`manim.cfg` config file only\naffects the scene scripts in its same folder.  However, the user may also\ncreate a special config file that will apply to all scenes rendered by that\nuser. This is referred to as the **user-wide** config file, and it will apply\nregardless of where Manim is executed from, and regardless of where the scene\nscript is stored.\n\nThe user-wide config file lives in a special folder, depending on the operating\nsystem.\n\n* Windows: :code:`UserDirectory`/AppData/Roaming/Manim/manim.cfg\n* MacOS: :code:`UserDirectory`/.config/manim/manim.cfg\n* Linux: :code:`UserDirectory`/.config/manim/manim.cfg\n\nHere, :code:`UserDirectory` is the user's home folder.\n\n\n.. note:: A user may have many **folder-wide** config files, one per folder,\n          but only one **user-wide** config file.  Different users in the same\n          computer may each have their own user-wide config file.\n\n.. warning:: Do not store scene scripts in the same folder as the user-wide\n             config file.  In this case, the behavior is undefined.\n\nWhenever you use Manim from anywhere in the system, Manim will look for a\nuser-wide config file and read its configuration.\n\n\nCascading config files\n======================\n\nWhat happens if you execute Manim and it finds both a folder-wide config file\nand a user-wide config file?  Manim will read both files, but if they are\nincompatible, **the folder-wide file takes precedence**.\n\nFor example, take the following user-wide config file\n\n.. code-block:: ini\n\n   # user-wide\n   [CLI]\n   output_file = myscene\n   save_as_gif = True\n   background_color = WHITE\n\nand the following folder-wide file\n\n.. code-block:: ini\n\n   # folder-wide\n   [CLI]\n   save_as_gif = False\n\nThen, executing :code:`manim <file.py> SceneName` will be equivalent to not\nusing any config files and executing\n\n.. code-block:: bash\n\n   manim -o myscene -c WHITE <file.py> SceneName\n\nAny command-line flags have precedence over any config file.  For example,\nusing the previous two config files and executing :code:`manim -c RED\n<file.py> SceneName` is equivalent to not using any config files and\nexecuting\n\n.. code-block:: bash\n\n   manim -o myscene -c RED <file.py> SceneName\n\nThere is also a **library-wide** config file that determines Manim's default\nbehavior and applies to every user of the library.  It has the least\nprecedence, so any config options in the user-wide and any folder-wide files\nwill override the library-wide file.  This is referred to as the *cascading*\nconfig file system.\n\n.. warning:: **The user should not try to modify the library-wide file**.\n\t     Contributors should receive explicit confirmation from the core\n\t     developer team before modifying it.\n\n\nOrder of operations\n*******************\n\n.. raw:: html\n\n    <div class=\"mxgraph\" style=\"max-width:100%;border:1px solid transparent;\" data-mxgraph=\"{&quot;highlight&quot;:&quot;#0000ff&quot;,&quot;nav&quot;:true,&quot;resize&quot;:true,&quot;toolbar&quot;:&quot;zoom layers lightbox&quot;,&quot;edit&quot;:&quot;_blank&quot;,&quot;url&quot;:&quot;https://drive.google.com/uc?id=1WYVKKoRbXrumHEcyQKQ9s1yCnBvfU2Ui&amp;export=download&quot;}\"></div>\n    <script type=\"text/javascript\" src=\"https://viewer.diagrams.net/embed2.js?&fetch=https%3A%2F%2Fdrive.google.com%2Fuc%3Fid%3D1WYVKKoRbXrumHEcyQKQ9s1yCnBvfU2Ui%26export%3Ddownload\"></script>\n\n\n\nWith so many different ways of configuring Manim, it can be difficult to know\nwhen each config option is being set.  In fact, this will depend on how Manim\nis being used.\n\nIf Manim is imported from a module, then the configuration system will follow\nthese steps:\n\n1. The library-wide config file is loaded.\n2. The user-wide and folder-wide files are loaded if they exist.\n3. All files found in the previous two steps are parsed in a single\n   :class:`ConfigParser` object, called ``parser``.  This is where *cascading*\n   happens.\n4. :class:`logging.Logger` is instantiated to create Manim's global ``logger``\n   object. It is configured using the \"logger\" section of the parser,\n   i.e. ``parser['logger']``.\n5. :class:`ManimConfig` is instantiated to create the global ``config`` object.\n6. The ``parser`` from step 3 is fed into the ``config`` from step 5 via\n   :meth:`ManimConfig.digest_parser`.\n7. Both ``logger`` and ``config`` are exposed to the user.\n\nIf Manim is being invoked from the command line, all of the previous steps\nhappen, and are complemented by:\n\n8. The CLI flags are parsed and fed into ``config`` via\n   :meth:`~ManimConfig.digest_args`.\n9. If the ``--config_file`` flag was used, a new :class:`ConfigParser` object\n   is created with the contents of the library-wide file, the user-wide file if\n   it exists, and the file passed via ``--config_file``.  In this case, the\n   folder-wide file, if it exists, is ignored.\n10. The new parser is fed into ``config``.\n11. The rest of the CLI flags are processed.\n\nTo summarize, the order of precedence for configuration options, from lowest to\nhighest precedence is:\n\n1. Library-wide config file,\n2. user-wide config file, if it exists,\n3. folder-wide config file, if it exists OR custom config file, if passed via\n   ``--config_file``,\n4. other CLI flags, and\n5. any programmatic changes made after the config system is set.\n\n\nA list of all config options\n****************************\n\n.. code::\n\n   ['aspect_ratio', 'assets_dir', 'background_color', 'background_opacity',\n   'bottom', 'custom_folders', 'disable_caching', 'dry_run',\n   'ffmpeg_loglevel', 'flush_cache', 'frame_height', 'frame_rate',\n   'frame_size', 'frame_width', 'frame_x_radius', 'frame_y_radius',\n   'from_animation_number', `fullscreen`, 'images_dir', 'input_file', 'left_side',\n   'log_dir', 'log_to_file', 'max_files_cached', 'media_dir', 'media_width',\n   'movie_file_extension', 'notify_outdated_version', 'output_file', 'partial_movie_dir',\n   'pixel_height', 'pixel_width', 'plugins', 'preview',\n   'progress_bar', 'quality', 'right_side', 'save_as_gif', 'save_last_frame',\n   'save_pngs', 'scene_names', 'show_in_file_browser', 'sound', 'tex_dir',\n   'tex_template', 'tex_template_file', 'text_dir', 'top', 'transparent',\n   'upto_animation_number', 'use_opengl_renderer', 'verbosity', 'video_dir',\n   'window_position', 'window_monitor', 'window_size', 'write_all', 'write_to_movie',\n   'enable_wireframe', 'force_window']\n\n\nAccessing CLI command options\n*****************************\n\nEntering ``manim``, or ``manim --help``, will open the main help page.\n\n.. code::\n\n   Usage: manim [OPTIONS] COMMAND [ARGS]...\n\n     Animation engine for explanatory math videos.\n\n   Options:\n     --version  Show version and exit.\n     --help     Show this message and exit.\n\n   Commands:\n     cfg      Manages Manim configuration files.\n     init     Sets up a new project in current working directory with default\n              settings.\n\n              It copies files from templates directory and pastes them in the\n              current working dir.\n     new      Create a new project or insert a new scene.\n     plugins  Manages Manim plugins.\n     render   Render SCENE(S) from the input FILE.\n\n   See 'manim <command>' to read about a specific subcommand.\n\n   Made with <3 by Manim Community developers.\n\nEach of the subcommands has its own help page which can be accessed similarly:\n\n.. code::\n\n   manim render\n   manim render --help\n"
  },
  {
    "path": "docs/source/guides/deep_dive.rst",
    "content": "A deep dive into Manim's internals\n==================================\n\n**Author:** `Benjamin Hackl <https://benjamin-hackl.at>`__\n\n.. admonition:: Disclaimer\n\n    This guide reflects the state of the library as of version ``v0.16.0``\n    and primarily treats the Cairo renderer. The situation in the latest\n    version of Manim might be different; in case of substantial deviations\n    we will add a note below.\n\nIntroduction\n------------\n\nManim can be a wonderful library, if it behaves the way you would like it to,\nand/or the way you expect it to. Unfortunately, this is not always the case\n(as you probably know if you have played with some manimations yourself already).\nTo understand where things *go wrong*, digging through the library's source code\nis sometimes the only option -- but in order to do that, you need to know where\nto start digging.\n\nThis article is intended as some sort of life line through the render process.\nWe aim to give an appropriate amount of detail describing what happens when\nManim reads your scene code and produces the corresponding animation. Throughout\nthis article, we will focus on the following toy example::\n\n    from manim import *\n\n    class ToyExample(Scene):\n        def construct(self):\n            orange_square = Square(color=ORANGE, fill_opacity=0.5)\n            blue_circle = Circle(color=BLUE, fill_opacity=0.5)\n            self.add(orange_square)\n            self.play(ReplacementTransform(orange_square, blue_circle, run_time=3))\n            small_dot = Dot()\n            small_dot.add_updater(lambda mob: mob.next_to(blue_circle, DOWN))\n            self.play(Create(small_dot))\n            self.play(blue_circle.animate.shift(RIGHT))\n            self.wait()\n            self.play(FadeOut(blue_circle, small_dot))\n\nBefore we go into details or even look at the rendered output of this scene,\nlet us first describe verbally what happens in this *manimation*. In the first\nthree lines of the ``construct`` method, a :class:`.Square` and a :class:`.Circle`\nare initialized, then the square is added to the scene. The first frame of the\nrendered output should thus show an orange square.\n\nThen the actual animations happen: the square first transforms into a circle,\nthen a :class:`.Dot` is created (Where do you guess the dot is located when\nit is first added to the scene? Answering this already requires detailed\nknowledge about the render process.). The dot has an updater attached to it, and\nas the circle moves right, the dot moves with it. In the end, all mobjects are\nfaded out.\n\nActually rendering the code yields the following video:\n\n.. manim:: ToyExample\n    :hide_source:\n\n    class ToyExample(Scene):\n        def construct(self):\n            orange_square = Square(color=ORANGE, fill_opacity=0.5)\n            blue_circle = Circle(color=BLUE, fill_opacity=0.5)\n            self.add(orange_square)\n            self.play(ReplacementTransform(orange_square, blue_circle, run_time=3))\n            small_dot = Dot()\n            small_dot.add_updater(lambda mob: mob.next_to(blue_circle, DOWN))\n            self.play(Create(small_dot))\n            self.play(blue_circle.animate.shift(RIGHT))\n            self.wait()\n            self.play(FadeOut(blue_circle, small_dot))\n\n\nFor this example, the output (fortunately) coincides with our expectations.\n\nOverview\n--------\n\nBecause there is a lot of information in this article, here is a brief overview\ndiscussing the contents of the following chapters on a very high level.\n\n- `Preliminaries`_: In this chapter we unravel all the steps that take place\n  to prepare a scene for rendering; right until the point where the user-overridden\n  ``construct`` method is ran. This includes a brief discussion on using Manim's CLI\n  versus other means of rendering (e.g., via Jupyter notebooks, or in your Python\n  script by calling the :meth:`.Scene.render` method yourself).\n- `Mobject Initialization`_: For the second chapter we dive into creating and handling\n  Mobjects, the basic elements that should be displayed in our scene.\n  We discuss the :class:`.Mobject` base class, how there are essentially\n  three different types of Mobjects, and then discuss the most important of them,\n  vectorized Mobjects. In particular, we describe the internal point data structure\n  that governs how the mechanism responsible for drawing the vectorized Mobject\n  to the screen sets the corresponding Bézier curves. We conclude the chapter\n  with a tour into :meth:`.Scene.add`, the bookkeeping mechanism controlling which\n  mobjects should be rendered.\n- `Animations and the Render Loop`_: And finally, in the last chapter we walk\n  through the instantiation of :class:`.Animation` objects (the blueprints that\n  hold information on how Mobjects should be modified when the render loop runs),\n  followed by a investigation of the infamous :meth:`.Scene.play` call. We will\n  see that there are three relevant parts in a :meth:`.Scene.play` call;\n  a part in which the passed animations and keyword arguments are processed\n  and prepared, followed by the actual \"render loop\" in which the library\n  steps through a time line and renders frame by frame. The final part\n  does some post-processing to save a short video segment (\"partial movie file\")\n  and cleanup for the next call to :meth:`.Scene.play`. In the end, after all of\n  :meth:`.Scene.construct` has been run, the library combines the partial movie\n  files to one video.\n\nAnd with that, let us get *in medias res*.\n\nPreliminaries\n-------------\n\nImporting the library\n^^^^^^^^^^^^^^^^^^^^^\n\nIndependent of how exactly you are telling your system\nto render the scene, i.e., whether you run ``manim -qm -p file_name.py ToyExample``, or\nwhether you are rendering the scene directly from the Python script via a snippet\nlike\n\n::\n\n    with tempconfig({\"quality\": \"medium_quality\", \"preview\": True}):\n        scene = ToyExample()\n        scene.render()\n\nor whether you are rendering the code in a Jupyter notebook, you are still telling your\npython interpreter to import the library. The usual pattern used to do this is\n\n::\n\n    from manim import *\n\nwhich (while being a debatable strategy in general) imports a lot of classes and\nfunctions shipped with the library and makes them available in your global name space.\nI explicitly avoided stating that it imports **all** classes and functions of the\nlibrary, because it does not do that: Manim makes use of the practice described\nin `Section 6.4.1 of the Python tutorial <https://docs.python.org/3/tutorial/modules.html#importing-from-a-package>`__,\nand all module members that should be exposed to the user upon running the ``*``-import\nare explicitly declared in the ``__all__`` variable of the module.\n\nManim also uses this strategy internally: taking a peek at the file that is run when\nthe import is called, ``__init__.py`` (see\n`here <https://github.com/ManimCommunity/manim/blob/main/manim/__init__.py>`__),\nyou will notice that most of the code in that module is concerned with importing\nmembers from various different submodules, again using ``*``-imports.\n\n.. hint::\n\n    If you would ever contribute a new submodule to Manim, the main\n    ``__init__.py`` is where it would have to be listed in order to make its\n    members accessible to users after importing the library.\n\nIn that file, there is one particular import at the beginning of the file however,\nnamely::\n\n    from ._config import *\n\nThis initializes Manim's global configuration system, which is used in various places\nthroughout the library. After the library runs this line, the current configuration\noptions are set. The code in there takes care of reading the options in your ``.cfg``\nfiles (all users have at least the global one that is shipped with the library)\nas well as correctly handling command line arguments (if you used the CLI to render).\n\nYou can read more about the config system in the\n:doc:`corresponding thematic guide </guides/configuration>`, and if you are interested in learning\nmore about the internals of the configuration system and how it is initialized,\nfollow the code flow starting in `the config module's init file\n<https://github.com/ManimCommunity/manim/blob/main/manim/_config/__init__.py>`__.\n\nNow that the library is imported, we can turn our attention to the next step:\nreading your scene code (which is not particularly exciting, Python just creates\na new class ``ToyExample`` based on our code; Manim is virtually not involved\nin that step, with the exception that ``ToyExample`` inherits from ``Scene``).\n\nHowever, with the ``ToyExample`` class created and ready to go, there is a new\nexcellent question to answer: how is the code in our ``construct`` method\nactually executed?\n\nScene instantiation and rendering\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe answer to this question depends on how exactly you are running the code.\nTo make things a bit clearer, let us first consider the case that you\nhave created a file ``toy_example.py`` which looks like this::\n\n    from manim import *\n\n    class ToyExample(Scene):\n        def construct(self):\n            orange_square = Square(color=ORANGE, fill_opacity=0.5)\n            blue_circle = Circle(color=BLUE, fill_opacity=0.5)\n            self.add(orange_square)\n            self.play(ReplacementTransform(orange_square, blue_circle, run_time=3))\n            small_dot = Dot()\n            small_dot.add_updater(lambda mob: mob.next_to(blue_circle, DOWN))\n            self.play(Create(small_dot))\n            self.play(blue_circle.animate.shift(RIGHT))\n            self.wait()\n            self.play(FadeOut(blue_circle, small_dot))\n\n    with tempconfig({\"quality\": \"medium_quality\", \"preview\": True}):\n        scene = ToyExample()\n        scene.render()\n\nWith such a file, the desired scene is rendered by simply running this Python\nscript via ``python toy_example.py``. Then, as described above, the library\nis imported and Python has read and defined the ``ToyExample`` class (but,\nread carefully: *no instance of this class has been created yet*).\n\nAt this point, the interpreter is about to enter the ``tempconfig`` context\nmanager. Even if you have not seen Manim's ``tempconfig`` before, its name\nalready suggests what it does: it creates a copy of the current state of the\nconfiguration, applies the changes to the key-value pairs in the passed\ndictionary, and upon leaving the context the original version of the\nconfiguration is restored. TL;DR: it provides a fancy way of temporarily setting\nconfiguration options.\n\nInside the context manager, two things happen: an actual ``ToyExample``-scene\nobject is instantiated, and the ``render`` method is called. Every way of using\nManim ultimately does something along of these lines, the library always instantiates\nthe scene object and then calls its ``render`` method. To illustrate that this\nreally is the case, let us briefly look at the two most common ways of rendering\nscenes:\n\n**Command Line Interface.** When using the CLI and running the command\n``manim -qm -p toy_example.py ToyExample`` in your terminal, the actual\nentry point is Manim's ``__main__.py`` file (located\n`here <https://github.com/ManimCommunity/manim/blob/main/manim/__main__.py>`__.\nManim uses `Click <https://click.palletsprojects.com/en/8.0.x/>`__ to implement\nthe command line interface, and the corresponding code is located in Manim's\n``cli`` module (https://github.com/ManimCommunity/manim/tree/main/manim/cli).\nThe corresponding code creating the scene class and calling its render method\nis located `here <https://github.com/ManimCommunity/manim/blob/ac1ee9a683ce8b92233407351c681f7d71a4f2db/manim/cli/render/commands.py#L139-L141>`__.\n\n**Jupyter notebooks.** In Jupyter notebooks, the communication with the library\nis handled by the ``%%manim`` magic command, which is implemented in the\n``manim.utils.ipython_magic`` module. There is\n:meth:`some documentation <.ManimMagic.manim>` available for the magic command,\nand the code creating the scene class and calling its render method is located\n`here <https://github.com/ManimCommunity/manim/blob/ac1ee9a683ce8b92233407351c681f7d71a4f2db/manim/utils/ipython_magic.py#L137-L138>`__.\n\n\nNow that we know that either way, a :class:`.Scene` object is created, let us investigate\nwhat Manim does when that happens. When instantiating our scene object\n\n::\n\n    scene = ToyExample()\n\nthe ``Scene.__init__`` method is called, given that we did not implement our own initialization\nmethod. Inspecting the corresponding code (see\n`here <https://github.com/ManimCommunity/manim/blob/main/manim/scene/scene.py>`__)\nreveals that ``Scene.__init__`` first sets several attributes of the scene objects that do not\ndepend on any configuration options set in ``config``. Then the scene inspects the value of\n``config.renderer``, and based on its value, either instantiates a ``CairoRenderer`` or an\n``OpenGLRenderer`` object and assigns it to its ``renderer`` attribute.\n\nThe scene then asks its renderer to initialize the scene by calling\n\n::\n\n    self.renderer.init_scene(self)\n\nInspecting both the default Cairo renderer and the OpenGL renderer shows that the ``init_scene``\nmethod effectively makes the renderer instantiate a :class:`.SceneFileWriter` object, which\nbasically is Manim's interface to ``libav`` (FFMPEG) and actually writes the movie file. The Cairo\nrenderer (see the implementation `here <https://github.com/ManimCommunity/manim/blob/main/manim/renderer/cairo_renderer.py>`__) does not require any further initialization. The OpenGL renderer\ndoes some additional setup to enable the realtime rendering preview window, which we do not go\ninto detail further here.\n\n.. warning::\n\n    Currently, there is a lot of interplay between a scene and its renderer. This is a flaw\n    in Manim's current architecture, and we are working on reducing this interdependency to\n    achieve a less convoluted code flow.\n\nAfter the renderer has been instantiated and initialized its file writer, the scene populates\nfurther initial attributes (notable mention: the ``mobjects`` attribute which keeps track\nof the mobjects that have been added to the scene). It is then done with its instantiation\nand ready to be rendered.\n\nThe rest of this article is concerned with the last line in our toy example script::\n\n    scene.render()\n\nThis is where the actual magic happens.\n\nInspecting the `implementation of the render method <https://github.com/ManimCommunity/manim/blob/df1a60421ea1119cbbbd143ef288d294851baaac/manim/scene/scene.py#L211>`__\nreveals that there are several hooks that can be used for pre- or postprocessing\na scene. Unsurprisingly, :meth:`.Scene.render` describes the full *render cycle*\nof a scene. During this life cycle, there are three custom methods whose base\nimplementation is empty and that can be overwritten to suit your purposes. In\nthe order they are called, these customizable methods are:\n\n- :meth:`.Scene.setup`, which is intended for preparing and, well, *setting up*\n  the scene for your animation (e.g., adding initial mobjects, assigning custom\n  attributes to your scene class, etc.),\n- :meth:`.Scene.construct`, which is the *script* for your screen play and\n  contains programmatic descriptions of your animations, and\n- :meth:`.Scene.tear_down`, which is intended for any operations you might\n  want to run on the scene after the last frame has already been rendered\n  (for example, this could run some code that generates a custom thumbnail\n  for the video based on the state of the objects in the scene -- this\n  hook is more relevant for situations where Manim is used within other\n  Python scripts).\n\nAfter these three methods are run, the animations have been fully rendered,\nand Manim calls :meth:`.CairoRenderer.scene_finished` to gracefully\ncomplete the rendering process. This checks whether any animations have been\nplayed -- and if so, it tells the :class:`.SceneFileWriter` to close the output\nfile. If not, Manim assumes that a static image should be output\nwhich it then renders using the same strategy by calling the render loop\n(see below) once.\n\n**Back in our toy example,** the call to :meth:`.Scene.render` first\ntriggers :meth:`.Scene.setup` (which only consists of ``pass``), followed by\na call of :meth:`.Scene.construct`. At this point, our *animation script*\nis run, starting with the initialization of ``orange_square``.\n\n\nMobject Initialization\n----------------------\n\nMobjects are, in a nutshell, the Python objects that represent all the\n*things* we want to display in our scene. Before we follow our debugger\ninto the depths of mobject initialization code, it makes sense to\ndiscuss Manim's different types of Mobjects and their basic data\nstructure.\n\nWhat even is a Mobject?\n^^^^^^^^^^^^^^^^^^^^^^^\n\n:class:`.Mobject` stands for *mathematical object* or *Manim object*\n(depends on who you ask 😄). The Python class :class:`.Mobject` is\nthe base class for all objects that should be displayed on screen.\nLooking at the `initialization method\n<https://github.com/ManimCommunity/manim/blob/5d72d9cfa2e3dd21c844b1da807576f5a7194fda/manim/mobject/mobject.py#L94>`__\nof :class:`.Mobject`, you will find that not too much happens in there:\n\n- some initial attribute values are assigned, like ``name`` (which makes the\n  render logs mention the name of the mobject instead of its type),\n  ``submobjects`` (initially an empty list), ``color``, and some others.\n- Then, two methods related to *points* are called: ``reset_points``\n  followed by ``generate_points``,\n- and finally, ``init_colors`` is called.\n\nDigging deeper, you will find that :meth:`.Mobject.reset_points` simply\nsets the ``points`` attribute of the mobject to an empty NumPy vector,\nwhile the other two methods, :meth:`.Mobject.generate_points` and\n:meth:`.Mobject.init_colors` are just implemented as ``pass``.\n\nThis makes sense: :class:`.Mobject` is not supposed to be used as\nan *actual* object that is displayed on screen; in fact the camera\n(which we will discuss later in more detail; it is the class that is,\nfor the Cairo renderer, responsible for \"taking a picture\" of the\ncurrent scene) does not process \"pure\" :class:`Mobjects <.Mobject>`\nin any way, they *cannot* even appear in the rendered output.\n\nThis is where different types of mobjects come into play. Roughly\nspeaking, the Cairo renderer setup knows three different types of\nmobjects that can be rendered:\n\n- :class:`.ImageMobject`, which represent images that you can display\n  in your scene,\n- :class:`.PMobject`, which are very special mobjects used to represent\n  point clouds; we will not discuss them further in this guide,\n- :class:`.VMobject`, which are *vectorized mobjects*, that is, mobjects\n  that consist of points that are connected via curves. These are pretty\n  much everywhere, and we will discuss them in detail in the next section.\n\n... and what are VMobjects?\n^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nAs just mentioned, :class:`VMobjects <.VMobject>` represent vectorized\nmobjects. To render a :class:`.VMobject`, the camera looks at the\n``points`` attribute of a :class:`.VMobject` and divides it into sets\nof four points each. Each of these sets is then used to construct a\ncubic Bézier curve with the first and last entry describing the\nend points of the curve (\"anchors\"), and the second and third entry\ndescribing the control points in between (\"handles\").\n\n.. hint::\n  To learn more about Bézier curves, take a look at the excellent\n  online textbook `A Primer on Bézier curves <https://pomax.github.io/bezierinfo/>`__\n  by `Pomax <https://twitter.com/TheRealPomax>`__ -- there is a playground representing\n  cubic Bézier curves `in §1 <https://pomax.github.io/bezierinfo/#introduction>`__,\n  the red and yellow points are \"anchors\", and the green and blue\n  points are \"handles\".\n\nIn contrast to :class:`.Mobject`, :class:`.VMobject` can be displayed\non screen (even though, technically, it is still considered a base class).\nTo illustrate how points are processed, consider the following short example\nof a :class:`.VMobject` with 8 points (and thus made out of 8/4 = 2 cubic\nBézier curves). The resulting :class:`.VMobject` is drawn in green.\nThe handles are drawn as red dots with a line to their closest anchor.\n\n.. manim:: VMobjectDemo\n    :save_last_frame:\n\n    class VMobjectDemo(Scene):\n        def construct(self):\n            plane = NumberPlane()\n            my_vmobject = VMobject(color=GREEN)\n            my_vmobject.points = [\n                np.array([-2, -1, 0]),  # start of first curve\n                np.array([-3, 1, 0]),\n                np.array([0, 3, 0]),\n                np.array([1, 3, 0]),  # end of first curve\n                np.array([1, 3, 0]),  # start of second curve\n                np.array([0, 1, 0]),\n                np.array([4, 3, 0]),\n                np.array([4, -2, 0]),  # end of second curve\n            ]\n            handles = [\n                Dot(point, color=RED) for point in\n                [[-3, 1, 0], [0, 3, 0], [0, 1, 0], [4, 3, 0]]\n            ]\n            handle_lines = [\n                Line(\n                    my_vmobject.points[ind],\n                    my_vmobject.points[ind+1],\n                    color=RED,\n                    stroke_width=2\n                ) for ind in range(0, len(my_vmobject.points), 2)\n            ]\n            self.add(plane, *handles, *handle_lines, my_vmobject)\n\n\n.. warning::\n  Manually setting the points of your :class:`.VMobject` is usually\n  discouraged; there are specialized methods that can take care of\n  that for you -- but it might be relevant when implementing your own,\n  custom :class:`.VMobject`.\n\n\n\nSquares and Circles: back to our Toy Example\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWith a basic understanding of different types of mobjects,\nand an idea of how vectorized mobjects are built we can now\ncome back to our toy example and the execution of the\n:meth:`.Scene.construct` method. In the first two lines\nof our animation script, the ``orange_square`` and the\n``blue_circle`` are initialized.\n\nWhen creating the orange square by running\n\n::\n\n  Square(color=ORANGE, fill_opacity=0.5)\n\nthe initialization method of :class:`.Square`,\n``Square.__init__``, is called. `Looking at the\nimplementation <https://github.com/ManimCommunity/manim/blob/5d72d9cfa2e3dd21c844b1da807576f5a7194fda/manim/mobject/geometry/polygram.py#L607>`__,\nwe can see that the ``side_length`` attribute of the square is set,\nand then\n\n::\n\n  super().__init__(height=side_length, width=side_length, **kwargs)\n\nis called. This ``super`` call is the Python way of calling the\ninitialization function of the parent class. As :class:`.Square`\ninherits from :class:`.Rectangle`, the next method called\nis ``Rectangle.__init__``. There, only the first three lines\nare really relevant for us::\n\n  super().__init__(UR, UL, DL, DR, color=color, **kwargs)\n  self.stretch_to_fit_width(width)\n  self.stretch_to_fit_height(height)\n\nFirst, the initialization function of the parent class of\n:class:`.Rectangle` -- :class:`.Polygon` -- is called. The\nfour positional arguments passed are the four corners of\nthe polygon: ``UR`` is up right (and equal to ``UP + RIGHT``),\n``UL`` is up left (and equal to ``UP + LEFT``), and so forth.\nBefore we follow our debugger deeper, let us observe what\nhappens with the constructed polygon: the remaining two lines\nstretch the polygon to fit the specified width and height\nsuch that a rectangle with the desired measurements is created.\n\nThe initialization function of :class:`.Polygon` is particularly\nsimple, it only calls the initialization function of its parent\nclass, :class:`.Polygram`. There, we have almost reached the end\nof the chain: :class:`.Polygram` inherits from :class:`.VMobject`,\nwhose initialization function mainly sets the values of some\nattributes (quite similar to ``Mobject.__init__``, but more specific\nto the Bézier curves that make up the mobject).\n\nAfter calling the initialization function of :class:`.VMobject`,\nthe constructor of :class:`.Polygram` also does something somewhat\nodd: it sets the points (which, you might remember above, should\nactually be set in a corresponding ``generate_points`` method\nof :class:`.Polygram`).\n\n.. warning::\n  In several instances, the implementation of mobjects does\n  not really stick to all aspects of Manim's interface. This\n  is unfortunate, and increasing consistency is something\n  that we actively work on. Help is welcome!\n\nWithout going too much into detail, :class:`.Polygram` sets its\n``points`` attribute via :meth:`.VMobject.start_new_path`,\n:meth:`.VMobject.add_points_as_corners`, which take care of\nsetting the quadruples of anchors and handles appropriately.\nAfter the points are set, Python continues to process the\ncall stack until it reaches the method that was first called;\nthe initialization method of :class:`.Square`. After this,\nthe square is initialized and assigned to the ``orange_square``\nvariable.\n\nThe initialization of ``blue_circle`` is similar to the one of\n``orange_square``, with the main difference being that the inheritance\nchain of :class:`.Circle` is different. Let us briefly follow the trace\nof the debugger:\n\nThe implementation of :meth:`.Circle.__init__` immediately calls\nthe initialization method of :class:`.Arc`, as a circle in Manim\nis simply an arc with an angle of :math:`\\tau = 2\\pi`. When\ninitializing the arc, some basic attributes are set (like\n``Arc.radius``, ``Arc.arc_center``, ``Arc.start_angle``, and\n``Arc.angle``), and then the initialization method of its\nparent class, :class:`.TipableVMobject`, is called (which is\na rather abstract base class for mobjects which a arrow tip can\nbe attached to). Note that in contrast to :class:`.Polygram`,\nthis class does **not** preemptively generate the points of the circle.\n\nAfter that, things are less exciting: :class:`.TipableVMobject` again\nsets some attributes relevant for adding arrow tips, and afterwards\npasses to the initialization method of :class:`.VMobject`. From there,\n:class:`.Mobject` is initialized and :meth:`.Mobject.generate_points`\nis called, which actually runs the method implemented in\n:meth:`.Arc.generate_points`.\n\nAfter both our ``orange_square`` and the ``blue_circle`` are initialized,\nthe square is actually added to the scene. The :meth:`.Scene.add` method\nis actually doing a few interesting things, so it is worth to dig a bit\ndeeper in the next section.\n\n\nAdding Mobjects to the Scene\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe code in our ``construct`` method that is run next is\n\n::\n\n  self.add(orange_square)\n\nFrom a high-level point of view, :meth:`.Scene.add` adds the\n``orange_square`` to the list of mobjects that should be rendered,\nwhich is stored in the ``mobjects`` attribute of the scene. However,\nit does so in a very careful way to avoid the situation that a mobject\nis being added to the scene more than once. At a first glance, this\nsounds like a simple task -- the problem is that ``Scene.mobjects``\nis not a \"flat\" list of mobjects, but a list of mobjects which\nmight contain mobjects themselves, and so on.\n\nStepping through the code in :meth:`.Scene.add`, we see that first\nit is checked whether we are currently using the OpenGL renderer\n(which we are not) -- adding mobjects to the scene works slightly\ndifferent (and actually easier!) for the OpenGL renderer. Then, the\ncode branch for the Cairo renderer is entered and the list of so-called\nforeground mobjects (which are rendered on top of all other mobjects)\nis added to the list of passed mobjects. This is to ensure that the\nforeground mobjects will stay above of the other mobjects, even after\nadding the new ones. In our case, the list of foreground mobjects\nis actually empty, and nothing changes.\n\nNext, :meth:`.Scene.restructure_mobjects` is called with the list\nof mobjects to be added as the ``to_remove`` argument, which might\nsound odd at first. Practically, this ensures that mobjects are not\nadded twice, as mentioned above: if they were present in the scene\n``Scene.mobjects`` list before (even if they were contained as a\nchild of some other mobject), they are first removed from the list.\nThe way :meth:`.Scene.restructure_mobjects` works is rather aggressive:\nIt always operates on a given list of mobjects; in the ``add`` method\ntwo different lists occur: the default one, ``Scene.mobjects`` (no extra\nkeyword argument is passed), and ``Scene.moving_mobjects`` (which we will\ndiscuss later in more detail). It iterates through all of the members of\nthe list, and checks whether any of the mobjects passed in ``to_remove``\nare contained as children (in any nesting level). If so, **their parent\nmobject is deconstructed** and their siblings are inserted directly\none level higher. Consider the following example::\n\n  >>> from manim import Scene, Square, Circle, Group\n  >>> test_scene = Scene()\n  >>> mob1 = Square()\n  >>> mob2 = Circle()\n  >>> mob_group = Group(mob1, mob2)\n  >>> test_scene.add(mob_group)\n  <manim.scene.scene.Scene object at ...>\n  >>> test_scene.mobjects\n  [Group]\n  >>> test_scene.restructure_mobjects(to_remove=[mob1])\n  <manim.scene.scene.Scene object at ...>\n  >>> test_scene.mobjects\n  [Circle]\n\nNote that the group is disbanded and the circle moves into the\nroot layer of mobjects in ``test_scene.mobjects``.\n\nAfter the mobject list is \"restructured\", the mobject to be added\nare simply appended to ``Scene.mobjects``. In our toy example,\nthe ``Scene.mobjects`` list is actually empty, so the\n``restructure_mobjects`` method does not actually do anything. The\n``orange_square`` is simply added to ``Scene.mobjects``, and as\nthe aforementioned ``Scene.moving_mobjects`` list is, at this point,\nalso still empty, nothing happens and :meth:`.Scene.add` returns.\n\nWe will hear more about the ``moving_mobject`` list when we discuss\nthe render loop. Before we do that, let us look at the next line\nof code in our toy example, which includes the initialization of\nan animation class,\n::\n\n  ReplacementTransform(orange_square, blue_circle, run_time=3)\n\nHence it is time to talk about :class:`.Animation`.\n\n\nAnimations and the Render Loop\n------------------------------\n\nInitializing animations\n^^^^^^^^^^^^^^^^^^^^^^^\n\nBefore we follow the trace of the debugger, let us briefly discuss\nthe general structure of the (abstract) base class :class:`.Animation`.\nAn animation object holds all the information necessary for the renderer\nto generate the corresponding frames. Animations (in the sense of\nanimation objects) in Manim are *always* tied to a specific mobject;\neven in the case of :class:`.AnimationGroup` (which you should actually\nthink of as an animation on a group of mobjects rather than a group\nof animations). Moreover, except for in a particular special case,\nthe run time of animations is also fixed and known beforehand.\n\nThe initialization of animations actually is not very exciting,\n:meth:`.Animation.__init__` merely sets some attributes derived\nfrom the passed keyword arguments and additionally ensures that\nthe ``Animation.starting_mobject`` and ``Animation.mobject``\nattributes are populated. Once the animation is played, the\n``starting_mobject`` attribute holds an unmodified copy of the\nmobject the animation is attached to; during the initialization\nit is set to a placeholder mobject. The ``mobject`` attribute\nis set to the mobject the animation is attached to.\n\nAnimations have a few special methods which are called during the\nrender loop:\n\n- :meth:`.Animation.begin`, which is called (as hinted by its name)\n  at the beginning of every animation, so before the first frame\n  is rendered. In it, all the required setup for the animation happens.\n- :meth:`.Animation.finish` is the counterpart to the ``begin`` method\n  which is called at the end of the life cycle of the animation (after\n  the last frame has been rendered).\n- :meth:`.Animation.interpolate` is the method that updates the mobject\n  attached to the animation to the corresponding animation completion\n  percentage. For example, if in the render loop,\n  ``some_animation.interpolate(0.5)`` is called, the attached mobject\n  will be updated to the state where 50% of the animation are completed.\n\nWe will discuss details about these and some further animation methods\nonce we walk through the actual render loop. For now, we continue with\nour toy example and the code that is run when initializing the\n:class:`.ReplacementTransform` animation.\n\nThe initialization method of :class:`.ReplacementTransform` only\nconsists of a call to the constructor of its parent class,\n:class:`.Transform`, with the additional keyword argument\n``replace_mobject_with_target_in_scene`` set to ``True``.\n:class:`.Transform` then sets attributes that control how the\npoints of the starting mobject are deformed into the points of\nthe target mobject, and then passes on to the initialization\nmethod of :class:`.Animation`. Other basic properties of the\nanimation (like its ``run_time``, the ``rate_func``, etc.) are\nprocessed there -- and then the animation object is fully\ninitialized and ready to be played.\n\nThe ``play`` call: preparing to enter Manim's render loop\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWe are finally there, the render loop is in our reach. Let us\nwalk through the code that is run when :meth:`.Scene.play` is called.\n\n.. hint::\n\n  Recall that this article is specifically about the Cairo renderer.\n  Up to here, things were more or less the same for the OpenGL renderer\n  as well; while some base mobjects might be different, the control flow\n  and lifecycle of mobjects is still more or less the same. There are more\n  substantial differences when it comes to the rendering loop.\n\nAs you will see when inspecting the method, :meth:`.Scene.play` almost\nimmediately passes over to the ``play`` method of the renderer,\nin our case :class:`.CairoRenderer.play`. The one thing :meth:`.Scene.play`\ntakes care of is the management of subcaptions that you might have\npassed to it (see the the documentation of :meth:`.Scene.play` and\n:meth:`.Scene.add_subcaption` for more information).\n\n.. warning::\n\n  As has been said before, the communication between scene and renderer\n  is not in a very clean state at this point, so the following paragraphs\n  might be confusing if you don't run a debugger and step through the\n  code yourself a bit.\n\nInside :meth:`.CairoRenderer.play`, the renderer first checks whether\nit may skip rendering of the current play call. This might happen, for example,\nwhen ``-s`` is passed to the CLI (i.e., only the last frame should be rendered),\nor when the ``-n`` flag is passed and the current play call is outside of the\nspecified render bounds. The \"skipping status\" is updated in form of the\ncall to :meth:`.CairoRenderer.update_skipping_status`.\n\nNext, the renderer asks the scene to process the animations in the play\ncall so that renderer obtains all of the information it needs. To\nbe more concrete, :meth:`.Scene.compile_animation_data` is called,\nwhich then takes care of several things:\n\n- The method processes all animations and the keyword arguments passed\n  to the initial :meth:`.Scene.play` call. In particular, this means\n  that it makes sure all arguments passed to the play call are actually\n  animations (or ``.animate`` syntax calls, which are also assembled to\n  be actual :class:`.Animation`-objects at that point). It also propagates\n  any animation-related keyword arguments (like ``run_time``,\n  or ``rate_func``) passed to :class:`.Scene.play` to each individual\n  animation. The processed animations are then stored in the ``animations``\n  attribute of the scene (which the renderer later reads...).\n- It adds all mobjects to which the animations that are played are\n  bound to to the scene (provided the animation is not an mobject-introducing\n  animation -- for these, the addition to the scene happens later).\n- In case the played animation is a :class:`.Wait` animation (this is the\n  case in a :meth:`.Scene.wait` call), the method checks whether a static\n  image should be rendered, or whether the render loop should be processed\n  as usual (see :meth:`.Scene.should_update_mobjects` for the exact conditions,\n  basically it checks whether there are any time-dependent updater functions\n  and so on).\n- Finally, the method determines the total run time of the play call (which\n  at this point is computed as the maximum of the run times of the passed\n  animations). This is stored in the ``duration`` attribute of the scene.\n\n\nAfter the animation data has been compiled by the scene, the renderer\ncontinues to prepare for entering the render loop. It now checks the\nskipping status which has been determined before. If the renderer can\nskip this play call, it does so: it sets the current play call hash (which\nwe will get back to in a moment) to ``None`` and increases the time of the\nrenderer by the determined animation run time.\n\nOtherwise, the renderer checks whether or not Manim's caching system should\nbe used. The idea of the caching system is simple: for every play call, a\nhash value is computed, which is then stored and upon re-rendering the scene,\nthe hash is generated again and checked against the stored value. If it is the\nsame, the cached output is reused, otherwise it is fully rerendered again.\nWe will not go into details of the caching system here; if you would like\nto learn more, the :func:`.get_hash_from_play_call` function in the\n:mod:`.utils.hashing` module is essentially the entry point to the caching\nmechanism.\n\nIn the event that the animation has to be rendered, the renderer asks\nits :class:`.SceneFileWriter` to open an output container. The process\nis started by a call to ``libav`` and opens a container to which rendered\nraw frames can be written. As long as the output is open, the container\ncan be accessed via the ``output_container`` attribute of the file writer.\nWith the writing process in place, the renderer then asks the scene\nto \"begin\" the animations.\n\nFirst, it literally *begins* all of the animations by calling their\nsetup methods (:meth:`.Animation._setup_scene`, :meth:`.Animation.begin`).\nIn doing so, the mobjects that are newly introduced by an animation\n(like via :class:`.Create` etc.) are added to the scene. Furthermore, the\nanimation suspends updater functions being called on its mobject, and\nit sets its mobject to the state that corresponds to the first frame\nof the animation.\n\nAfter this has happened for all animations in the current ``play`` call,\nthe Cairo renderer determines which of the scene's mobjects can be\npainted statically to the background, and which ones have to be\nredrawn every frame. It does so by calling\n:meth:`.Scene.get_moving_and_static_mobjects`, and the resulting\npartition of mobjects is stored in the corresponding ``moving_mobjects``\nand ``static_mobjects`` attributes.\n\n.. NOTE::\n\n  The mechanism that determines static and moving mobjects is\n  specific for the Cairo renderer, the OpenGL renderer works differently.\n  Basically, moving mobjects are determined by checking whether they,\n  any of their children, or any of the mobjects \"below\" them (in the\n  sense of the order in which mobjects are processed in the scene)\n  either have an update function attached, or whether they appear\n  in one of the current animations. See the implementation of\n  :meth:`.Scene.get_moving_mobjects` for more details.\n\nUp to this very point, we did not actually render any (partial)\nimage or movie files from the scene yet. This is, however, about to change.\nBefore we enter the render loop, let us briefly revisit our toy\nexample and discuss how the generic :meth:`.Scene.play` call\nsetup looks like there.\n\nFor the call that plays the :class:`.ReplacementTransform`, there\nis no subcaption to be taken care of. The renderer then asks\nthe scene to compile the animation data: the passed argument\nalready is an animation (no additional preparations needed),\nthere is no need for processing any keyword arguments (as\nwe did not specify any additional ones to ``play``). The\nmobject bound to the animation, ``orange_square``, is already\npart of the scene (so again, no action taken). Finally, the run\ntime is extracted (3 seconds long) and stored in\n``Scene.duration``. The renderer then checks whether it should\nskip (it should not), then whether the animation is already\ncached (it is not). The corresponding animation hash value is\ndetermined and passed to the file writer, which then also calls\n``libav`` to start the writing process which waits for rendered\nframes from the library.\n\nThe scene then ``begin``\\ s the animation: for the\n:class:`.ReplacementTransform` this means that the animation populates\nall of its relevant animation attributes (i.e., compatible copies\nof the starting and the target mobject so that it can safely interpolate\nbetween the two).\n\nThe mechanism determining static and moving mobjects considers\nall of the scenes mobjects (at this point only the\n``orange_square``), and determines that the ``orange_square`` is\nbound to an animation that is currently played. As a result,\nthe square is classified as a \"moving mobject\".\n\nTime to render some frames.\n\n\nThe render loop (for real this time)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nAs mentioned above, due to the mechanism that determines static and moving\nmobjects in the scene, the renderer knows which mobjects it can paint\nstatically to the background of the scene. Practically, this means that\nit partially renders a scene (to produce a background image), and then\nwhen iterating through the time progression of the animation only the\n\"moving mobjects\" are re-painted on top of the static background.\n\nThe renderer calls :meth:`.CairoRenderer.save_static_frame_data`, which\nfirst checks whether there are currently any static mobjects, and if there\nare, it updates the frame (only with the static mobjects; more about how\nexactly this works in a moment) and then saves a NumPy array representing\nthe rendered frame in the ``static_image`` attribute. In our toy example,\nthere are no static mobjects, and so the ``static_image`` attribute is\nsimply set to ``None``.\n\nNext, the renderer asks the scene whether the current animation is\na \"frozen frame\" animation, which would mean that the renderer actually\ndoes not have to repaint the moving mobjects in every frame of the time\nprogression. It can then just take the latest static frame, and display it\nthroughout the animation.\n\n.. NOTE::\n\n  An animation is considered a \"frozen frame\" animation if only a\n  static :class:`.Wait` animation is played. See the description\n  of :meth:`.Scene.compile_animation_data` above, or the\n  implementation of :meth:`.Scene.should_update_mobjects` for\n  more details.\n\nIf this is not the case (just as in our toy example), the renderer\nthen calls the :meth:`.Scene.play_internal` method, which is the\nintegral part of the render loop (in which the library steps through\nthe time progression of the animation and renders the corresponding\nframes).\n\nWithin :meth:`.Scene.play_internal`, the following steps are performed:\n\n- The scene determines the run time of the animations by calling\n  :meth:`.Scene.get_run_time`. This method basically takes the maximum\n  ``run_time`` attribute of all of the animations passed to the\n  :meth:`.Scene.play` call.\n- Then the *time progression* is constructed via the (internal)\n  :meth:`.Scene._get_animation_time_progression` method, which wraps\n  the actual :meth:`.Scene.get_time_progression` method. The time\n  progression is a ``tqdm`` `progress bar object <https://tqdm.github.io>`__\n  for an iterator over ``np.arange(0, run_time, 1 / config.frame_rate)``. In\n  other words, the time progression holds the time stamps (relative to the\n  current animations, so starting at 0 and ending at the total animation run time,\n  with the step size determined by the render frame rate) of the timeline where\n  a new animation frame should be rendered.\n- Then the scene iterates over the time progression: for each time stamp ``t``,\n  :meth:`.Scene.update_to_time` is called, which ...\n\n  - ... first computes the time passed since the last update (which might be 0,\n    especially for the initial call) and references it as ``dt``,\n  - then (in the order in which the animations are passed to :meth:`.Scene.play`)\n    calls :meth:`.Animation.update_mobjects` to trigger all updater functions that\n    are attached to the respective animation except for the \"main mobject\" of\n    the animation (that is, for example, for :class:`.Transform` the unmodified\n    copies of start and target mobject -- see :meth:`.Animation.get_all_mobjects_to_update`\n    for more details),\n  - then the relative time progression with respect to the current animation\n    is computed (``alpha = t / animation.run_time``), which is then used to\n    update the state of the animation with a call to :meth:`.Animation.interpolate`.\n  - After all of the passed animations have been processed, the updater functions\n    of all mobjects in the scene, all meshes, and finally those attached to\n    the scene itself are run.\n\nAt this point, the internal (Python) state of all mobjects has been updated\nto match the currently processed timestamp. If rendering should not be skipped,\nthen it is now time to *take a picture*!\n\n.. NOTE::\n\n  The update of the internal state (iteration over the time progression) happens\n  *always* once :meth:`.Scene.play_internal` is entered. This ensures that even\n  if frames do not need to be rendered (because, e.g., the ``-n`` CLI flag has\n  been passed, something has been cached, or because we might be in a *Section*\n  with skipped rendering), updater functions still run correctly, and the state\n  of the first frame that *is* rendered is kept consistent.\n\nTo render an image, the scene calls the corresponding method of its renderer,\n:meth:`.CairoRenderer.render` and passes just the list of *moving mobjects* (remember,\nthe *static mobjects* are assumed to have already been painted statically to\nthe background of the scene). All of the hard work then happens when the renderer\nupdates its current frame via a call to :meth:`.CairoRenderer.update_frame`:\n\nFirst, the renderer prepares its :class:`.Camera` by checking whether the renderer\nhas a ``static_image`` different from ``None`` stored already. If so, it sets the\nimage as the *background image* of the camera via :meth:`.Camera.set_frame_to_background`,\nand otherwise it just resets the camera via :meth:`.Camera.reset`. The camera is then\nasked to capture the scene with a call to :meth:`.Camera.capture_mobjects`.\n\nThings get a bit technical here, and at some point it is more efficient to\ndelve into the implementation -- but here is a summary of what happens once the\ncamera is asked to capture the scene:\n\n- First, a flat list of mobjects is created (so submobjects get extracted from\n  their parents). This list is then processed in groups of the same type of\n  mobjects (e.g., a batch of vectorized mobjects, followed by a batch of image mobjects,\n  followed by more vectorized mobjects, etc. -- in many cases there will just be\n  one batch of vectorized mobjects).\n- Depending on the type of the currently processed batch, the camera uses dedicated\n  *display functions* to convert the :class:`.Mobject` Python object to\n  a NumPy array stored in the camera's ``pixel_array`` attribute.\n  The most important example in that context is the display function for\n  vectorized mobjects, :meth:`.Camera.display_multiple_vectorized_mobjects`,\n  or the more particular (in case you did not add a background image to your\n  :class:`.VMobject`), :meth:`.Camera.display_multiple_non_background_colored_vmobjects`.\n  This method first gets the current Cairo context, and then, for every (vectorized)\n  mobject in the batch, calls :meth:`.Camera.display_vectorized`. There,\n  the actual background stroke, fill, and then stroke of the mobject is\n  drawn onto the context. See :meth:`.Camera.apply_stroke` and\n  :meth:`.Camera.set_cairo_context_color` for more details -- but it does not get\n  much deeper than that, in the latter method the actual Bézier curves\n  determined by the points of the mobject are drawn; this is where the low-level\n  interaction with Cairo happens.\n\nAfter all batches have been processed, the camera has an image representation\nof the Scene at the current time stamp in form of a NumPy array stored in its\n``pixel_array`` attribute. The renderer then takes this array and passes it to\nits :class:`.SceneFileWriter`. This concludes one iteration of the render loop,\nand once the time progression has been processed completely, a final bit\nof cleanup is performed before the :meth:`.Scene.play_internal` call is completed.\n\nA TL;DR for the render loop, in the context of our toy example, reads as follows:\n\n- The scene finds that a 3 second long animation (the :class:`.ReplacementTransform`\n  changing the orange square to the blue circle) should be played. Given the requested\n  medium render quality, the frame rate is 30 frames per second, and so the time\n  progression with steps ``[0, 1/30, 2/30, ..., 89/30]`` is created.\n- In the internal render loop, each of these time stamps is processed:\n  there are no updater functions, so effectively the scene updates the\n  state of the transformation animation to the desired time stamp (for example,\n  at time stamp ``t = 45/30``, the animation is completed to a rate of\n  ``alpha = 0.5``).\n- Then the scene asks the renderer to do its job. The renderer asks its camera\n  to capture the scene, the only mobject that needs to be processed at this point\n  is the main mobject attached to the transformation; the camera converts the\n  current state of the mobject to entries in a NumPy array. The renderer passes\n  this array to the file writer.\n- At the end of the loop, 90 frames have been passed to the file writer.\n\nCompleting the render loop\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe last few steps in the :meth:`.Scene.play_internal` call are not too\nexciting: for every animation, the corresponding :meth:`.Animation.finish`\nand :meth:`.Animation.clean_up_from_scene` methods are called.\n\n.. NOTE::\n\n  Note that as part of :meth:`.Animation.finish`, the :meth:`.Animation.interpolate`\n  method is called with an argument of 1.0 -- you might have noticed already that\n  the last frame of an animation can sometimes be a bit off or incomplete.\n  This is by current design! The last frame rendered in the render loop (and displayed\n  for a duration of ``1 / frame_rate`` seconds in the rendered video) corresponds to\n  the state of the animation ``1 / frame_rate`` seconds before it ends. To display\n  the final frame as well in the video, we would need to append another ``1 / frame_rate``\n  seconds to the video -- which would then mean that a 1 second rendered Manim video\n  would be slightly longer than 1 second. We decided against this at some point.\n\nIn the end, the time progression is closed (which completes the displayed progress bar)\nin the terminal. With the closing of the time progression, the\n:meth:`.Scene.play_internal` call is completed, and we return to the renderer,\nwhich now orders the :class:`.SceneFileWriter` to close the output container that has\nbeen opened for this animation: a partial movie file is written.\n\nThis pretty much concludes the walkthrough of a :class:`.Scene.play` call,\nand actually there is not too much more to say for our toy example either: at\nthis point, a partial movie file that represents playing the\n:class:`.ReplacementTransform` has been written. The initialization of\nthe :class:`.Dot` happens analogous to the initialization of ``blue_circle``,\nwhich has been discussed above. The :meth:`.Mobject.add_updater` call literally\njust attaches a function to the ``updaters`` attribute of the ``small_dot``. And\nthe remaining :meth:`.Scene.play` and :meth:`.Scene.wait` calls follow the\nexact same procedure as discussed in the render loop section above; each such call\nproduces a corresponding partial movie file.\n\nOnce the :meth:`.Scene.construct` method has been fully processed (and thus all\nof the corresponding partial movie files have been written), the\nscene calls its cleanup method :meth:`.Scene.tear_down`, and then\nasks its renderer to finish the scene. The renderer, in turn, asks\nits scene file writer to wrap things up by calling :meth:`.SceneFileWriter.finish`,\nwhich triggers the combination of the partial movie files into the final product.\n\nAnd there you go! This is a more or less detailed description of how Manim works\nunder the hood. While we did not discuss every single line of code in detail\nin this walkthrough, it should still give you a fairly good idea of how the general\nstructural design of the library and at least the Cairo rendering flow in particular\nlooks like.\n"
  },
  {
    "path": "docs/source/guides/index.rst",
    "content": "Thematic Guides\n===============\n\n.. toctree::\n   :caption: Table of Contents\n   :maxdepth: 2\n   :glob:\n\n   configuration\n   deep_dive\n   using_text\n   add_voiceovers\n"
  },
  {
    "path": "docs/source/guides/using_text.rst",
    "content": "###########################\nRendering Text and Formulas\n###########################\n\nThere are two different ways by which you can render **Text** in videos:\n\n1. Using Pango (:mod:`~.text_mobject`)\n2. Using LaTeX (:mod:`~.tex_mobject`)\n\nIf you want to render simple text, you should use either :class:`~.Text` or\n:class:`~.MarkupText`, or one of its derivatives like :class:`~.Paragraph`.\nSee :ref:`using-text-objects` for more information.\n\nLaTeX should be used when you need mathematical typesetting. See\n:ref:`rendering-with-latex` for more information.\n\n.. _using-text-objects:\n\nText Without LaTeX\n******************\n\nThe simplest way to add text to your animations is to use the :class:`~.Text`\nclass. It uses the `Pango library`_ to render text. With Pango, you can also\nrender non-English alphabets like 你好 or  こんにちは or 안녕하세요 or\nمرحبا بالعالم.\n\nHere is a simple *Hello World* animation.\n\n.. manim:: HelloWorld\n    :save_last_frame:\n    :ref_classes: Text\n\n    class HelloWorld(Scene):\n        def construct(self):\n            text = Text(\"Hello world\", font_size=144)\n            self.add(text)\n\nYou can also use :class:`~.MarkupText` which allows the use of PangoMarkup\n(see the documentation of :class:`~.MarkupText` for details) to render text.\nFor example:\n\n.. manim:: SingleLineColor\n    :save_last_frame:\n    :ref_classes: MarkupText\n\n    class SingleLineColor(Scene):\n        def construct(self):\n            text = MarkupText(\n                f'all in red <span fgcolor=\"{YELLOW}\">except this</span>', color=RED\n            )\n            self.add(text)\n\n.. _Pango library: https://pango.org\n\nWorking with :class:`~.Text`\n============================\n\nThis section explains the properties of :class:`~.Text` and how can it be used\nin your animations.\n\nUsing Fonts\n-----------\n\nYou can set a different font using :attr:`~.Text.font`.\n\n.. note::\n\n    The font used must be installed in your system, and Pango should know\n    about it. You can get a list of fonts using :func:`manimpango.list_fonts`.\n\n    >>> import manimpango\n    >>> manimpango.list_fonts()\n    [...]\n\n\n.. manim:: FontsExample\n    :save_last_frame:\n\n    class FontsExample(Scene):\n        def construct(self):\n            ft = Text(\"Noto Sans\", font=\"Noto Sans\")\n            self.add(ft)\n\nSetting Slant and Weight\n------------------------\nSlant is the style of the Text, and it can be ``NORMAL`` (the default),\n``ITALIC`` or ``OBLIQUE``. Usually, for many fonts both ``ITALIC`` and\n``OBLIQUE`` look similar, but ``ITALIC`` uses **Roman Style**, whereas\n``OBLIQUE`` uses **Italic Style**.\n\nWeight specifies the boldness of a font. You can see a list of weights in\n:class:`manimpango.Weight`.\n\n.. manim:: SlantsExample\n    :save_last_frame:\n\n    class SlantsExample(Scene):\n        def construct(self):\n            a = Text(\"Italic\", slant=ITALIC)\n            self.add(a)\n\n.. manim:: DifferentWeight\n    :save_last_frame:\n\n    class DifferentWeight(Scene):\n        def construct(self):\n            import manimpango\n\n            g = VGroup()\n            weight_list = dict(\n                sorted(\n                    {\n                        weight: manimpango.Weight(weight).value\n                        for weight in manimpango.Weight\n                    }.items(),\n                    key=lambda x: x[1],\n                )\n            )\n            for weight in weight_list:\n                g += Text(weight.name, weight=weight.name, font=\"Open Sans\")\n            self.add(g.arrange(DOWN).scale(0.5))\n\n.. _using-colors:\n\nUsing Colors\n------------\n\nYou can set the color of the text using :attr:`~.Text.color`:\n\n.. manim:: SimpleColor\n    :save_last_frame:\n\n    class SimpleColor(Scene):\n        def construct(self):\n            col = Text(\"RED COLOR\", color=RED)\n            self.add(col)\n\nYou can use utilities like :attr:`~.Text.t2c` for coloring specific characters.\nThis may be problematic if your text contains ligatures\nas explained in :ref:`iterating-text`.\n\n:attr:`~Text.t2c` accepts two types of dictionaries,\n\n* The keys can contain indices like ``[2:-1]`` or ``[4:8]``,\n  this works similar to how `slicing <https://realpython.com/python-strings/#string-slicing>`_\n  works in Python. The values should be the color of the Text from :class:`~.Color`.\n\n\n* The keys contain words or characters which should be colored separately\n  and the values should be the color from :class:`~.Color`:\n\n.. manim:: Textt2cExample\n    :save_last_frame:\n\n    class Textt2cExample(Scene):\n        def construct(self):\n            t2cindices = Text('Hello', t2c={'[1:-1]': BLUE}).move_to(LEFT)\n            t2cwords = Text('World',t2c={'rl':RED}).next_to(t2cindices, RIGHT)\n            self.add(t2cindices, t2cwords)\n\nIf you want to avoid problems when using colors (due to ligatures), consider using\n:class:`MarkupText`.\n\n\nUsing Gradients\n---------------\n\nYou can add a gradient using :attr:`~.Text.gradient`. The value must\nbe an iterable of any length:\n\n.. manim:: GradientExample\n    :save_last_frame:\n\n    class GradientExample(Scene):\n        def construct(self):\n            t = Text(\"Hello\", gradient=(RED, BLUE, GREEN), font_size=96)\n            self.add(t)\n\nYou can also use :attr:`~.Text.t2g` for gradients with specific\ncharacters of the text. It shares a similar syntax to :ref:`the\ninterface for colors <using-colors>`:\n\n.. manim:: t2gExample\n    :save_last_frame:\n\n    class t2gExample(Scene):\n        def construct(self):\n            t2gindices = Text(\n                'Hello',\n                t2g={\n                    '[1:-1]': (RED,GREEN),\n                },\n            ).move_to(LEFT)\n            t2gwords = Text(\n                'World',\n                t2g={\n                    'World':(RED,BLUE),\n                },\n            ).next_to(t2gindices, RIGHT)\n            self.add(t2gindices, t2gwords)\n\nSetting Line Spacing\n--------------------\n\nYou can set the line spacing using :attr:`~.Text.line_spacing`:\n\n.. manim:: LineSpacing\n    :save_last_frame:\n\n    class LineSpacing(Scene):\n        def construct(self):\n            a = Text(\"Hello\\nWorld\", line_spacing=1)\n            b = Text(\"Hello\\nWorld\", line_spacing=4)\n            self.add(Group(a,b).arrange(LEFT, buff=5))\n\n\n.. _disable-ligatures:\n\nDisabling Ligatures\n-------------------\n\nBy disabling ligatures you would get a one-to-one mapping between characters and\nsubmobjects. This fixes the issues with coloring text.\n\n\n.. warning::\n\n    Be aware that using this method with text that heavily depends on\n    ligatures (Arabic text) may yield unexpected results.\n\nYou can disable ligatures by passing ``disable_ligatures`` to\n:class:`Text`. For example:\n\n.. manim:: DisableLigature\n    :save_last_frame:\n\n    class DisableLigature(Scene):\n        def construct(self):\n            li = Text(\"fl ligature\",font_size=96)\n            nli = Text(\"fl ligature\", disable_ligatures=True, font_size=96)\n            self.add(Group(li, nli).arrange(DOWN, buff=.8))\n\n.. _iterating-text:\n\nIterating :class:`~.Text`\n-------------------------\n\nText objects behave like :class:`VGroups <.VGroup>`. Therefore, you can slice and index\nthe text.\n\nFor example, you can set each letter to different color by iterating it.\n\n.. manim:: IterateColor\n    :save_last_frame:\n\n    class IterateColor(Scene):\n        def construct(self):\n            text = Text(\"Colors\", font_size=96)\n            for letter in text:\n                letter.set_color(random_bright_color())\n            self.add(text)\n\n.. warning::\n\n    Please note that `Ligature`_ can cause problems here. If you need a\n    one-to-one mapping of characters to submobjects you should pass\n    the ``disable_ligatures`` parameter to :class:`~.Text`.\n    See :ref:`disable-ligatures`.\n\n.. _Ligature: https://en.wikipedia.org/wiki/Ligature_(writing)\n\nWorking with :class:`~.MarkupText`\n==================================\n\nMarkupText is similar to :class:`~.Text`, the only difference between them is\nthat this accepts and processes PangoMarkup (which is similar to\nhtml), instead of just rendering plain text.\n\nConsult the documentation of :class:`~.MarkupText` for more details\nand further references about PangoMarkup.\n\n.. manim:: MarkupTest\n    :save_last_frame:\n\n    class MarkupTest(Scene):\n        def construct(self):\n            text = MarkupText(\n                f'<span underline=\"double\" underline_color=\"green\">double green underline</span> in red text<span fgcolor=\"{YELLOW}\"> except this</span>',\n                color=RED,\n                font_size=34\n            )\n            self.add(text)\n\n.. _rendering-with-latex:\n\nText With LaTeX\n***************\n\nJust as you can use :class:`~.Text` to add text to your videos, you can\nuse :class:`~.Tex` to insert LaTeX.\n\nFor example,\n\n.. manim:: HelloLaTeX\n    :save_last_frame:\n\n    class HelloLaTeX(Scene):\n        def construct(self):\n            tex = Tex(r\"\\LaTeX\", font_size=144)\n            self.add(tex)\n\n.. note::\n\n    Note that we are using a raw string (``r'...'``) instead of a regular string (``'...'``).\n    This is because TeX code uses a lot of special characters - like ``\\`` for example - that\n    have special meaning within a regular python string. An alternative would have been to\n    write ``\\\\`` to escape the backslash: ``Tex('\\\\LaTeX')``.\n\nWorking with :class:`~.MathTex`\n===============================\n\nEverything passed to :class:`~.MathTex` is in math mode by default. To be more precise,\n:class:`~.MathTex` is processed within an ``align*`` environment. You can achieve a\nsimilar effect with :class:`~.Tex` by enclosing your formula with ``$`` symbols:\n``$\\xrightarrow{x^6y^8}$``:\n\n.. manim:: MathTeXDemo\n    :save_last_frame:\n\n    class MathTeXDemo(Scene):\n        def construct(self):\n            rtarrow0 = MathTex(r\"\\xrightarrow{x^6y^8}\", font_size=96)\n            rtarrow1 = Tex(r\"$\\xrightarrow{x^6y^8}$\", font_size=96)\n\n            self.add(VGroup(rtarrow0, rtarrow1).arrange(DOWN))\n\n\nLaTeX commands and keyword arguments\n====================================\n\nWe can use any standard LaTeX commands in the AMS maths packages. Such\nas the ``mathtt`` math-text type or the ``looparrowright`` arrow.\n\n.. manim:: AMSLaTeX\n    :save_last_frame:\n\n    class AMSLaTeX(Scene):\n        def construct(self):\n            tex = Tex(r'$\\mathtt{H} \\looparrowright$ \\LaTeX', font_size=144)\n            self.add(tex)\n\nOn the Manim side, the :class:`~.Tex` class also accepts attributes to\nchange the appearance of the output. This is very similar to the\n:class:`~.Text` class. For example, the ``color`` keyword changes the\ncolor of the TeX mobject.\n\n.. manim:: LaTeXAttributes\n    :save_last_frame:\n\n    class LaTeXAttributes(Scene):\n        def construct(self):\n            tex = Tex(r'Hello \\LaTeX', color=BLUE, font_size=144)\n            self.add(tex)\n\nExtra LaTeX Packages\n====================\n\nSome commands require special packages to be loaded into the TeX template.\nFor example, to use the ``mathscr`` script, we need to add the ``mathrsfs``\npackage. Since this package isn't loaded into Manim's tex template by default,\nwe have to add it manually.\n\n.. manim:: AddPackageLatex\n    :save_last_frame:\n\n    class AddPackageLatex(Scene):\n        def construct(self):\n            myTemplate = TexTemplate()\n            myTemplate.add_to_preamble(r\"\\usepackage{mathrsfs}\")\n            tex = Tex(\n                r\"$\\mathscr{H} \\rightarrow \\mathbb{H}$\",\n                tex_template=myTemplate,\n                font_size=144,\n            )\n            self.add(tex)\n\nSubstrings and parts\n====================\n\nThe TeX mobject can accept multiple strings as arguments. Afterwards you can\nrefer to the individual parts either by their index (like ``tex[1]``), or by\nusing :func:`~.set_color_by_tex`, which matches the argument exactly against\nthe strings passed to the constructor. In this example, we color the\n``\\bigstar`` part:\n\n.. manim:: LaTeXSubstrings\n    :save_last_frame:\n\n    class LaTeXSubstrings(Scene):\n        def construct(self):\n            tex = Tex('Hello', r'$\\bigstar$', r'\\LaTeX', font_size=144)\n            tex.set_color_by_tex(r'$\\bigstar$', RED)\n            self.add(tex)\n\nBecause :func:`~.set_color_by_tex` requires an exact match, it cannot directly\ntarget a token inside a string that was passed as a single argument. To color\nevery ``x`` in a formula, use ``substrings_to_isolate`` to split the string at\neach occurrence first:\n\n.. manim:: CorrectLaTeXSubstringColoring\n    :save_last_frame:\n\n    class CorrectLaTeXSubstringColoring(Scene):\n        def construct(self):\n            equation = MathTex(\n                r\"e^{x} = x^0 + x^1 + \\frac{1}{2} x^2 + \\frac{1}{6} x^3 + \\cdots + \\frac{1}{n!} x^n + \\cdots\",\n                substrings_to_isolate=\"x\"\n            )\n            equation.set_color_by_tex(\"x\", YELLOW)\n            self.add(equation)\n\nEach isolated occurrence of ``x`` becomes its own sub-mobject that\n:meth:`~.set_color_by_tex` can match exactly.\nIf one of the ``substrings_to_isolate`` is in a sub or superscript, it needs\nto be enclosed by curly brackets.\n\nNote that Manim also supports a custom syntax that allows splitting\na TeX string into substrings easily: simply enclose parts of your formula\nthat you want to isolate with double braces. In the string\n``MathTex(r\"{{ a^2 }} + {{ b^2 }} = {{ c^2 }}\")``, the rendered mobject\nwill consist of the substrings ``a^2``, ``+``, ``b^2``, ``=``, and ``c^2``.\nThis makes transformations between similar text fragments easy\nto write using :class:`~.TransformMatchingTex`.\n\nFor Manim to recognise a ``{{`` as a group opener, it must appear either\nat the very start of the string or be immediately preceded by a whitespace\ncharacter.  This means that ``{{`` embedded directly after non-whitespace\nLaTeX — such as ``\\frac{{{n}}}{k}`` or ``a^{{2}}`` — is left untouched,\nwhich prevents accidental splitting of ordinary nested-brace expressions.\nTo stop a leading ``{{`` from being treated as a group opener, insert a\nspace between the two braces: ``{{ ... }}`` → ``{ { ... } }``.\n\nUsing ``index_labels`` to work with complicated strings\n=======================================================\n\nYou might sometimes be working with a very complicated :class:`~.MathTex` mobject\nthat makes it difficult to work with its individual components. This is\nwhere the debugging function :func:`.index_labels` is very useful.\n\nThe method shows the index of a mobject's submobjects, allowing you\nto easily find the components of the mobject you would like to change.\n\n.. manim:: IndexLabelsMathTex\n    :save_last_frame:\n\n    class IndexLabelsMathTex(Scene):\n        def construct(self):\n            text = MathTex(r\"\\binom{2n}{n+2}\", font_size=96)\n\n            # index the first (and only) term of the MathTex mob\n            self.add(index_labels(text[0]))\n\n            text[0][1:3].set_color(YELLOW)\n            text[0][3:6].set_color(RED)\n            self.add(text)\n\n\nLaTeX Maths Fonts - The Template Library\n========================================\n\nChanging fonts in LaTeX when typesetting mathematical formulae is\ntrickier than regular text. It requires changing the template that is used\nto compile the TeX. Manim comes with a collection of :class:`~.TexFontTemplates`\nready for you to use. These templates will all work in math mode:\n\n.. manim:: LaTeXMathFonts\n    :save_last_frame:\n\n    class LaTeXMathFonts(Scene):\n        def construct(self):\n            tex = Tex(\n                r\"$x^2 + y^2 = z^2$\",\n                tex_template=TexFontTemplates.french_cursive,\n                font_size=144,\n            )\n            self.add(tex)\n\nManim also has a :class:`~.TexTemplateLibrary` containing the TeX\ntemplates used by 3Blue1Brown. One example is the ctex template,\nused for typesetting Chinese script. For this to work, the ctex LaTeX package\nmust be installed on your system. Furthermore, if you are only\ntypesetting Text, you probably do not need :class:`~.Tex` at all, and\nshould use :class:`~.Text` instead.\n\n.. manim:: LaTeXTemplateLibrary\n    :save_last_frame:\n\n    class LaTeXTemplateLibrary(Scene):\n        def construct(self):\n            tex = Tex('Hello 你好 \\\\LaTeX', tex_template=TexTemplateLibrary.ctex, font_size=144)\n            self.add(tex)\n\n\nAligning formulae\n=================\n\n:class:`~.MathTex` mobject is typeset in the LaTeX  ``align*``\nenvironment. This means you can use the ``&`` alignment character\nwhen typesetting multiline formulae:\n\n.. manim:: LaTeXAlignEnvironment\n    :save_last_frame:\n\n    class LaTeXAlignEnvironment(Scene):\n        def construct(self):\n            tex = MathTex(r'f(x) &= 3 + 2 + 1\\\\ &= 5 + 1 \\\\ &= 6', font_size=96)\n            self.add(tex)\n"
  },
  {
    "path": "docs/source/index.rst",
    "content": ".. manim documentation master file, created by\n   sphinx-quickstart on Tue Aug  4 13:58:07 2020.\n   You can adapt this file completely to your liking, but it should at least\n   contain the root `toctree` directive.\n\nManim Community Edition\n=======================\n\nAnimating technical concepts is traditionally pretty tedious since it can be\ndifficult to make the animations precise enough to convey them accurately.\nManim relies on Python's simplicity to generate animations programmatically,\nmaking it convenient to specify exactly how each one should run. Take a look\nat the :doc:`Example Gallery <../examples>` for some inspiration on how to\ncreate beautiful images and videos with Manim.\n\nFirst Steps\n-----------\n\nAre you new to Manim and are looking for where to get started? Then you are\nin the right place!\n\n.. note::\n\n   Please be aware that there are different, incompatible versions of Manim available.\n   This version, the Community Edition of Manim (`ManimCE <https://github.com/ManimCommunity/manim>`_),\n   is a separate project maintained by the community, but it was forked from `3b1b/manim <https://github.com/3b1b/manim>`_,\n   the original Manim created and open-sourced by Grant Sanderson, creator of `3Blue1Brown <https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw>`_ educational math videos.\n   Check our :ref:`installation FAQ <different-versions>`\n   to learn more!\n\n- The :doc:`Installation <installation>` section has the latest and\n  up-to-date installation instructions for Windows, macOS, and Linux.\n  You can also find information on Manim's docker images and (online)\n  notebook environments there.\n- Want to try the library before installing it? Take a look at our\n  interactive online playground at https://try.manim.community in the form\n  of a Jupyter notebook.\n- In our :doc:`Tutorials <tutorials/index>` section you will find a\n  collection of resources that will teach you how to use Manim. In particular,\n  the :doc:`tutorials/quickstart` tutorial teaches you Manim's basics,\n  and in :doc:`tutorials/building_blocks` the classes used to compose\n  your animations are described in more detail.\n\n\nFinding Help\n------------\n\nAre you struggling with installing or using Manim? Don't worry, we've all been\nthere. Here are some good resources to help you out:\n\n- Perhaps your problem is one that occurs frequently, then chances are it is\n  addressed in our :doc:`collection of FAQs <faq/index>`.\n- If you are looking for information on some specific class, look for it\n  in the :doc:`reference manual <reference>` and/or use the search feature\n  of the documentation.\n- Still no luck? Then you are welcome to ask the community for help, together\n  we usually manage to find a solution for your problem! Consult the\n  :doc:`FAQ page on getting help <faq/help>` for instructions.\n\n\nNavigating the Documentation\n----------------------------\n\nHere are some short summaries for all of the sections in this documentation:\n\n- The :doc:`Example Gallery </examples>` is a collection of examples (rendered videos\n  and images together with the code they were generated from) that show a few different,\n  simple things that you can do with Manim.\n- The :doc:`Installation </installation>` section has information on installing Manim.\n- In :doc:`Tutorials & Guides </tutorials_guides>` you can find learning resources: proper\n  tutorials that guide you through the process of creating a video are in\n  the :doc:`Tutorial </tutorials/index>` section; guides on specific topics are in the\n  :doc:`Guides </guides/index>` section, and the answers to frequently asked questions\n  can be found in the :doc:`FAQ </faq/index>` section.\n- The :doc:`Reference Manual </reference>` contains a comprehensive list of all of Manim's\n  (documented) modules, classes, and functions. If you are somewhat familiar with Manim's\n  module structure, feel free to browse the manual directly. If you are searching for\n  something specific, feel free to use the documentation's search feature in the sidebar.\n  Many classes and methods come with their own illustrated examples too!\n- The :doc:`Plugins </plugins>` page documents how to install, write, and distribute\n  plugins (that is, separate Python packages that extend the feature set of the core library).\n- Changes between versions are documented in our :doc:`Changelog </changelog>`.\n- If you are looking into contributing to the development of Manim, you can find information\n  on how to get involved in our :doc:`Contributing </contributing>` section.\n- And finally, the :doc:`Code of Conduct </conduct>` page has a formal description of\n  the rules you should abide by when interacting within our community.\n\nSharing Your Work\n-----------------\n\nWe'd love to hear from you and see your manimations\n`on Twitter <https://twitter.com/manim_community>`_, `Reddit <https://www.reddit.com/r/manim/>`_,\nor `Discord <https://www.manim.community/discord/>`_. If you're using Manim in a scientific\ncontext, instructions on how to cite a particular release can be found\n`in our README <https://github.com/ManimCommunity/manim/blob/main/README.md>`_.\n\nLicense Information\n-------------------\n\nManim is an open-source library licensed under the **MIT License**, which applies to both the\noriginal and the community editions of the software. This means you are free to use, modify,\nand distribute the code in accordance with the MIT License terms. However, there are some\nadditional points to be aware of:\n\n- **Copyrighted Assets:** Specific assets, such as the \"Pi creatures\" in Grant Sanderson's\n  (3Blue1Brown) videos, are copyrighted and protected. Please avoid using these characters in\n  any derivative works.\n- **Content Creation and Sharing:** Videos and animations created with Manim can be freely\n  shared, and no attribution to Manim is required—although it is much appreciated! You are\n  encouraged to showcase your work online and share it with the Manim community.\n\nIndex\n-----\n\n.. toctree::\n   :maxdepth: 2\n\n   examples\n   installation\n   tutorials_guides\n   reference\n   plugins\n   changelog\n   contributing\n   conduct\n\n.. image:: _static/crowdin-badge.svg\n  :align: center\n  :alt: Localized with Crowdin\n  :target: https://translate.manim.community\n"
  },
  {
    "path": "docs/source/installation/conda.rst",
    "content": "Conda\n=====\n\nRequired Dependencies\n---------------------\n\nThere are several package managers that work with conda packages,\nnamely `conda <https://docs.conda.io/projects/conda/en/latest/user-guide/install/download.html>`__,\n`mamba <https://mamba.readthedocs.io>`__ and `pixi <https://pixi.sh>`__.\n\nAfter installing your package manager, you can create a new environment and install ``manim`` inside by running\n\n\n.. tab-set::\n\n   .. tab-item:: conda / mamba\n\n      .. code-block:: bash\n\n         # if you want to use mamba, just replace conda below with mamba\n         conda create -n my-manim-environment\n         conda activate my-manim-environment\n         conda install -c conda-forge manim\n\n   .. tab-item:: pixi\n\n      .. code-block:: bash\n\n         pixi init\n         pixi add manim\n\n\nSince all dependencies (except LaTeX) are handled by conda, you don't need to worry\nabout needing to install additional dependencies.\n\n\n\nOptional Dependencies\n---------------------\n\nIn order to make use of Manim's interface to LaTeX to, for example, render\nequations, LaTeX has to be installed as well. Note that this is an optional\ndependency: if you don't intend to use LaTeX, you don't have to install it.\n\nRecommendations on how to install LaTeX on different operating systems\ncan be found :doc:`in our local installation guide </installation/uv>`.\n\n\nWorking with Manim\n------------------\n\nAt this point, you should have a working installation of Manim, head\nover to our :doc:`Quickstart Tutorial <../tutorials/quickstart>` to learn\nhow to make your own *Manimations*!\n"
  },
  {
    "path": "docs/source/installation/docker.rst",
    "content": "Docker\n======\n\nThe community maintains a docker image, which can be found\n`on DockerHub <https://hub.docker.com/r/manimcommunity/manim>`__.\nFor our image ``manimcommunity/manim``, there are the following tags:\n\n- ``latest``: the most recent version corresponding\n  to `the main branch <https://github.com/ManimCommunity/manim>`__,\n- ``stable``: the latest released version (according to\n  `the releases page <https://github.com/ManimCommunity/manim/releases>`__),\n- ``vX.Y.Z``: any particular released version (according to\n  `the releases page <https://github.com/ManimCommunity/manim/releases>`__).\n\n.. note::\n\n   When using Manim's CLI within a Docker container, some flags like\n   ``-p`` (preview file) and ``-f`` (show output file in the file browser)\n   are not supported.\n\n.. note::\n\n   The Docker image ships with a minimal TeX Live installation. In particular,\n   ``ctex`` is not installed by default. If your scenes rely on\n   ``TexTemplateLibrary.ctex``, install it in the container via\n   ``tlmgr install ctex``.\n\n\nBasic usage of the Docker container\n-----------------------------------\n\nAssuming that you can access the docker installation on your system\nfrom a terminal (bash / PowerShell) via ``docker``, you can\nrender a scene ``CircleToSquare`` in a file `test_scenes.py`\nwith the following command.\n\n.. code-block:: bash\n\n   docker run --rm -it -v \"/full/path/to/your/directory:/manim\" manimcommunity/manim manim -qm test_scenes.py CircleToSquare\n\n.. tip::\n\n   For Linux users there might be permission problems when letting the\n   user in the container write to the mounted volume.\n   Add ``--user=\"$(id -u):$(id -g)\"`` to the ``docker`` CLI arguments\n   to prevent the creation of output files not belonging to your user.\n\n\nInstead of using the \"throwaway container\" approach outlined\nabove, you can also create a named container that you can\nmodify to your liking. First, run\n\n.. code-block:: sh\n\n   docker run -it --name my-manim-container -v \"/full/path/to/your/directory:/manim\" manimcommunity/manim bash\n\n\nto obtain an interactive shell inside your container allowing you\nto, e.g., install further dependencies (like texlive packages using\n``tlmgr``). Exit the container as soon as you are satisfied. Then,\nbefore using it, start the container by running\n\n.. code-block:: sh\n\n   docker start my-manim-container\n\nwhich starts the container in the background. Then, to render\na scene ``CircleToSquare`` in a file ``test_scenes.py``, run\n\n.. code-block:: sh\n\n   docker exec -it my-manim-container manim -qm test_scenes.py CircleToSquare\n\n\nRunning JupyterLab via Docker\n-----------------------------\n\nAnother alternative to using the Docker image is to spin up a\nlocal JupyterLab instance. To do that, simply run\n\n.. code-block:: sh\n\n   docker run -it -p 8888:8888 manimcommunity/manim jupyter lab --ip=0.0.0.0\n\nand then follow the instructions in the terminal.\n"
  },
  {
    "path": "docs/source/installation/jupyter.rst",
    "content": "Jupyter Notebooks\n=================\n\n\nBinder\n------\n\n`Binder <https://mybinder.readthedocs.io/en/latest/>`__ is an online\nplatform that hosts shareable and customizable computing environments\nin the form of Jupyter notebooks. Manim ships with a built-in ``%%manim``\nJupyter magic command which makes it easy to use in these notebooks.\n\nTo see an example for such an environment, visit our interactive\ntutorial over at https://try.manim.community/.\n\nIt is relatively straightforward to prepare your own notebooks in\na way that allows them to be shared interactively via Binder as well:\n\n#. First, prepare a directory containing one or multiple notebooks\n   which you would like to share in an interactive environment. You\n   can create these notebooks by using Jupyter notebooks with a\n   local installation of Manim, or also by working in our pre-existing\n   `interactive tutorial environment <https://try.manim.community/>`__.\n#. In the same directory containing your notebooks, add a\n   file named ``Dockerfile`` with the following content:\n\n   .. code-block:: dockerfile\n\n      FROM docker.io/manimcommunity/manim:v0.9.0\n\n      COPY --chown=manimuser:manimuser . /manim\n\n   Don't forget to change the version tag ``v0.9.0`` to the version you\n   were working with locally when creating your notebooks.\n#. Make the directory with your worksheets and the ``Dockerfile``\n   available to the public (and in particular: to Binder!). There are\n   `several different options to do so\n   <https://mybinder.readthedocs.io/en/latest/introduction.html#how-can-i-prepare-a-repository-for-binder>`__,\n   within the community we usually work with GitHub\n   repositories or gists.\n#. Once your material is publicly available, visit\n   https://mybinder.org and follow the instructions there to\n   generate an interactive environment for your worksheets.\n\n.. hint::\n\n   The repository containing our `interactive tutorial\n   <https://try.manim.community>`__ can be found at\n   https://github.com/ManimCommunity/jupyter_examples.\n\n\nGoogle Colaboratory\n-------------------\n\nIt is also possible to install Manim in a\n`Google Colaboratory <https://colab.research.google.com/>`__ environment.\nIn contrast to Binder, where you can customize and prepare the environment\nbeforehand (such that Manim is already installed and ready to be used), you\nwill have to take care of that every time you start\na new notebook in Google Colab. Fortunately, this\nis not particularly difficult.\n\nAfter creating a new notebook, paste the following code block in a cell,\nthen execute it.\n\n.. code-block::\n\n   !sudo apt update\n   !sudo apt install libcairo2-dev \\\n       texlive texlive-latex-extra texlive-fonts-extra \\\n       texlive-latex-recommended texlive-science \\\n       tipa libpango1.0-dev\n   !pip install manim\n   !pip install IPython==8.21.0\n\nYou should start to see Colab installing all the dependencies specified\nin these commands. After the execution has completed, you will be prompted\nto restart the runtime. Click the \"restart runtime\" button at the bottom of\nthe cell output. You are now ready to use Manim in Colab!\n\nTo check that everything works as expected, first import Manim by running\n\n.. code-block::\n\n   from manim import *\n\nin a new code cell. Then create another cell containing the\nfollowing code::\n\n   %%manim -qm -v WARNING SquareToCircle\n\n   class SquareToCircle(Scene):\n      def construct(self):\n         square = Square()\n         circle = Circle()\n         circle.set_fill(PINK, opacity=0.5)\n         self.play(Create(square))\n         self.play(Transform(square, circle))\n         self.wait()\n\nUpon running this cell, a short animation transforming a square\ninto a circle should be rendered and displayed.\n"
  },
  {
    "path": "docs/source/installation/uv.md",
    "content": "# Installing Manim locally\n\nThe standard way of installing Manim is by using\nPython's package manager `pip` to install the latest\nrelease from [PyPI](https://pypi.org/project/manim/).\n\nTo make it easier for you to follow best practices when it\ncomes to setting up a Python project for your Manim animations,\nwe strongly recommend using a tool for managing Python environments\nand dependencies. In particular,\n[we strongly recommend using `uv`](https://docs.astral.sh/uv/#getting-started).\n\nFor the two main ways of installing Manim described below, we assume\nthat `uv` is available; we think it is particularly helpful if you are\nnew to Python or programming in general. It is not a hard requirement\nwhatsoever; if you know what you are doing you can just use `pip` to\ninstall Manim directly.\n\n:::::{admonition} Installing the Python management tool `uv`\n:class: seealso\n\nOne way to install `uv` is via the dedicated console installer supporting\nall large operating systems. Simply paste the following snippet into\nyour terminal / PowerShell -- or\n[consult `uv`'s documentation](https://docs.astral.sh/uv/#getting-started)\nfor alternative ways to install the tool.\n\n::::{tab-set}\n:::{tab-item} MacOS and Linux\n```bash\ncurl -LsSf https://astral.sh/uv/install.sh | sh\n```\n:::\n:::{tab-item} Windows\n```powershell\npowershell -ExecutionPolicy ByPass -c \"irm https://astral.sh/uv/install.ps1 | iex\"\n```\n:::\n::::\n\n:::::\n\nOf course, if you know what you are doing and prefer to setup a virtual\nenvironment yourself, feel free to do so!\n\n:::{important}\nIf you run into issues when following our instructions below, do\nnot worry: check our [installation FAQs](<project:/faq/installation.md>) to\nsee whether the problem is already addressed there -- and otherwise go and\ncheck [how to contact our community](<project:/faq/help.md>) to get help.\n:::\n\n\n\n## Installation\n\n### Step 1: Installing Python\n\nWe first need to check that an appropriate version of Python is available\non your machine. Open a terminal to run\n```bash\nuv python install\n```\nto install the latest version of Python. If this is successful, continue\nto the next step.\n\n(installation-optional-latex)=\n### Step 2 (optional): Installing LaTeX\n\n[LaTeX](https://en.wikibooks.org/wiki/LaTeX/Mathematics) is a very well-known\nand widely used typesetting system allowing you to write formulas like\n\n\\begin{equation*}\n\\frac{1}{2\\pi i} \\oint_{\\gamma} \\frac{f(z)}{(z - z_0)^{n+1}}~dz\n= \\frac{f^{(n)}(z_0)}{n!}.\n\\end{equation*}\n\nIf rendering plain text is sufficient for your needs and you don't want\nto render any typeset formulas, you can technically skip this step. Otherwise\nselect your operating system from the tab list below and follow the instructions.\n\n:::::{tab-set}\n\n::::{tab-item} Windows\nFor Windows we recommend installing LaTeX via the\n[MiKTeX distribution](https://miktex.org). Simply grab\nthe Windows installer available from their download page,\n<https://miktex.org/download> and run it.\n::::\n\n::::{tab-item} MacOS\nIf you are running MacOS, we recommend installing the\n[MacTeX distribution](https://www.tug.org/mactex/). The latest\navailable PKG file can be downloaded from\n<https://www.tug.org/mactex/mactex-download.html>.\nGet it and follow the standard installation procedure.\n::::\n\n::::{tab-item} Linux\nGiven the large number of Linux distributions with different ways\nof installing packages, we cannot give detailed instructions for\nall package managers.\n\nIn general we recommend to install a *TeX Live* distribution\n(<https://www.tug.org/texlive/>). For most Linux distributions,\nTeX Live has already been packaged such that it can be installed\neasily with your system package manager. Search the internet and\nyour usual OS resources for detailed instructions.\n\nFor example, on Debian-based systems with the package manager `apt`,\na full TeX Live distribution can be installed by running\n```bash\nsudo apt install texlive-full\n```\nFor Fedora (managed via `dnf`), the corresponding command is\n```bash\nsudo dnf install texlive-scheme-full\n```\nAs soon as LaTeX is installed, continue with actually installing Manim\nitself.\n\n::::\n\n:::::\n\n:::{dropdown} I know what I am doing and I would like to setup a minimal LaTeX installation\nYou are welcome to use a smaller, more customizable LaTeX distribution like\n[TinyTeX](https://yihui.org/tinytex/). Manim overall requires the following\nLaTeX packages to be installed in your distribution:\n```text\namsmath babel-english cbfonts-fd cm-super count1to ctex doublestroke dvisvgm everysel\nfontspec frcursive fundus-calligra gnu-freefont jknapltx latex-bin\nmathastext microtype multitoc physics preview prelim2e ragged2e relsize rsfs\nsetspace standalone tipa wasy wasysym xcolor xetex xkeyval\n```\n:::\n\n### Step 3: Installing Manim\n\nThese steps again differ slightly between different operating systems. Make\nsure you select the correct one from the tab list below, then follow\nthe instructions below.\n\n::::::{tab-set}\n\n:::::{tab-item} Windows\nThe following commands will\n\n- create a new directory for a Python project,\n- and add Manim as a dependency, which installs it into the corresponding\n  local Python environment.\n\nThe name for the Python project is *manimations*, which you can change\nto anything you like.\n\n```bash\nuv init manimations\ncd manimations\nuv add manim\n```\n\nManim is now installed in your local project environment!\n\n:::::\n\n:::::{tab-item} MacOS\nBefore we can install Manim, we need to make sure that the system utilities\n`cairo` and `pkg-config` are present. They are needed for the [`pycairo` Python\npackage](https://pycairo.readthedocs.io/en/latest/), a dependency of Manim.\n\nThe easiest way of installing these utilities is by using [Homebrew](https://brew.sh/),\na fairly popular 3rd party package manager for MacOS. Check whether Homebrew is\nalready installed by running\n\n```bash\nbrew --version\n```\n\nwhich will report something along the lines of `Homebrew 4.4.15-54-...`\nif it is installed, and a message `command not found: brew` otherwise. In this\ncase, use the shell installer [as instructed on Homebrew's website](https://brew.sh/),\nor get a `.pkg`-installer from\n[their GitHub release page](https://github.com/Homebrew/brew/releases). Make sure to\nfollow the instructions of the installer carefully, especially when prompted to\nmodify your `.zprofile` to add Homebrew to your system's PATH.\n\nWith Homebrew available, the required utilities can be installed by running\n\n```bash\nbrew install cairo pkg-config\n```\n\nWith all of this preparation out of the way, now it is time to actually install\nManim itself! The following commands will\n\n- create a new directory for a Python project,\n- and add Manim as a dependency, which installs it into the corresponding\n  local Python environment.\n\nThe name for the Python project is *manimations*, which you can change\nto anything you like.\n\n```bash\nuv init manimations\ncd manimations\nuv add manim\n```\n\nManim is now installed in your local project environment!\n\n:::::\n\n:::::{tab-item} Linux\nPractically, the instructions given in the *Windows* tab\nalso apply for Linux -- however, some additional dependencies are\nrequired as Linux users need to build\n[ManimPango](https://github.com/ManimCommunity/ManimPango)\n(and potentially [pycairo](https://pycairo.readthedocs.io/en/latest/))\nfrom source. More specifically, this includes:\n\n- A C compiler,\n- Python's development headers,\n- the `pkg-config` tool,\n- Pango and its development headers,\n- and Cairo and its development headers.\n\nInstructions for popular systems / package managers are given below.\n\n::::{tab-set}\n\n:::{tab-item} Debian-based / apt\n```bash\nsudo apt update\nsudo apt install build-essential python3-dev libcairo2-dev libpango1.0-dev\n```\n:::\n\n:::{tab-item} Fedora / dnf\n```bash\nsudo dnf install python3-devel pkg-config cairo-devel pango-devel\n```\n:::\n\n:::{tab-item} Arch Linux / pacman\n```bash\nsudo pacman -Syu base-devel cairo pango\n```\n:::\n\n::::\n\nAs soon as the required dependencies are installed, you can create\na Python project (feel free to change the name *manimations* used below\nto some other name) with a local environment containing Manim by running\n```bash\nuv init manimations\ncd manimations\nuv add manim\n```\n\n:::::\n\n::::::\n\nTo verify that your local Python project is setup correctly\nand that Manim is available, simply run\n```bash\nuv run manim checkhealth\n```\n\nAt this point, you can also open your project folder with the\nIDE of your choice. All modern Python IDEs (for example VS Code\nwith the Python extension, or PyCharm) should automatically detect\nthe local environment created by `uv` such that if you put\n```py\nimport manim\n```\ninto a new file `my-first-animation.py`, the import is resolved\ncorrectly and autocompletion is available.\n\n*Happy Manimating!*\n\n\n:::{dropdown} Alternative: Installing Manim as a global `uv`-managed tool\nIf you have Manim projects in many different directories and you do not\nwant to setup a local project environment for each of them, you could\nalso install Manim as a `uv`-managed tool.\n\nSee [`uv`'s documentation for more information](https://docs.astral.sh/uv/concepts/tools/)\non their tool mechanism.\n\nTo install Manim as a global `uv` tool, simply run\n```bash\nuv tool install manim\n```\nafter which the `manim` executable will be available on your\nglobal system path, without the need to activate any virtual\nenvironment or prefixing your commands with `uv run`.\n\nNote that when using this approach, setting up your code editor\nto properly resolve `import manim` requires additional work, as\nthe global tool environment is not automatically detected: the\nbase path of all tool environments can be determined by running\n```\nuv tool dir\n```\nwhich should now contain a directory `manim` in which the appropriate\nvirtual environment is located. Set the Python interpreter of your IDE\nto this environment to make imports properly resolve themselves.\n:::\n\n:::{dropdown} Installing Manim for a different version of Python\nIn case you would like to use a different version of Python\n(for example, due to compatibility issues with other packages),\nthen `uv` allows you to do so in a fairly straightforward way.\n\nWhen initializing the local Python project, simply pass the Python\nversion you want to use as an argument to the `init` command:\n```\nuv init --python 3.12 manimations\ncd manimations\nuv add manim\n```\nTo change the version for an existing package, you will need to\nedit the `pyproject.toml` file. If you are downgrading the python version, the\n`requires-python` entry needs to be updated such that your chosen\nversion satisfies the requirement. Change the line to, for example\n`requires-python = \">=3.12\"`. After that, run `uv python pin 3.12`\nto pin the python version to `3.12`. Finally, run `uv sync`, and your\nenvironment is updated!\n:::\n\n:::{dropdown} Installing the latest development version\nIf you want to install the latest (potentially unstable!)\ndevelopment version of Manim from our source repository\n[on GitHub](https://github.com/ManimCommunity/manim), then\nsimply run\n```bash\nuv add git+https://github.com/ManimCommunity/manim.git@main\n```\n:::\n"
  },
  {
    "path": "docs/source/installation.rst",
    "content": "Installation\n============\n\nDepending on your use case, different installation options are recommended:\nif you just want to play around with Manim for a bit, interactive in-browser\nnotebooks are a really simple way of exploring the library as they\nrequire no local installation. Head over to\nhttps://try.manim.community to give our interactive tutorial a try.\n\nOtherwise, if you intend to use Manim to work on an animation project,\nwe recommend installing the library locally (preferably to some isolated\nvirtual Python environment, or a conda-like environment, or via Docker).\n\n.. warning::\n\n   Note that there are several different versions of Manim. The\n   instructions on this website are **only** for the *community edition*.\n   Find out more about the :ref:`differences between Manim\n   versions <different-versions>` if you are unsure which\n   version you should install.\n\n#. :ref:`(Recommended) Installing Manim via Python's package manager pip\n   <local-installation>`\n#. :ref:`Installing Manim to a conda environment <conda-installation>`\n#. :ref:`Using Manim via Docker <docker-installation>`\n#. :ref:`Interactive Jupyter notebooks via Binder / Google Colab\n   <interactive-online>`\n\n\n.. _local-installation:\n\nInstalling Manim locally via pip\n********************************\n\nThe recommended way of installing Manim is by using Python's package manager\npip. If you already have a Python environment set up, you can simply run\n``pip install manim`` to install the library.\n\nOur :doc:`local installation guide <installation/uv>` provides more detailed\ninstructions, including best practices for setting up a suitable local environment.\n\n.. toctree::\n   :hidden:\n\n   installation/uv\n\n.. _conda-installation:\n\nInstalling Manim via Conda and related environment managers\n***********************************************************\n\nConda is a package manager for Python that allows creating environments\nwhere all your dependencies are stored. Like this, you don't clutter up your PC with\nunwanted libraries and you can just delete the environment when you don't need it anymore.\nIt is a good way to install manim since all dependencies like ``pycairo``, etc. come with it.\nAlso, the installation steps are the same, no matter if you are\non Windows, Linux, Intel Macs or on Apple Silicon.\n\n.. NOTE::\n\n   There are various popular alternatives to Conda like\n   `mamba <https://mamba.readthedocs.io/en/latest/>`__ /\n   `micromamba <https://mamba.readthedocs.io/en/latest/user_guide/micromamba.html>`__,\n   or `pixi <https://pixi.sh>`__.\n   They all can be used to setup a suitable, isolated environment\n   for your Manim projects.\n\nThe following pages show how to install Manim in a conda environment:\n\n.. toctree::\n   :maxdepth: 2\n\n   installation/conda\n\n\n.. _docker-installation:\n\nUsing Manim via Docker\n**********************\n\n`Docker <https://www.docker.com>`__ is a virtualization tool that\nallows the distribution of encapsulated software environments (containers).\n\nThe following pages contain more information about the docker image\nmaintained by the community, ``manimcommunity/manim``:\n\n.. toctree::\n\n   installation/docker\n\n\n.. _interactive-online:\n\nInteractive Jupyter notebooks for your browser\n**********************************************\n\nManim ships with a built-in ``%%manim`` IPython magic command\ndesigned for the use within `Jupyter notebooks <https://jupyter.org>`__.\nOur interactive tutorial over at https://try.manim.community illustrates\nhow Manim can be used from within a Jupyter notebook.\n\nThe following pages explain how you can setup interactive environments\nlike that yourself:\n\n.. toctree::\n\n   installation/jupyter\n\n.. _editor-addons:\n\nEditors\n********\n\nIf you're using Visual Studio Code you can install an extension called\n*Manim Sideview* which provides automated rendering and an integrated preview\nof the animation inside the editor. The extension can be installed through the\n`marketplace of VS Code <https://marketplace.visualstudio.com/items?itemName=Rickaym.manim-sideview>`__.\n\n.. caution::\n\n   This extension is not officially maintained by the Manim Community.\n   If you run into issues, please report them to the extension's author.\n\n\nInstallation for developers\n***************************\n\nIn order to change code in the library, it is recommended to\ninstall Manim in a different way. Please follow the instructions\nin our :doc:`contribution guide <contributing>` if you are\ninterested in that.\n"
  },
  {
    "path": "docs/source/plugins.rst",
    "content": ".. _plugins:\n\n=======\nPlugins\n=======\n\nPlugins are features that extend Manim's core functionality. Since Manim is\nextensible and not everything belongs in its core, we'll go over how to\ninstall, use, and create your own plugins.\n\n.. note::\n\n    The standard naming convention for plugins is to prefix the plugin with\n    ``manim-``. This makes them easy for users to find on package\n    repositories such as PyPI.\n\n.. WARNING::\n\n    The plugin feature is new and under active development. Expect updates\n    for the best practices on installing, using, and creating plugins; as\n    well as new subcommands/flags for ``manim plugins``\n\n.. tip::\n\n    See https://plugins.manim.community/ for the list of plugins available.\n\nInstalling Plugins\n******************\nPlugins can be easily installed via the ``pip``\ncommand:\n\n.. code-block:: bash\n\n    pip install manim-*\n\nAfter installing a plugin, you may use the ``manim plugins`` command to list\nyour available plugins, see the following help output:\n\n.. code-block:: bash\n\n    manim plugins -h\n    Usage: manim plugins [OPTIONS]\n\n      Manages Manim plugins.\n\n    Options:\n    -l, --list  List available plugins\n    -h, --help  Show this message and exit.\n\n    Made with <3 by Manim Community developers.\n\nYou can list plugins as such:\n\n.. code-block:: bash\n\n    manim plugins -l\n    Plugins:\n    • manim_plugintemplate\n\nUsing Plugins in Projects\n*************************\nFor enabling a plugin ``manim.cfg`` or command line parameters should be used.\n\n.. important::\n\n    The plugins should be module name of the plugin and not PyPi name.\n\nEnabling plugins through ``manim.cfg``\n\n.. code-block:: ini\n\n    [CLI]\n    plugins = manim_rubikscube\n\nFor specifying multiple plugins, comma-separated values must be used.\n\n.. code-block:: ini\n\n    [CLI]\n    plugins = manim_rubikscube, manim_plugintemplate\n\nCreating Plugins\n****************\n\nPlugins are intended to extend Manim's core functionality. If you aren't sure\nwhether a feature should be included in Manim's core, feel free to ask over\non the `Discord server <https://www.manim.community/discord/>`_. Visit\n`manim-plugintemplate <https://pypi.org/project/manim-plugintemplate/>`_\non PyPI.org which serves as an in-depth tutorial for creating plugins.\n\n.. code-block:: bash\n\n    pip install manim-plugintemplate\n\nThe only requirement of manim plugins is that they specify an entry point\nwith the group, ``\"manim.plugins\"``. This allows Manim to discover plugins\navailable in the user's environment. Everything regarding the plugin's\ndirectory structure, build system, and naming are completely up to your\ndiscretion as an author.\n\nThe standard way to specify an entry point (see\n`the Python packaging guide <https://packaging.python.org/specifications/entry-points/>`__\nfor details) is to include the following in your ``pyproject.toml``:\n\n.. code-block:: toml\n\n    [project.entry-points.\"manim.plugins\"]\n    \"name\" = \"object_reference\"\n\n.. versionremoved:: 0.18.1\n\n    Plugins should be imported explicitly to be usable in user code. The plugin\n    system will probably be refactored in the future to provide a more structured\n    interface.\n\nA note on Renderer Compatibility\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nDepending on which renderer is currently active, custom mobjects\ncreated in your plugin might want to behave differently as the\ncorresponding mobject base classes are (unfortunately) not fully\ncompatible.\n\nThe currently active renderer can be queried by checking the value\nof ``manim.config.renderer``. All possible renderer types are given\nby :class:`.constants.RendererType`. The module :mod:`.manim.mobject.utils`\ncontains utility functions that return the base class for the currently\nactive renderer.\n\nA simple form of renderer compatibility (by hot-swapping the class\ninheritance chain) for Mobjects directly inheriting from\n:class:`.Mobject` or :class:`.VMobject` can be achieved by using the\n:class:`.mobject.opengl.opengl_compatibility.ConvertToOpenGL` metaclass.\n"
  },
  {
    "path": "docs/source/reference.rst",
    "content": "Reference Manual\n================\n\nThis reference manual details modules, functions, and variables included in\nManim, describing what they are and what they do.  For learning how to use\nManim, see :doc:`tutorials/index`.  For a list of changes since the last release, see\nthe :doc:`changelog`.\n\n.. warning:: The pages linked to here are currently a work in progress.\n\nInheritance Graphs\n------------------\n\nAnimations\n**********\n\n.. inheritance-diagram::\n   manim.animation.animation\n   manim.animation.changing\n   manim.animation.composition\n   manim.animation.creation\n   manim.animation.fading\n   manim.animation.growing\n   manim.animation.indication\n   manim.animation.movement\n   manim.animation.numbers\n   manim.animation.rotation\n   manim.animation.specialized\n   manim.animation.speedmodifier\n   manim.animation.transform\n   manim.animation.transform_matching_parts\n   manim.animation.updaters.mobject_update_utils\n   manim.animation.updaters.update\n   :parts: 1\n   :top-classes: manim.animation.animation.Animation\n\nCameras\n*******\n\n.. inheritance-diagram::\n   manim.camera.camera\n   manim.camera.mapping_camera\n   manim.camera.moving_camera\n   manim.camera.multi_camera\n   manim.camera.three_d_camera\n   :parts: 1\n   :top-classes: manim.camera.camera.Camera, manim.mobject.mobject.Mobject\n\nMobjects\n********\n\n.. inheritance-diagram::\n   manim.mobject.frame\n   manim.mobject.geometry.arc\n   manim.mobject.geometry.boolean_ops\n   manim.mobject.geometry.line\n   manim.mobject.geometry.polygram\n   manim.mobject.geometry.shape_matchers\n   manim.mobject.geometry.tips\n   manim.mobject.graph\n   manim.mobject.graphing.coordinate_systems\n   manim.mobject.graphing.functions\n   manim.mobject.graphing.number_line\n   manim.mobject.graphing.probability\n   manim.mobject.graphing.scale\n   manim.mobject.logo\n   manim.mobject.matrix\n   manim.mobject.mobject\n   manim.mobject.table\n   manim.mobject.three_d.polyhedra\n   manim.mobject.three_d.three_d_utils\n   manim.mobject.three_d.three_dimensions\n   manim.mobject.svg.brace\n   manim.mobject.svg.svg_mobject\n   manim.mobject.text.code_mobject\n   manim.mobject.text.numbers\n   manim.mobject.text.tex_mobject\n   manim.mobject.text.text_mobject\n   manim.mobject.types.image_mobject\n   manim.mobject.types.point_cloud_mobject\n   manim.mobject.types.vectorized_mobject\n   manim.mobject.value_tracker\n   manim.mobject.vector_field\n   :parts: 1\n   :top-classes: manim.mobject.mobject.Mobject\n\nScenes\n******\n\n.. inheritance-diagram::\n   manim.scene.moving_camera_scene\n   manim.scene.scene\n   manim.scene.scene_file_writer\n   manim.scene.three_d_scene\n   manim.scene.vector_space_scene\n   manim.scene.zoomed_scene\n   :parts: 1\n   :top-classes: manim.scene.scene.Scene, manim.scene.scene.RerunSceneHandler\n\n\nModule Index\n------------\n\n.. toctree::\n   :maxdepth: 3\n\n   reference_index/animations\n   reference_index/cameras\n   reference_index/configuration\n   reference_index/mobjects\n   reference_index/scenes\n   reference_index/utilities_misc\n"
  },
  {
    "path": "docs/source/reference_index/animations.rst",
    "content": "Animations\n==========\n\n.. currentmodule:: manim\n\n.. autosummary::\n   :toctree: ../reference\n\n   ~animation.animation\n   ~animation.changing\n   ~animation.composition\n   ~animation.creation\n   ~animation.fading\n   ~animation.growing\n   ~animation.indication\n   ~animation.movement\n   ~animation.numbers\n   ~animation.rotation\n   ~animation.specialized\n   ~animation.speedmodifier\n   ~animation.transform\n   ~animation.transform_matching_parts\n   ~animation.updaters\n"
  },
  {
    "path": "docs/source/reference_index/cameras.rst",
    "content": "Cameras\n=======\n\n.. currentmodule:: manim\n\n.. autosummary::\n   :toctree: ../reference\n\n   ~camera.camera\n   ~camera.mapping_camera\n   ~camera.moving_camera\n   ~camera.multi_camera\n   ~camera.three_d_camera\n"
  },
  {
    "path": "docs/source/reference_index/configuration.rst",
    "content": "Configuration\n=============\n\nModule Index\n------------\n\n.. currentmodule:: manim\n\n.. autosummary::\n   :toctree: ../reference\n\n   ~_config\n   ~_config.utils\n   ~_config.logger_utils\n"
  },
  {
    "path": "docs/source/reference_index/mobjects.rst",
    "content": "Mobjects\n========\n\n.. currentmodule:: manim\n\n.. autosummary::\n   :toctree: ../reference\n\n   ~mobject.frame\n   ~mobject.geometry\n   ~mobject.graph\n   ~mobject.graphing\n   ~mobject.logo\n   ~mobject.matrix\n   ~mobject.mobject\n   ~mobject.svg\n   ~mobject.table\n   ~mobject.text\n   ~mobject.three_d\n   ~mobject.types\n   ~mobject.utils\n   ~mobject.value_tracker\n   ~mobject.vector_field\n"
  },
  {
    "path": "docs/source/reference_index/scenes.rst",
    "content": "Scenes\n======\n\n.. currentmodule:: manim\n\n.. autosummary::\n   :toctree: ../reference\n\n   ~scene.moving_camera_scene\n   ~scene.section\n   ~scene.scene\n   ~scene.scene_file_writer\n   ~scene.three_d_scene\n   ~scene.vector_space_scene\n   ~scene.zoomed_scene\n"
  },
  {
    "path": "docs/source/reference_index/utilities_misc.rst",
    "content": "Utilities and other modules\n===========================\n\nModule Index\n------------\n\n.. currentmodule:: manim\n\n.. autosummary::\n   :toctree: ../reference\n\n   ~utils.bezier\n   cli\n   ~utils.color\n   ~utils.commands\n   ~utils.config_ops\n   constants\n   data_structures\n   ~utils.debug\n   ~utils.deprecation\n   ~utils.docbuild\n   ~utils.hashing\n   ~utils.images\n   ~utils.ipython_magic\n   ~utils.iterables\n   ~utils.paths\n   ~utils.rate_functions\n   ~utils.simple_functions\n   ~utils.sounds\n   ~utils.space_ops\n   ~utils.testing\n   ~utils.tex\n   ~utils.tex_file_writing\n   ~utils.tex_templates\n   typing\n"
  },
  {
    "path": "docs/source/robots.txt",
    "content": "User-agent: *\nDisallow: /\nAllow: /en/stable/\n\nSitemap: https://docs.manim.community/sitemap.xml\n"
  },
  {
    "path": "docs/source/tutorials/building_blocks.rst",
    "content": "#######################\nManim's building blocks\n#######################\n\nThis document explains the building blocks of manim and will give you all the\nnecessary tools to start producing your own videos.\n\nEssentially, manim puts at your disposal three different concepts that you can\norchestrate together to produce mathematical animations: the\n**mathematical object** (or **mobject** for short), the **animation**, and the\n**scene**.  As we will see in the following sections, each of these three\nconcepts is implemented in manim as a separate class: the :class:`.Mobject`,\n:class:`.Animation`, and :class:`.Scene` classes.\n\n.. note:: It is recommended that you read the tutorials :doc:`quickstart` and\n          :doc:`output_and_config` before reading this page.\n\n\n********\nMobjects\n********\n\nMobjects are the basic building blocks for all manim animations.  Each class\nthat derives from :class:`.Mobject` represents an object that can be displayed\non the screen.  For example, simple shapes such as :class:`.Circle`,\n:class:`.Arrow`, and :class:`.Rectangle` are all mobjects.  More complicated\nconstructs such as :class:`.Axes`, :class:`.FunctionGraph`, or\n:class:`.BarChart` are mobjects as well.\n\nIf you try to display an instance of :class:`.Mobject` on the screen, you will only\nsee an empty frame.  The reason is that the :class:`.Mobject` class is an\nabstract base class of all other mobjects, i.e. it does not have any\npre-determined visual shape that can be displayed on the screen.  It is only the\nskeleton of a thing that *could* be displayed.  Therefore, you will rarely need\nto use plain instances of :class:`.Mobject`; instead, you will most likely\ncreate instances of its derived classes.  One of these derived classes is\n:class:`.VMobject`.  The ``V`` stands for Vectorized Mobject.  In essence, a\nvmobject is a mobject that uses `vector graphics\n<https://en.wikipedia.org/wiki/Vector_graphics>`_ to be displayed.  Most of\nthe time, you will be dealing with vmobjects, though we will continue to use\nthe term \"mobject\" to refer to the class of shapes that can be displayed on the\nscreen, as it is more general.\n\n.. note:: Any object that can be displayed on the screen is a ``mobject``, even if\n          it is not necessarily *mathematical* in nature.\n\n.. tip:: To see examples of classes derived from :class:`.Mobject`, see the\n         :mod:`.geometry` module.  Most of these are in fact derived from\n         :class:`.VMobject` as well.\n\n\nCreating and displaying mobjects\n================================\n\nAs explained in :doc:`quickstart`, usually all of the code in a manim\nscript is put inside the :meth:`.construct` method of a :class:`.Scene` class.\nTo display a mobject on the screen, call the :meth:`~.Scene.add` method of the\ncontaining :class:`.Scene`.  This is the principal way of displaying a mobject\non the screen when it is not being animated.  To remove a mobject from the\nscreen, simply call the :meth:`~.Scene.remove` method from the containing\n:class:`.Scene`.\n\n.. manim:: CreatingMobjects\n\n    class CreatingMobjects(Scene):\n        def construct(self):\n            circle = Circle()\n            self.add(circle)\n            self.wait(1)\n            self.remove(circle)\n            self.wait(1)\n\n\nPlacing mobjects\n================\n\nLet's define a new :class:`.Scene` called ``Shapes`` and :meth:`~.Scene.add`\nsome mobjects to it.  This script generates a static picture that displays a\ncircle, a square, and a triangle:\n\n.. manim:: Shapes\n\n    class Shapes(Scene):\n        def construct(self):\n            circle = Circle()\n            square = Square()\n            triangle = Triangle()\n\n            circle.shift(LEFT)\n            square.shift(UP)\n            triangle.shift(RIGHT)\n\n            self.add(circle, square, triangle)\n            self.wait(1)\n\nBy default, mobjects are placed at the center of coordinates, or *origin*, when\nthey are first created.  They are also given some default colors.  Further, the\n``Shapes`` scene places the mobjects by using the :meth:`.shift` method.  The\nsquare is shifted one unit in the ``UP`` direction from the origin, while the\ncircle and triangle are shifted one unit ``LEFT`` and ``RIGHT``, respectively.\n\n.. attention:: Unlike other graphics software, manim places the center of\n               coordinates at the center of the screen.  The positive vertical\n               direction is up, and the positive horizontal direction is right.\n               See also the constants ``ORIGIN``, ``UP``, ``DOWN``, ``LEFT``,\n               ``RIGHT``, and others, defined in the :mod:`.constants` module.\n\nThere are many other possible ways to place mobjects on the screen, for example\n:meth:`.move_to`, :meth:`.next_to`, and :meth:`.align_to`.  The next scene\n``MobjectPlacement`` uses all three.\n\n.. manim:: MobjectPlacement\n\n    class MobjectPlacement(Scene):\n        def construct(self):\n            circle = Circle()\n            square = Square()\n            triangle = Triangle()\n\n            # place the circle two units left from the origin\n            circle.move_to(LEFT * 2)\n            # place the square to the left of the circle\n            square.next_to(circle, LEFT)\n            # align the left border of the triangle to the left border of the circle\n            triangle.align_to(circle, LEFT)\n\n            self.add(circle, square, triangle)\n            self.wait(1)\n\nThe :meth:`.move_to` method uses absolute units (measured relative to the\n``ORIGIN``), while :meth:`.next_to` uses relative units (measured from the\nmobject passed as the first argument).  :meth:`align_to` uses ``LEFT`` not as\nmeasuring units but as a way to determine the border to use for alignment.  The\ncoordinates of the borders of a mobject are determined using an imaginary\nbounding box around it.\n\n.. tip:: Many methods in manim can be chained together.  For example the two\n         lines\n\n         .. code-block:: python\n\n             square = Square()\n             square.shift(LEFT)\n\n         can be replaced by\n\n         .. code-block:: python\n\n             square = Square().shift(LEFT)\n\n         Technically, this is possible because most methods calls return the modified mobject.\n\n\nStyling mobjects\n================\n\nThe following scene changes the default aesthetics of the mobjects.\n\n.. manim:: MobjectStyling\n\n    class MobjectStyling(Scene):\n        def construct(self):\n            circle = Circle().shift(LEFT)\n            square = Square().shift(UP)\n            triangle = Triangle().shift(RIGHT)\n\n            circle.set_stroke(color=GREEN, width=20)\n            square.set_fill(YELLOW, opacity=1.0)\n            triangle.set_fill(PINK, opacity=0.5)\n\n            self.add(circle, square, triangle)\n            self.wait(1)\n\nThis scene uses two of the main functions that change the visual style of a\nmobject: :meth:`.set_stroke` and :meth:`.set_fill`.  The former changes the\nvisual style of the mobject's border while the latter changes the style of the\ninterior.  By default, most mobjects have a fully transparent interior so you\nmust specify the ``opacity`` parameter to display the color.  An\nopacity of ``1.0`` means fully opaque, while ``0.0`` means fully transparent.\n\nOnly instances of :class:`.VMobject` implement :meth:`.set_stroke` and\n:meth:`.set_fill`.  Instances of :class:`.Mobject` implement\n:meth:`.~Mobject.set_color` instead.  The vast majority of pre-defined classes\nare derived from :class:`.VMobject` so it is usually safe to assume that you\nhave access to :meth:`.set_stroke` and :meth:`.set_fill`.\n\n\nMobject on-screen order\n=======================\n\nThe next scene is exactly the same as the ``MobjectStyling`` scene from the\nprevious section, except for exactly one line.\n\n.. manim:: MobjectZOrder\n\n    class MobjectZOrder(Scene):\n        def construct(self):\n            circle = Circle().shift(LEFT)\n            square = Square().shift(UP)\n            triangle = Triangle().shift(RIGHT)\n\n            circle.set_stroke(color=GREEN, width=20)\n            square.set_fill(YELLOW, opacity=1.0)\n            triangle.set_fill(PINK, opacity=0.5)\n\n            self.add(triangle, square, circle)\n            self.wait(1)\n\nThe only difference here (besides the scene name) is the order in which the\nmobjects are added to the scene.  In ``MobjectStyling``, we added them as\n``add(circle, square, triangle)``, whereas in ``MobjectZOrder`` we add them as\n``add(triangle, square, circle)``.\n\nAs you can see, the order of the arguments of :meth:`~.Scene.add` determines\nthe order that the mobjects are displayed on the screen, with the left-most\narguments being put in the back.\n\n\n**********\nAnimations\n**********\n\nAt the heart of manim is animation.  Generally, you can add an animation to\nyour scene by calling the :meth:`~.Scene.play` method.\n\n.. manim:: SomeAnimations\n\n    class SomeAnimations(Scene):\n        def construct(self):\n            square = Square()\n\n            # some animations display mobjects, ...\n            self.play(FadeIn(square))\n\n            # ... some move or rotate mobjects around...\n            self.play(Rotate(square, PI/4))\n\n            # some animations remove mobjects from the screen\n            self.play(FadeOut(square))\n\n            self.wait(1)\n\nPut simply, animations are procedures that interpolate between two mobjects.\nFor example, :code:`FadeIn(square)` starts with a fully transparent version of\n:code:`square` and ends with a fully opaque version, interpolating between them\nby gradually increasing the opacity.  :class:`.FadeOut` works in the opposite\nway: it interpolates from fully opaque to fully transparent.  As another\nexample, :class:`.Rotate` starts with the mobject passed to it as argument, and\nends with the same object but rotated by a certain amount, this time\ninterpolating the mobject's angle instead of its opacity.\n\n\nAnimating methods\n=================\n\nAny property of a mobject that can be changed can be animated.  In fact, any\nmethod that changes a mobject's property can be used as an animation, through\nthe use of :meth:`.animate`.\n\n.. manim:: AnimateExample\n    :ref_classes: Animation\n\n    class AnimateExample(Scene):\n        def construct(self):\n            square = Square().set_fill(RED, opacity=1.0)\n            self.add(square)\n\n            # animate the change of color\n            self.play(square.animate.set_fill(WHITE))\n            self.wait(1)\n\n            # animate the change of position and the rotation at the same time\n            self.play(square.animate.shift(UP).rotate(PI / 3))\n            self.wait(1)\n\n:meth:`.animate` is a property of all mobjects that animates the methods that come\nafterward. For example, :code:`square.set_fill(WHITE)` sets the fill color of\nthe square, while :code:`square.animate.set_fill(WHITE)` animates this action.\n\nAnimation run time\n==================\n\nBy default, any animation passed to :meth:`play` lasts for exactly one second.\nUse the :code:`run_time` argument to control the duration.\n\n.. manim:: RunTime\n\n    class RunTime(Scene):\n        def construct(self):\n            square = Square()\n            self.add(square)\n            self.play(square.animate.shift(UP), run_time=3)\n            self.wait(1)\n\nCreating a custom animation\n===========================\n\nEven though Manim has many built-in animations, you will find times when you need to smoothly animate from one state of a :class:`~.Mobject` to another.\nIf you find yourself in that situation, then you can define your own custom animation.\nYou start by extending the :class:`~.Animation` class and overriding its :meth:`~.Animation.interpolate_mobject`.\nThe :meth:`~.Animation.interpolate_mobject` method receives alpha as a parameter that starts at 0 and changes throughout the animation.\nSo, you just have to manipulate self.mobject inside Animation according to the alpha value in its interpolate_mobject method.\nThen you get all the benefits of :class:`~.Animation` such as playing it for different run times or using different rate functions.\n\nLet's say you start with a number and want to create a :class:`~.Transform` animation that transforms it to a target number.\nYou can do it using :class:`~.FadeTransform`, which will fade out the starting number and fade in the target number.\nBut when we think about transforming a number from one to another, an intuitive way of doing it is by incrementing or decrementing it smoothly.\nManim has a feature that allows you to customize this behavior by defining your own custom animation.\n\nYou can start by creating your own ``Count`` class that extends :class:`~.Animation`.\nThe class can have a constructor with three arguments, a :class:`~.DecimalNumber` Mobject, start, and end.\nThe constructor will pass the :class:`~.DecimalNumber` Mobject to the super constructor (in this case, the :class:`~.Animation` constructor) and will set start and end.\n\nThe only thing that you need to do is to define how you want it to look at every step of the animation.\nManim provides you with the alpha value in the :meth:`~.Animation.interpolate_mobject` method based on frame rate of video, rate function, and run time of animation played.\nThe alpha parameter holds a value between 0 and 1 representing the step of the currently playing animation.\nFor example, 0 means the beginning of the animation, 0.5 means halfway through the animation, and 1 means the end of the animation.\n\nIn the case of the ``Count`` animation, you just have to figure out a way to determine the number to display at the given alpha value and then set that value in the :meth:`~.Animation.interpolate_mobject` method of the ``Count`` animation.\nSuppose you are starting at 50 and incrementing until the :class:`~.DecimalNumber` reaches 100 at the end of the animation.\n\n* If alpha is 0, you want the value to be 50.\n* If alpha is 0.5, you want the value to be 75.\n* If alpha is 1, you want the value to be 100.\n\nGenerally, you start with the starting number and add only some part of the value to be increment according to the alpha value.\nSo, the logic of calculating the number to display at each step will be ``50 + alpha * (100 - 50)``.\nOnce you set the calculated value for the :class:`~.DecimalNumber`, you are done.\n\n.. note::\n\n    If you're creating a custom animation and want to use a ``rate_func``, you must explicitly apply\n    ``self.rate_func(alpha)`` to the parameter you're animating. For example, try switching the rate\n    function to ``rate_functions.there_and_back`` to observe how it affects the counting behavior.\n\n\nOnce you have defined your ``Count`` animation, you can play it in your :class:`~.Scene` for any duration you want for any :class:`~.DecimalNumber` with any rate function.\n\n.. manim:: CountingScene\n    :ref_classes: Animation DecimalNumber\n    :ref_methods: Animation.interpolate_mobject Scene.play\n\n    class Count(Animation):\n        def __init__(self, number: DecimalNumber, start: float, end: float, **kwargs) -> None:\n            # Pass number as the mobject of the animation\n            super().__init__(number,  **kwargs)\n            # Set start and end\n            self.start = start\n            self.end = end\n\n        def interpolate_mobject(self, alpha: float) -> None:\n            # Set value of DecimalNumber according to alpha\n            value = self.start + (self.rate_func(alpha) * (self.end - self.start))\n            self.mobject.set_value(value)\n\n\n    class CountingScene(Scene):\n        def construct(self):\n            # Create Decimal Number and add it to scene\n            number = DecimalNumber().set_color(WHITE).scale(5)\n            # Add an updater to keep the DecimalNumber centered as its value changes\n            number.add_updater(lambda number: number.move_to(ORIGIN))\n\n            self.add(number)\n\n            self.wait()\n\n            # Play the Count Animation to count from 0 to 100 in 4 seconds\n            self.play(Count(number, 0, 100), run_time=4, rate_func=linear)\n\n            self.wait()\n\nUsing coordinates of a mobject\n==============================\n\nMobjects contain points that define their boundaries.\nThese points can be used to add other mobjects respectively to each other,\ne.g. by methods like :meth:`~.Mobject.get_center` , :meth:`~.Mobject.get_top`\nand :meth:`~.Mobject.get_start`. Here is an example of some important coordinates:\n\n.. manim:: MobjectExample\n    :save_last_frame:\n\n    class MobjectExample(Scene):\n        def construct(self):\n            p1 = [-1,-1, 0]\n            p2 = [ 1,-1, 0]\n            p3 = [ 1, 1, 0]\n            p4 = [-1, 1, 0]\n            a  = Line(p1,p2).append_points(Line(p2,p3).points).append_points(Line(p3,p4).points)\n            point_start  = a.get_start()\n            point_end    = a.get_end()\n            point_center = a.get_center()\n            self.add(Text(f\"a.get_start() = {np.round(point_start,2).tolist()}\", font_size=24).to_edge(UR).set_color(YELLOW))\n            self.add(Text(f\"a.get_end() = {np.round(point_end,2).tolist()}\", font_size=24).next_to(self.mobjects[-1],DOWN).set_color(RED))\n            self.add(Text(f\"a.get_center() = {np.round(point_center,2).tolist()}\", font_size=24).next_to(self.mobjects[-1],DOWN).set_color(BLUE))\n\n            self.add(Dot(a.get_start()).set_color(YELLOW).scale(2))\n            self.add(Dot(a.get_end()).set_color(RED).scale(2))\n            self.add(Dot(a.get_top()).set_color(GREEN_A).scale(2))\n            self.add(Dot(a.get_bottom()).set_color(GREEN_D).scale(2))\n            self.add(Dot(a.get_center()).set_color(BLUE).scale(2))\n            self.add(Dot(a.point_from_proportion(0.5)).set_color(ORANGE).scale(2))\n            self.add(*[Dot(x) for x in a.points])\n            self.add(a)\n\nTransforming mobjects into other mobjects\n=========================================\nIt is also possible to transform a mobject into another mobject like this:\n\n.. manim:: ExampleTransform\n\n    class ExampleTransform(Scene):\n        def construct(self):\n            self.camera.background_color = WHITE\n            m1 = Square().set_color(RED)\n            m2 = Rectangle().set_color(RED).rotate(0.2)\n            self.play(Transform(m1,m2))\n\nThe Transform function maps points of the previous mobject to the points of the\nnext mobject.\nThis might result in strange behaviour, e.g. when the dots of one mobject are\narranged clockwise and the other points are arranged counterclockwise.\nHere it might help to use the `flip` function and reposition the points via the\n`roll <https://numpy.org/doc/stable/reference/generated/numpy.roll.html>`_\nfunction of numpy:\n\n.. manim:: ExampleRotation\n\n    class ExampleRotation(Scene):\n        def construct(self):\n            self.camera.background_color = WHITE\n            m1a = Square().set_color(RED).shift(LEFT)\n            m1b = Circle().set_color(RED).shift(LEFT)\n            m2a = Square().set_color(BLUE).shift(RIGHT)\n            m2b = Circle().set_color(BLUE).shift(RIGHT)\n\n            points = m2a.points\n            points = np.roll(points, int(len(points)/4), axis=0)\n            m2a.points = points\n\n            self.play(Transform(m1a,m1b),Transform(m2a,m2b), run_time=1)\n\n******\nScenes\n******\n\nThe :class:`.Scene` class is the connective tissue of manim.  Every mobject has\nto be :meth:`added <.Scene.add>` to a scene to be displayed, or :meth:`removed\n<.Scene.remove>` from it to cease being displayed.  Every animation has to be\n:meth:`played <.Scene.play>` by a scene, and every time interval where no\nanimation occurs is determined by a call to :meth:`~.Scene.wait`.  All of the\ncode of your video must be contained in the :meth:`~.Scene.construct` method of\na class that derives from :class:`.Scene`.  Finally, a single file may contain\nmultiple :class:`.Scene` subclasses if multiple scenes are to be\nrendered at the same time.\n"
  },
  {
    "path": "docs/source/tutorials/index.rst",
    "content": "Tutorials\n=========\n\n.. toctree::\n   :caption: Table of Contents\n   :maxdepth: 2\n\n   quickstart\n   output_and_config\n   building_blocks\n"
  },
  {
    "path": "docs/source/tutorials/output_and_config.rst",
    "content": "Manim's Output Settings\n=======================\n\nThis document will focus on understanding manim's output files and some of the\nmain command-line flags available.\n\n.. note:: This tutorial picks up where :doc:`quickstart` left off, so please\n          read that document before starting this one.\n\nManim output folders\n********************\n\nAt this point, you have just executed the following command.\n\n.. code-block:: bash\n\n   manim -pql scene.py SquareToCircle\n\nLet's dissect what just happened step by step.  First, this command executes\nmanim on the file ``scene.py``, which contains our animation code.  Further,\nthis command tells manim exactly which ``Scene`` is to be rendered, in this case,\nit is ``SquareToCircle``.  This is necessary because a single scene file may\ncontain more than one scene.  Next, the flag `-p` tells manim to play the scene\nonce it's rendered, and the `-ql` flag tells manim to render the scene in low\nquality.\n\nAfter the video is rendered, you will see that manim has generated some new\nfiles and the project folder will look as follows.\n\n.. code-block:: bash\n\n   project/\n   ├─scene.py\n   └─media\n     ├─videos\n     |  └─scene\n     |     └─480p15\n     |        ├─SquareToCircle.mp4\n     |        └─partial_movie_files\n     ├─text\n     └─Tex\n\n\nThere are quite a few new files.  The main output is in\n``media/videos/scene/480p15/SquareToCircle.mp4``.  By default, the ``media``\nfolder will contain all of manim's output files.  The ``media/videos``\nsubfolder contains the rendered videos.  Inside of it, you will find one folder\nfor each different video quality.  In our case, since we used the ``-l`` flag,\nthe video was generated at 480 resolution at 15 frames per second from the\n``scene.py`` file.  Therefore, the output can be found inside\n``media/videos/scene/480p15``.  The additional folders\n``media/videos/scene/480p15/partial_movie_files`` as well as ``media/text`` and\n``media/Tex`` contain files that are used by manim internally.\n\nYou can see how manim makes use of the generated folder structure by executing\nthe following command,\n\n.. code-block:: bash\n\n   manim -pqh scene.py SquareToCircle\n\nThe ``-ql`` flag (for low quality) has been replaced by the ``-qh`` flag, for\nhigh quality.  Manim will take considerably longer to render this file, and it\nwill play it once it's done since we are using the ``-p`` flag.  The output\nshould look like this:\n\n.. manim:: SquareToCircle3\n   :hide_source:\n   :quality: high\n\n   class SquareToCircle3(Scene):\n       def construct(self):\n           circle = Circle()                    # create a circle\n           circle.set_fill(PINK, opacity=0.5)   # set color and transparency\n\n           square = Square()                    # create a square\n           square.flip(RIGHT)                   # flip horizontally\n           square.rotate(-3 * TAU / 8)          # rotate a certain amount\n\n           self.play(Create(square))      # animate the creation of the square\n           self.play(Transform(square, circle)) # interpolate the square into the circle\n           self.play(FadeOut(square))           # fade out animation\n\nAnd the folder structure should look as follows.\n\n.. code-block:: bash\n\n   project/\n   ├─scene.py\n   └─media\n     ├─videos\n     | └─scene\n     |   ├─480p15\n     |   | ├─SquareToCircle.mp4\n     |   | └─partial_movie_files\n     |   └─1080p60\n     |     ├─SquareToCircle.mp4\n     |     └─partial_movie_files\n     ├─text\n     └─Tex\n\nManim has created a new folder ``media/videos/1080p60``, which corresponds to\nthe high resolution and the 60 frames per second.  Inside of it, you can find\nthe new ``SquareToCircle.mp4``, as well as the corresponding\n``partial_movie_files``.\n\nWhen working on a project with multiple scenes, and trying out multiple\nresolutions, the structure of the output directories will keep all your videos\norganized.\n\nFurther, manim has the option to output the last frame of a scene, when adding\nthe flag ``-s``. This is the fastest option to quickly get a preview of a scene.\nThe corresponding folder structure looks like this:\n\n.. code-block:: bash\n\n   project/\n   ├─scene.py\n   └─media\n     ├─images\n     | └─scene\n     |   ├─SquareToCircle.png\n     ├─videos\n     | └─scene\n     |   ├─480p15\n     |   | ├─SquareToCircle.mp4\n     |   | └─partial_movie_files\n     |   └─1080p60\n     |     ├─SquareToCircle.mp4\n     |     └─partial_movie_files\n     ├─text\n     └─Tex\n\nSaving the last frame with ``-s`` can be combined with the flags for different\nresolutions, e.g. ``-s -ql``, ``-s -qh``\n\n\n\n\nSections\n********\n\nIn addition to the movie output file one can use sections. Each section produces\nits own output video. The cuts between two sections can be set like this:\n\n.. code-block:: python\n\n    def construct(self):\n        # play the first animations...\n        # you don't need a section in the very beginning as it gets created automatically\n        self.next_section()\n        # play more animations...\n        self.next_section(\"this is an optional name that doesn't have to be unique\")\n        # play even more animations...\n        self.next_section(\"this is a section without any animations, it will be removed\")\n\nAll the animations between two of these cuts get concatenated into a single output\nvideo file.\nBe aware that you need at least one animation in each section. For example this wouldn't create an output video:\n\n.. code-block:: python\n\n   def construct(self):\n       self.next_section()\n       # this section doesn't have any animations and will be removed\n       # but no error will be thrown\n       # feel free to tend your flock of empty sections if you so desire\n       self.add(Circle())\n       self.next_section()\n\nOne way of fixing this is to wait a little:\n\n.. code-block:: python\n\n   def construct(self):\n       self.next_section()\n       self.add(Circle())\n       # now we wait 1sec and have an animation to satisfy the section\n       self.wait()\n       self.next_section()\n\nFor videos to be created for each section you have to add the ``--save_sections`` flag to the Manim call like this:\n\n.. code-block:: bash\n\n   manim --save_sections scene.py\n\nIf you do this, the ``media`` folder will look like this:\n\n.. code-block:: bash\n\n    media\n    ├── images\n    │   └── simple_scenes\n    └── videos\n        └── simple_scenes\n            └── 480p15\n                ├── ElaborateSceneWithSections.mp4\n                ├── partial_movie_files\n                │   └── ElaborateSceneWithSections\n                │       ├── 2201830969_104169243_1331664314.mp4\n                │       ├── 2201830969_398514950_125983425.mp4\n                │       ├── 2201830969_398514950_3447021159.mp4\n                │       ├── 2201830969_398514950_4144009089.mp4\n                │       ├── 2201830969_4218360830_1789939690.mp4\n                │       ├── 3163782288_524160878_1793580042.mp4\n                │       └── partial_movie_file_list.txt\n                └── sections\n                    ├── ElaborateSceneWithSections_0000.mp4\n                    ├── ElaborateSceneWithSections_0001.mp4\n                    ├── ElaborateSceneWithSections_0002.mp4\n                    └── ElaborateSceneWithSections.json\n\nAs you can see each section receives their own output video in the ``sections`` directory.\nThe JSON file in here contains some useful information for each section:\n\n.. code-block:: json\n\n    [\n        {\n            \"name\": \"create square\",\n            \"type\": \"default.normal\",\n            \"video\": \"ElaborateSceneWithSections_0000.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"2.000000\",\n            \"nb_frames\": \"30\"\n        },\n        {\n            \"name\": \"transform to circle\",\n            \"type\": \"default.normal\",\n            \"video\": \"ElaborateSceneWithSections_0001.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"2.000000\",\n            \"nb_frames\": \"30\"\n        },\n        {\n            \"name\": \"fade out\",\n            \"type\": \"default.normal\",\n            \"video\": \"ElaborateSceneWithSections_0002.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"2.000000\",\n            \"nb_frames\": \"30\"\n        }\n    ]\n\nThis data can be used by third party applications, like a presentation system or automated video editing tool.\n\nYou can also skip rendering all animations belonging to a section like this:\n\n.. code-block:: python\n\n    def construct(self):\n        self.next_section(skip_animations=True)\n        # play some animations that shall be skipped...\n        self.next_section()\n        # play some animations that won't get skipped...\n\n\n\n\nSome command line flags\n***********************\n\nWhen executing the command\n\n.. code-block:: bash\n\n   manim -pql scene.py SquareToCircle\n\nit specifies the scene to render.  This is not necessary now.  When a single\nfile contains only one ``Scene`` class, it will just render the ``Scene``\nclass.  When a single file contains more than one ``Scene`` class, manim will\nlet you choose a ``Scene`` class. If your file contains multiple ``Scene``\nclasses, and you want to render them all, you can use the ``-a`` flag.\n\nAs discussed previously, the ``-ql`` specifies low render quality (854x480\n15FPS).  This does not look very good, but is very useful for rapid\nprototyping and testing. The other options that specify render quality are\n``-qm``, ``-qh``, ``-qp`` and ``-qk`` for medium (1280x720 30FPS), high\n(1920x1080 60FPS), 2k (2560x1440 60FPS) and 4k quality (3840x2160 60FPS),\nrespectively.\n\nThe ``-p`` flag plays the animation once it is rendered.  If you want to open\nthe file browser at the location of the animation instead of playing it, you\ncan use the ``-f`` flag.  You can also omit these two flags.\n\nFinally, by default manim will output .mp4 files.  If you want your animations\nin .gif format instead, use the ``--format gif`` flag.  The output files will\nbe in the same folder as the .mp4 files, and with the same name, but a\ndifferent file extension.\n\nThis was a quick review of some of the most frequent command-line flags.\nFor a thorough review of all flags available, see the :doc:`thematic guide on\nManim's configuration system </guides/configuration>`.\n"
  },
  {
    "path": "docs/source/tutorials/quickstart.rst",
    "content": "==========\nQuickstart\n==========\n\n.. note::\n\n  Before proceeding, install Manim and make sure it is running properly by\n  following the steps in :doc:`../installation`. For\n  information on using Manim with Jupyterlab or Jupyter notebook, go to the\n  documentation for the\n  :meth:`IPython magic command <manim.utils.ipython_magic.ManimMagic.manim>`,\n  ``%%manim``.\n\n\n.. important::\n\n  If you installed Manim in the recommended way, using the\n  Python management tool ``uv``, then you either need to make sure the corresponding\n  virtual environment is activated (follow the instructions printed on running ``uv venv``),\n  or you need to remember to prefix the ``manim`` command in the console with ``uv run``;\n  that is, ``uv run manim ...``.\n\nOverview\n********\n\nThis quickstart guide will lead you through creating a sample project using Manim: an animation\nengine for precise programmatic animations.\n\nFirst, you will use a command line\ninterface to create a ``Scene``, the class through which Manim generates videos.\nIn the ``Scene`` you will animate a circle. Then you will add another ``Scene`` showing\na square transforming into a circle. This will be your introduction to Manim's animation ability.\nAfterwards, you will position multiple mathematical objects (``Mobject``\\s). Finally, you\nwill learn the ``.animate`` syntax, a powerful feature that animates the methods you\nuse to modify ``Mobject``\\s.\n\n\nStarting a new project\n**********************\n\nStart by creating a new folder::\n\n   manim init project my-project --default\n\nThe ``my-project`` folder is the root folder for your project. It contains all the files that Manim needs to function,\nas well as any output that your project produces.\n\n\nAnimating a circle\n******************\n\n1. Open a text editor, such as Notepad. Open the file ``main.py`` in the ``my-project`` folder.\n   It should look something like this:\n\n   .. code-block:: python\n\n     from manim import *\n\n\n     class CreateCircle(Scene):\n         def construct(self):\n             circle = Circle()  # create a circle\n             circle.set_fill(PINK, opacity=0.5)  # set the color and transparency\n             self.play(Create(circle))  # show the circle on screen\n\n\n2. Open the command line, navigate to your project folder, and execute\n   the following command:\n\n   .. code-block:: bash\n\n     manim -pql main.py CreateCircle\n\nManim will output rendering information, then create an MP4 file.\nYour default movie player will play the MP4 file, displaying the following animation.\n\n.. manim:: CreateCircle\n   :hide_source:\n\n   class CreateCircle(Scene):\n       def construct(self):\n           circle = Circle()                   # create a circle\n           circle.set_fill(PINK, opacity=0.5)  # set the color and transparency\n           self.play(Create(circle))     # show the circle on screen\n\nIf you see an animation of a pink circle being drawn, congratulations!\nYou just wrote your first Manim scene from scratch.\n\nIf you get an error\nmessage instead, you do not see a video, or if the video output does not\nlook like the preceding animation, it is likely that Manim has not been\ninstalled correctly. Please refer to our :doc:`FAQ section </faq/index>`\nfor help with the most common issues.\n\n\n***********\nExplanation\n***********\n\nLet's go over the script you just executed line by line to see how Manim was\nable to draw the circle.\n\nThe first line imports all of the contents of the library:\n\n.. code-block:: python\n\n   from manim import *\n\nThis is the recommended way of using Manim, as a single script often uses\nmultiple names from the Manim namespace. In your script, you imported and used\n``Scene``, ``Circle``, ``PINK`` and ``Create``.\n\nNow let's look at the next two lines:\n\n.. code-block:: python\n\n   class CreateCircle(Scene):\n       def construct(self):\n           [...]\n\nMost of the time, the code for scripting an animation is entirely contained within\nthe :meth:`~.Scene.construct` method of a :class:`.Scene` class.\nInside :meth:`~.Scene.construct`, you can create objects, display them on screen, and animate them.\n\nThe next two lines create a circle and set its color and opacity:\n\n.. code-block:: python\n\n           circle = Circle()  # create a circle\n           circle.set_fill(PINK, opacity=0.5)  # set the color and transparency\n\nFinally, the last line uses the animation :class:`.Create` to display the\ncircle on your screen:\n\n.. code-block:: python\n\n           self.play(Create(circle))  # show the circle on screen\n\n.. tip:: All animations must reside within the :meth:`~.Scene.construct` method of a\n         class derived from :class:`.Scene`.  Other code, such as auxiliary\n         or mathematical functions, may reside outside the class.\n\n\nTransforming a square into a circle\n***********************************\n\nWith our circle animation complete, let's move on to something a little more complicated.\n\n1. Open ``scene.py``, and add the following code snippet below the ``CreateCircle`` class:\n\n.. code-block:: python\n\n   class SquareToCircle(Scene):\n       def construct(self):\n           circle = Circle()  # create a circle\n           circle.set_fill(PINK, opacity=0.5)  # set color and transparency\n\n           square = Square()  # create a square\n           square.rotate(PI / 4)  # rotate a certain amount\n\n           self.play(Create(square))  # animate the creation of the square\n           self.play(Transform(square, circle))  # interpolate the square into the circle\n           self.play(FadeOut(square))  # fade out animation\n\n2. Render ``SquareToCircle`` by running the following command in the command line:\n\n.. code-block:: bash\n\n   manim -pql scene.py SquareToCircle\n\nThe following animation will render:\n\n.. manim:: SquareToCircle2\n   :hide_source:\n\n   class SquareToCircle2(Scene):\n       def construct(self):\n           circle = Circle()  # create a circle\n           circle.set_fill(PINK, opacity=0.5)  # set color and transparency\n\n           square = Square()  # create a square\n           square.rotate(PI / 4)  # rotate a certain amount\n\n           self.play(Create(square))  # animate the creation of the square\n           self.play(Transform(square, circle))  # interpolate the square into the circle\n           self.play(FadeOut(square))  # fade out animation\n\nThis example shows one of the primary features of Manim: the ability to\nimplement complicated and mathematically intensive animations (such as cleanly\ninterpolating between two geometric shapes) with just a few lines of code.\n\n\nPositioning ``Mobject``\\s\n*************************\n\nNext, let's go over some basic techniques for positioning ``Mobject``\\s.\n\n1. Open ``scene.py``, and add the following code snippet below the ``SquareToCircle`` class:\n\n.. code-block:: python\n\n   class SquareAndCircle(Scene):\n       def construct(self):\n           circle = Circle()  # create a circle\n           circle.set_fill(PINK, opacity=0.5)  # set the color and transparency\n\n           square = Square()  # create a square\n           square.set_fill(BLUE, opacity=0.5)  # set the color and transparency\n\n           square.next_to(circle, RIGHT, buff=0.5)  # set the position\n           self.play(Create(circle), Create(square))  # show the shapes on screen\n\n2. Render ``SquareAndCircle`` by running the following command in the command line:\n\n.. code-block:: bash\n\n   manim -pql scene.py SquareAndCircle\n\nThe following animation will render:\n\n.. manim:: SquareAndCircle2\n   :hide_source:\n\n   class SquareAndCircle2(Scene):\n       def construct(self):\n           circle = Circle()  # create a circle\n           circle.set_fill(PINK, opacity=0.5)  # set the color and transparency\n\n           square = Square() # create a square\n           square.set_fill(BLUE, opacity=0.5) # set the color and transparency\n\n           square.next_to(circle, RIGHT, buff=0.5) # set the position\n           self.play(Create(circle), Create(square))  # show the shapes on screen\n\n``next_to`` is a ``Mobject`` method for positioning ``Mobject``\\s.\n\nWe first specified\nthe pink circle as the square's reference point by passing ``circle`` as the method's first argument.\nThe second argument is used to specify the direction the ``Mobject`` is placed relative to the reference point.\nIn this case, we set the direction to ``RIGHT``, telling Manim to position the square to the right of the circle.\nFinally, ``buff=0.5`` applied a small distance buffer between the two objects.\n\nTry changing ``RIGHT`` to ``LEFT``, ``UP``, or ``DOWN`` instead, and see how that changes the position of the square.\n\nUsing positioning methods, you can render a scene with multiple ``Mobject``\\s,\nsetting their locations in the scene using coordinates or positioning them\nrelative to each other.\n\nFor more information on ``next_to`` and other positioning methods, check out the\nlist of :class:`.Mobject` methods in our reference manual.\n\n\nUsing ``.animate`` syntax to animate methods\n********************************************\n\nThe final lesson in this tutorial is using ``.animate``, a ``Mobject`` method which\nanimates changes you make to a ``Mobject``. When you prepend ``.animate`` to any\nmethod call that modifies a ``Mobject``, the method becomes an animation which\ncan be played using ``self.play``. Let's return to ``SquareToCircle`` to see the\ndifferences between using methods when creating a ``Mobject``,\nand animating those method calls with ``.animate``.\n\n1. Open ``scene.py``, and add the following code snippet below the ``SquareAndCircle`` class:\n\n.. code-block:: python\n\n   class AnimatedSquareToCircle(Scene):\n       def construct(self):\n           circle = Circle()  # create a circle\n           square = Square()  # create a square\n\n           self.play(Create(square))  # show the square on screen\n           self.play(square.animate.rotate(PI / 4))  # rotate the square\n           self.play(Transform(square, circle))  # transform the square into a circle\n           self.play(\n               square.animate.set_fill(PINK, opacity=0.5)\n           )  # color the circle on screen\n\n2. Render ``AnimatedSquareToCircle`` by running the following command in the command line:\n\n.. code-block:: bash\n\n   manim -pql scene.py AnimatedSquareToCircle\n\nThe following animation will render:\n\n.. manim:: AnimatedSquareToCircle2\n   :hide_source:\n\n   class AnimatedSquareToCircle2(Scene):\n       def construct(self):\n           circle = Circle()  # create a circle\n           square = Square()  # create a square\n\n           self.play(Create(square))  # show the square on screen\n           self.play(square.animate.rotate(PI / 4))  # rotate the square\n           self.play(Transform(square, circle))  # transform the square into a circle\n           self.play(square.animate.set_fill(PINK, opacity=0.5))  # color the circle on screen\n\nThe first ``self.play`` creates the square. The second animates rotating it 45 degrees.\nThe third transforms the square into a circle, and the last colors the circle pink.\nAlthough the end result is the same as that of ``SquareToCircle``, ``.animate`` shows\n``rotate`` and ``set_fill`` being applied to the ``Mobject`` dynamically, instead of creating them\nwith the changes already applied.\n\nTry other methods, like ``flip`` or ``shift``, and see what happens.\n\n3. Open ``scene.py``, and add the following code snippet below the ``AnimatedSquareToCircle`` class:\n\n.. code-block:: python\n\n   class DifferentRotations(Scene):\n       def construct(self):\n           left_square = Square(color=BLUE, fill_opacity=0.7).shift(2 * LEFT)\n           right_square = Square(color=GREEN, fill_opacity=0.7).shift(2 * RIGHT)\n           self.play(\n               left_square.animate.rotate(PI), Rotate(right_square, angle=PI), run_time=2\n           )\n           self.wait()\n\n4. Render ``DifferentRotations`` by running the following command in the command line:\n\n.. code-block:: bash\n\n   manim -pql scene.py DifferentRotations\n\nThe following animation will render:\n\n.. manim:: DifferentRotations2\n   :hide_source:\n\n   class DifferentRotations2(Scene):\n       def construct(self):\n           left_square = Square(color=BLUE, fill_opacity=0.7).shift(2*LEFT)\n           right_square = Square(color=GREEN, fill_opacity=0.7).shift(2*RIGHT)\n           self.play(left_square.animate.rotate(PI), Rotate(right_square, angle=PI), run_time=2)\n           self.wait()\n\nThis ``Scene`` illustrates the quirks of ``.animate``. When using ``.animate``, Manim\nactually takes a ``Mobject``'s starting state and its ending state and interpolates the two.\nIn the ``AnimatedSquareToCircle`` class, you can observe this when the square rotates:\nthe corners of the square appear to contract slightly as they move into the positions required\nfor the first square to transform into the second one.\n\nIn ``DifferentRotations``, the difference between ``.animate``'s interpretation of rotation and the\n``Rotate`` method is far more apparent. The starting and ending states of a ``Mobject`` rotated 180 degrees\nare the same, so ``.animate`` tries to interpolate two identical objects and the result is the left square.\nIf you find that your own usage of ``.animate`` is causing similar unwanted behavior, consider\nusing conventional animation methods like the right square, which uses ``Rotate``.\n\n\n``Transform`` vs ``ReplacementTransform``\n*****************************************\nThe difference between ``Transform`` and ``ReplacementTransform`` is that ``Transform(mob1, mob2)`` transforms the points\n(as well as other attributes like color) of ``mob1`` into the points/attributes of ``mob2``.\n\n``ReplacementTransform(mob1, mob2)`` on the other hand literally replaces ``mob1`` on the scene with ``mob2``.\n\nThe use of ``ReplacementTransform`` or ``Transform`` is mostly up to personal preference. They can be used to accomplish the same effect, as shown below.\n\n.. code-block:: python\n\n    class TwoTransforms(Scene):\n        def transform(self):\n            a = Circle()\n            b = Square()\n            c = Triangle()\n            self.play(Transform(a, b))\n            self.play(Transform(a, c))\n            self.play(FadeOut(a))\n\n        def replacement_transform(self):\n            a = Circle()\n            b = Square()\n            c = Triangle()\n            self.play(ReplacementTransform(a, b))\n            self.play(ReplacementTransform(b, c))\n            self.play(FadeOut(c))\n\n        def construct(self):\n            self.transform()\n            self.wait(0.5)  # wait for 0.5 seconds\n            self.replacement_transform()\n\n\nHowever, in some cases it is more beneficial to use ``Transform``, like when you are transforming several mobjects one after the other.\nThe code below avoids having to keep a reference to the last mobject that was transformed.\n\n.. manim:: TransformCycle\n\n    class TransformCycle(Scene):\n        def construct(self):\n            a = Circle()\n            t1 = Square()\n            t2 = Triangle()\n            self.add(a)\n            self.wait()\n            for t in [t1,t2]:\n                self.play(Transform(a,t))\n\n************\nYou're done!\n************\n\nWith a working installation of Manim and this sample project under your belt,\nyou're ready to start creating animations of your own.  To learn\nmore about what Manim is doing under the hood, move on to the next tutorial:\n:doc:`output_and_config`.  For an overview of\nManim's features, as well as its configuration and other settings, check out the\nother :doc:`Tutorials <../tutorials/index>`.  For a list of all available features, refer to the\n:doc:`../reference` page.\n"
  },
  {
    "path": "docs/source/tutorials_guides.rst",
    "content": "Tutorials & Guides\n==================\n\n.. toctree::\n   :caption: Table of Contents\n   :maxdepth: 2\n\n   tutorials/index\n   guides/index\n   faq/index\n"
  },
  {
    "path": "example_scenes/advanced_tex_fonts.py",
    "content": "from manim import *\n\n# French Cursive LaTeX font example from http://jf.burnol.free.fr/showcase.html\n\n# Example 1 Manually creating a Template\n\nTemplateForFrenchCursive = TexTemplate(\n    preamble=r\"\"\"\n\\usepackage[english]{babel}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\n\\usepackage[T1]{fontenc}\n\\usepackage[default]{frcursive}\n\\usepackage[eulergreek,noplusnominus,noequal,nohbar,%\nnolessnomore,noasterisk]{mathastext}\n\"\"\",\n)\n\n\ndef FrenchCursive(*tex_strings, **kwargs):\n    return Tex(*tex_strings, tex_template=TemplateForFrenchCursive, **kwargs)\n\n\nclass TexFontTemplateManual(Scene):\n    \"\"\"An example scene that uses a manually defined TexTemplate() object to create\n    LaTeX output in French Cursive font\n    \"\"\"\n\n    def construct(self):\n        self.add(Tex(\"Tex Font Example\").to_edge(UL))\n        self.play(Create(FrenchCursive(\"$f: A \\\\longrightarrow B$\").shift(UP)))\n        self.play(Create(FrenchCursive(\"Behold! We can write math in French Cursive\")))\n        self.wait(1)\n        self.play(\n            Create(\n                Tex(\n                    \"See more font templates at \\\\\\\\ http://jf.burnol.free.fr/showcase.html\",\n                ).shift(2 * DOWN),\n            ),\n        )\n        self.wait(2)\n\n\n# Example 2, using a Template from the collection\n\n\nclass TexFontTemplateLibrary(Scene):\n    \"\"\"An example scene that uses TexTemplate objects from the TexFontTemplates collection\n    to create sample LaTeX output in every font that will compile on the local system.\n\n    Please Note:\n    Many of the in the TexFontTemplates collection require that specific fonts\n    are installed on your local machine.\n    For example, choosing the template TexFontTemplates.comic_sans will\n    not compile if the Comic Sans Microsoft font is not installed.\n\n    This scene will only render those Templates that do not cause a TeX\n    compilation error on your system. Furthermore, some of the ones that do render,\n    may still render incorrectly. This is beyond the scope of manim.\n    Feel free to experiment.\n    \"\"\"\n\n    def construct(self):\n        def write_one_line(template):\n            x = Tex(template.description, tex_template=template).shift(UP)\n            self.play(Create(x))\n            self.wait(1)\n            self.play(FadeOut(x))\n\n        examples = [\n            TexFontTemplates.american_typewriter,  # \"American Typewriter\"\n            TexFontTemplates.antykwa,  # \"Antykwa Półtawskiego (TX Fonts for Greek and math symbols)\"\n            TexFontTemplates.apple_chancery,  # \"Apple Chancery\"\n            TexFontTemplates.auriocus_kalligraphicus,  # \"Auriocus Kalligraphicus (Symbol Greek)\"\n            TexFontTemplates.baskervald_adf_fourier,  # \"Baskervald ADF with Fourier\"\n            TexFontTemplates.baskerville_it,  # \"Baskerville (Italic)\"\n            TexFontTemplates.biolinum,  # \"Biolinum\"\n            TexFontTemplates.brushscriptx,  # \"BrushScriptX-Italic (PX math and Greek)\"\n            TexFontTemplates.chalkboard_se,  # \"Chalkboard SE\"\n            TexFontTemplates.chalkduster,  # \"Chalkduster\"\n            TexFontTemplates.comfortaa,  # \"Comfortaa\"\n            TexFontTemplates.comic_sans,  # \"Comic Sans MS\"\n            TexFontTemplates.droid_sans,  # \"Droid Sans\"\n            TexFontTemplates.droid_sans_it,  # \"Droid Sans (Italic)\"\n            TexFontTemplates.droid_serif,  # \"Droid Serif\"\n            TexFontTemplates.droid_serif_px_it,  # \"Droid Serif (PX math symbols) (Italic)\"\n            TexFontTemplates.ecf_augie,  # \"ECF Augie (Euler Greek)\"\n            TexFontTemplates.ecf_jd,  # \"ECF JD (with TX fonts)\"\n            TexFontTemplates.ecf_skeetch,  # \"ECF Skeetch (CM Greek)\"\n            TexFontTemplates.ecf_tall_paul,  # \"ECF Tall Paul (with Symbol font)\"\n            TexFontTemplates.ecf_webster,  # \"ECF Webster (with TX fonts)\"\n            TexFontTemplates.electrum_adf,  # \"Electrum ADF (CM Greek)\"\n            TexFontTemplates.epigrafica,  # Epigrafica\n            TexFontTemplates.fourier_utopia,  # \"Fourier Utopia (Fourier upright Greek)\"\n            TexFontTemplates.french_cursive,  # \"French Cursive (Euler Greek)\"\n            TexFontTemplates.gfs_bodoni,  # \"GFS Bodoni\"\n            TexFontTemplates.gfs_didot,  # \"GFS Didot (Italic)\"\n            TexFontTemplates.gfs_neoHellenic,  # \"GFS NeoHellenic\"\n            TexFontTemplates.gnu_freesans_tx,  # \"GNU FreeSerif (and TX fonts symbols)\"\n            TexFontTemplates.gnu_freeserif_freesans,  # \"GNU FreeSerif and FreeSans\"\n            TexFontTemplates.helvetica_fourier_it,  # \"Helvetica with Fourier (Italic)\"\n            TexFontTemplates.latin_modern_tw_it,  # \"Latin Modern Typewriter Proportional (CM Greek) (Italic)\"\n            TexFontTemplates.latin_modern_tw,  # \"Latin Modern Typewriter Proportional\"\n            TexFontTemplates.libertine,  # \"Libertine\"\n            TexFontTemplates.libris_adf_fourier,  # \"Libris ADF with Fourier\"\n            TexFontTemplates.minion_pro_myriad_pro,  # \"Minion Pro and Myriad Pro (and TX fonts symbols)\"\n            TexFontTemplates.minion_pro_tx,  # \"Minion Pro (and TX fonts symbols)\"\n            TexFontTemplates.new_century_schoolbook,  # \"New Century Schoolbook (Symbol Greek)\"\n            TexFontTemplates.new_century_schoolbook_px,  # \"New Century Schoolbook (Symbol Greek, PX math symbols)\"\n            TexFontTemplates.noteworthy_light,  # \"Noteworthy Light\"\n            TexFontTemplates.palatino,  # \"Palatino (Symbol Greek)\"\n            TexFontTemplates.papyrus,  # \"Papyrus\"\n            TexFontTemplates.romande_adf_fourier_it,  # \"Romande ADF with Fourier (Italic)\"\n            TexFontTemplates.slitex,  # \"SliTeX (Euler Greek)\"\n            TexFontTemplates.times_fourier_it,  # \"Times with Fourier (Italic)\"\n            TexFontTemplates.urw_avant_garde,  # \"URW Avant Garde (Symbol Greek)\"\n            TexFontTemplates.urw_zapf_chancery,  # \"URW Zapf Chancery (CM Greek)\"\n            TexFontTemplates.venturis_adf_fourier_it,  # \"Venturis ADF with Fourier (Italic)\"\n            TexFontTemplates.verdana_it,  # \"Verdana (Italic)\"\n            TexFontTemplates.vollkorn_fourier_it,  # \"Vollkorn with Fourier (Italic)\"\n            TexFontTemplates.vollkorn,  # \"Vollkorn (TX fonts for Greek and math symbols)\"\n            TexFontTemplates.zapf_chancery,  # \"Zapf Chancery\"\n        ]\n\n        self.add(Tex(\"Tex Font Template Example\").to_edge(UL))\n\n        for font in examples:\n            try:\n                write_one_line(font)\n            except Exception:\n                print(\"FAILURE on \", font.description, \" - skipping.\")\n\n        self.play(\n            Create(\n                Tex(\n                    \"See more font templates at \\\\\\\\ http://jf.burnol.free.fr/showcase.html\",\n                ).shift(2 * DOWN),\n            ),\n        )\n        self.wait(2)\n"
  },
  {
    "path": "example_scenes/basic.py",
    "content": "#!/usr/bin/env python\n\n\nfrom manim import *\n\n# To watch one of these scenes, run the following:\n# python --quality m manim -p example_scenes.py SquareToCircle\n#\n# Use the flag --quality l for a faster rendering at a lower quality.\n# Use -s to skip to the end and just save the final frame\n# Use the -p to have preview of the animation (or image, if -s was\n# used) pop up once done.\n# Use -n <number> to skip ahead to the nth animation of a scene.\n# Use -r <number> to specify a resolution (for example, -r 1920,1080\n# for a 1920x1080 video)\n\n\nclass OpeningManim(Scene):\n    def construct(self):\n        title = Tex(r\"This is some \\LaTeX\")\n        basel = MathTex(r\"\\sum_{n=1}^\\infty \\frac{1}{n^2} = \\frac{\\pi^2}{6}\")\n        VGroup(title, basel).arrange(DOWN)\n        self.play(\n            Write(title),\n            FadeIn(basel, shift=DOWN),\n        )\n        self.wait()\n\n        transform_title = Tex(\"That was a transform\")\n        transform_title.to_corner(UP + LEFT)\n        self.play(\n            Transform(title, transform_title),\n            LaggedStart(*(FadeOut(obj, shift=DOWN) for obj in basel)),\n        )\n        self.wait()\n\n        grid = NumberPlane()\n        grid_title = Tex(\"This is a grid\", font_size=72)\n        grid_title.move_to(transform_title)\n\n        self.add(grid, grid_title)  # Make sure title is on top of grid\n        self.play(\n            FadeOut(title),\n            FadeIn(grid_title, shift=UP),\n            Create(grid, run_time=3, lag_ratio=0.1),\n        )\n        self.wait()\n\n        grid_transform_title = Tex(\n            r\"That was a non-linear function \\\\ applied to the grid\",\n        )\n        grid_transform_title.move_to(grid_title, UL)\n        grid.prepare_for_nonlinear_transform()\n        self.play(\n            grid.animate.apply_function(\n                lambda p: p\n                + np.array(\n                    [\n                        np.sin(p[1]),\n                        np.sin(p[0]),\n                        0,\n                    ],\n                ),\n            ),\n            run_time=3,\n        )\n        self.wait()\n        self.play(Transform(grid_title, grid_transform_title))\n        self.wait()\n\n\nclass SquareToCircle(Scene):\n    def construct(self):\n        circle = Circle()\n        square = Square()\n        square.flip(RIGHT)\n        square.rotate(-3 * TAU / 8)\n        circle.set_fill(PINK, opacity=0.5)\n\n        self.play(Create(square))\n        self.play(Transform(square, circle))\n        self.play(FadeOut(square))\n\n\nclass WarpSquare(Scene):\n    def construct(self):\n        square = Square()\n        self.play(\n            ApplyPointwiseFunction(\n                lambda point: complex_to_R3(np.exp(R3_to_complex(point))),\n                square,\n            ),\n        )\n        self.wait()\n\n\nclass WriteStuff(Scene):\n    def construct(self):\n        example_text = Tex(\"This is a some text\", tex_to_color_map={\"text\": YELLOW})\n        example_tex = MathTex(\n            \"\\\\sum_{k=1}^\\\\infty {1 \\\\over k^2} = {\\\\pi^2 \\\\over 6}\",\n        )\n        group = VGroup(example_text, example_tex)\n        group.arrange(DOWN)\n        group.width = config[\"frame_width\"] - 2 * LARGE_BUFF\n\n        self.play(Write(example_text))\n        self.play(Write(example_tex))\n        self.wait()\n\n\nclass UpdatersExample(Scene):\n    def construct(self):\n        decimal = DecimalNumber(\n            0,\n            show_ellipsis=True,\n            num_decimal_places=3,\n            include_sign=True,\n        )\n        square = Square().to_edge(UP)\n\n        decimal.add_updater(lambda d: d.next_to(square, RIGHT))\n        decimal.add_updater(lambda d: d.set_value(square.get_center()[1]))\n        self.add(square, decimal)\n        self.play(\n            square.animate.to_edge(DOWN),\n            rate_func=there_and_back,\n            run_time=5,\n        )\n        self.wait()\n\n\nclass SpiralInExample(Scene):\n    def construct(self):\n        logo_green = \"#81b29a\"\n        logo_blue = \"#454866\"\n        logo_red = \"#e07a5f\"\n\n        font_color = \"#ece6e2\"\n\n        pi = MathTex(r\"\\pi\").scale(7).set_color(font_color)\n        pi.shift(2.25 * LEFT + 1.5 * UP)\n\n        circle = Circle(color=logo_green, fill_opacity=0.7, stroke_width=0).shift(LEFT)\n        square = Square(color=logo_blue, fill_opacity=0.8, stroke_width=0).shift(UP)\n        triangle = Triangle(color=logo_red, fill_opacity=0.9, stroke_width=0).shift(\n            RIGHT\n        )\n        pentagon = Polygon(\n            *[\n                [np.cos(2 * np.pi / 5 * i), np.sin(2 * np.pi / 5 * i), 0]\n                for i in range(5)\n            ],\n            color=PURPLE_B,\n            fill_opacity=1,\n            stroke_width=0,\n        ).shift(UP + 2 * RIGHT)\n        shapes = VGroup(triangle, square, circle, pentagon, pi)\n        self.play(SpiralIn(shapes, fade_in_fraction=0.9))\n        self.wait()\n        self.play(FadeOut(shapes))\n\n\nTriangle.set_default(stroke_width=20)\n\n\nclass LineJoints(Scene):\n    def construct(self):\n        t1 = Triangle()\n        t2 = Triangle(joint_type=LineJointType.ROUND)\n        t3 = Triangle(joint_type=LineJointType.BEVEL)\n\n        grp = VGroup(t1, t2, t3).arrange(RIGHT)\n        grp.set(width=config.frame_width - 1)\n\n        self.add(grp)\n\n\n# See many more examples at https://docs.manim.community/en/stable/examples.html\n"
  },
  {
    "path": "example_scenes/custom_template.tex",
    "content": "\\documentclass[preview]{standalone}\n\n\\usepackage[english]{babel}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\n\\usepackage[f]{esvect}\n\n\\begin{document}\n\nYourTextHere\n\n\\end{document}\n"
  },
  {
    "path": "example_scenes/customtex.py",
    "content": "from manim import *\n\n\nclass TexTemplateFromCLI(Scene):\n    \"\"\"This scene uses a custom TexTemplate file.\n    The path of the TexTemplate _must_ be passed with the command line\n    argument `--tex_template <path to template>`.\n    For this scene, you can use the custom_template.tex file next to it.\n    This scene will fail to render if a tex_template.tex that doesn't\n    import esvect is passed, and will throw a LaTeX error in that case.\n    \"\"\"\n\n    def construct(self):\n        text = MathTex(r\"\\vv{vb}\")\n        self.play(Write(text))\n        self.wait(1)\n\n\nclass InCodeTexTemplate(Scene):\n    \"\"\"This example scene demonstrates how to modify the tex template\n    for a particular scene from the code for the scene itself.\n    \"\"\"\n\n    def construct(self):\n        # Create a new template\n        myTemplate = TexTemplate()\n\n        # Add packages to the template\n        myTemplate.add_to_preamble(r\"\\usepackage{esvect}\")\n\n        # Set the compiler and output format (default: latex and .dvi)\n        # possible tex compilers: \"latex\", \"pdflatex\", \"xelatex\", \"lualatex\", \"luatex\"\n        # possible output formats: \".dvi\",  \".pdf\", and \".xdv\"\n        myTemplate.tex_compiler = \"latex\"\n        myTemplate.output_format = \".dvi\"\n\n        # To use this template in a Tex() or MathTex() object\n        # use the keyword argument tex_template\n        text = MathTex(r\"\\vv{vb}\", tex_template=myTemplate)\n        self.play(Write(text))\n        self.wait(1)\n"
  },
  {
    "path": "example_scenes/manim.cfg",
    "content": "\n#This is some custom configuration just as an example\n[logger]\nlogging_keyword = magenta\nlogging_level_notset = dim\nlogging_level_debug = yellow\nlogging_level_info = dim green\nlogging_level_warning = dim red\nlogging_level_error = red\nlogging_level_critical = red\nlog_level =\nlog_time = dim yellow\nlog_message = green\nlog_path = dim\n"
  },
  {
    "path": "example_scenes/manim_jupyter_example.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from manim import *\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"%%manim -v WARNING --disable_caching -ql -s Example1\\n\",\n    \"\\n\",\n    \"class Example1(Scene):\\n\",\n    \"    def construct(self):\\n\",\n    \"        self.add(Circle())\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"%%manim -v WARNING --disable_caching -qm HelloManim\\n\",\n    \"\\n\",\n    \"# set the maximum width for video outputs to a predefined value\\n\",\n    \"config.media_width = \\\"20vw\\\"\\n\",\n    \"# embed video\\n\",\n    \"config.media_embed = True\\n\",\n    \"\\n\",\n    \"class HelloManim(Scene):\\n\",\n    \"    def construct(self):\\n\",\n    \"        self.camera.background_color = \\\"#ece6e2\\\"\\n\",\n    \"        banner_large = ManimBanner(dark_theme=False).scale(0.7)\\n\",\n    \"        self.play(banner_large.create())\\n\",\n    \"        self.play(banner_large.expand())\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.9.1\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 4\n}\n"
  },
  {
    "path": "example_scenes/opengl.py",
    "content": "from pathlib import Path\n\nimport manim.utils.opengl as opengl\nfrom manim import *\nfrom manim.opengl import *\n\n# Copied from https://3b1b.github.io/manim/getting_started/example_scenes.html#surfaceexample.\n# Lines that do not yet work with the Community Version are commented.\n\n\ndef get_plane_mesh(context):\n    shader = Shader(context, name=\"vertex_colors\")\n    attributes = np.zeros(\n        18,\n        dtype=[\n            (\"in_vert\", np.float32, (4,)),\n            (\"in_color\", np.float32, (4,)),\n        ],\n    )\n    attributes[\"in_vert\"] = np.array(\n        [\n            # xy plane\n            [-1, -1, 0, 1],\n            [-1, 1, 0, 1],\n            [1, 1, 0, 1],\n            [-1, -1, 0, 1],\n            [1, -1, 0, 1],\n            [1, 1, 0, 1],\n            # yz plane\n            [0, -1, -1, 1],\n            [0, -1, 1, 1],\n            [0, 1, 1, 1],\n            [0, -1, -1, 1],\n            [0, 1, -1, 1],\n            [0, 1, 1, 1],\n            # xz plane\n            [-1, 0, -1, 1],\n            [-1, 0, 1, 1],\n            [1, 0, 1, 1],\n            [-1, 0, -1, 1],\n            [1, 0, -1, 1],\n            [1, 0, 1, 1],\n        ],\n    )\n    attributes[\"in_color\"] = np.array(\n        [\n            # xy plane\n            [1, 0, 0, 1],\n            [1, 0, 0, 1],\n            [1, 0, 0, 1],\n            [1, 0, 0, 1],\n            [1, 0, 0, 1],\n            [1, 0, 0, 1],\n            # yz plane\n            [0, 1, 0, 1],\n            [0, 1, 0, 1],\n            [0, 1, 0, 1],\n            [0, 1, 0, 1],\n            [0, 1, 0, 1],\n            [0, 1, 0, 1],\n            # xz plane\n            [0, 0, 1, 1],\n            [0, 0, 1, 1],\n            [0, 0, 1, 1],\n            [0, 0, 1, 1],\n            [0, 0, 1, 1],\n            [0, 0, 1, 1],\n        ],\n    )\n    return Mesh(shader, attributes)\n\n\nclass TextTest(Scene):\n    def construct(self):\n        import string\n\n        text = Text(string.ascii_lowercase, stroke_width=4, stroke_color=BLUE).scale(2)\n        text2 = (\n            Text(string.ascii_uppercase, stroke_width=4, stroke_color=BLUE)\n            .scale(2)\n            .next_to(text, DOWN)\n        )\n        # self.add(text, text2)\n        self.play(Write(text))\n        self.play(Write(text2))\n        self.interactive_embed()\n\n\nclass GuiTest(Scene):\n    def construct(self):\n        mesh = get_plane_mesh(self.renderer.context)\n        # mesh.attributes[\"in_vert\"][:, 0]\n        self.add(mesh)\n\n        def update_mesh(mesh, dt):\n            mesh.model_matrix = np.matmul(\n                opengl.rotation_matrix(z=dt),\n                mesh.model_matrix,\n            )\n\n        mesh.add_updater(update_mesh)\n\n        self.interactive_embed()\n\n\nclass GuiTest2(Scene):\n    def construct(self):\n        mesh = get_plane_mesh(self.renderer.context)\n        mesh.attributes[\"in_vert\"][:, 0] -= 2\n        self.add(mesh)\n\n        mesh2 = get_plane_mesh(self.renderer.context)\n        mesh2.attributes[\"in_vert\"][:, 0] += 2\n        self.add(mesh2)\n\n        def callback(sender, data):\n            mesh2.attributes[\"in_color\"][:, 3] = dpg.get_value(sender)\n\n        self.widgets.append(\n            {\n                \"name\": \"mesh2 opacity\",\n                \"widget\": \"slider_float\",\n                \"callback\": callback,\n                \"min_value\": 0,\n                \"max_value\": 1,\n                \"default_value\": 1,\n            },\n        )\n\n        self.interactive_embed()\n\n\nclass ThreeDMobjectTest(Scene):\n    def construct(self):\n        # config[\"background_color\"] = \"#333333\"\n\n        s = Square(fill_opacity=0.5).shift(2 * RIGHT)\n        self.add(s)\n\n        sp = Sphere().shift(2 * LEFT)\n        self.add(sp)\n\n        mesh = get_plane_mesh(self.renderer.context)\n        self.add(mesh)\n\n        def update_mesh(mesh, dt):\n            mesh.model_matrix = np.matmul(\n                opengl.rotation_matrix(z=dt),\n                mesh.model_matrix,\n            )\n\n        mesh.add_updater(update_mesh)\n\n        self.interactive_embed()\n\n\nclass NamedFullScreenQuad(Scene):\n    def construct(self):\n        surface = FullScreenQuad(self.renderer.context, fragment_shader_name=\"design_3\")\n        surface.shader.set_uniform(\n            \"u_resolution\",\n            (config[\"pixel_width\"], config[\"pixel_height\"], 0.0),\n        )\n        surface.shader.set_uniform(\"u_time\", 0)\n        self.add(surface)\n\n        t = 0\n\n        def update_surface(surface, dt):\n            nonlocal t\n            t += dt\n            surface.shader.set_uniform(\"u_time\", t / 4)\n\n        surface.add_updater(update_surface)\n\n        # self.wait()\n        self.interactive_embed()\n\n\nclass InlineFullScreenQuad(Scene):\n    def construct(self):\n        surface = FullScreenQuad(\n            self.renderer.context,\n            \"\"\"\n            #version 330\n\n\n            #define TWO_PI 6.28318530718\n\n            uniform vec2 u_resolution;\n            uniform float u_time;\n            out vec4 frag_color;\n\n            //  Function from Iñigo Quiles\n            //  https://www.shadertoy.com/view/MsS3Wc\n            vec3 hsb2rgb( in vec3 c ){\n                vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),\n                                         6.0)-3.0)-1.0,\n                                 0.0,\n                                 1.0 );\n                rgb = rgb*rgb*(3.0-2.0*rgb);\n                return c.z * mix( vec3(1.0), rgb, c.y);\n            }\n\n            void main(){\n                vec2 st = gl_FragCoord.xy/u_resolution;\n                vec3 color = vec3(0.0);\n\n                // Use polar coordinates instead of cartesian\n                vec2 toCenter = vec2(0.5)-st;\n                float angle = atan(toCenter.y,toCenter.x);\n                angle += u_time;\n                float radius = length(toCenter)*2.0;\n\n                // Map the angle (-PI to PI) to the Hue (from 0 to 1)\n                // and the Saturation to the radius\n                color = hsb2rgb(vec3((angle/TWO_PI)+0.5,radius,1.0));\n\n                frag_color = vec4(color,1.0);\n            }\n            \"\"\",\n        )\n        surface.shader.set_uniform(\n            \"u_resolution\",\n            (config[\"pixel_width\"], config[\"pixel_height\"]),\n        )\n        shader_time = 0\n\n        def update_surface(surface):\n            nonlocal shader_time\n            surface.shader.set_uniform(\"u_time\", shader_time)\n            shader_time += 1 / 60.0\n\n        surface.add_updater(update_surface)\n        self.add(surface)\n        # self.wait(5)\n        self.interactive_embed()\n\n\nclass SimpleInlineFullScreenQuad(Scene):\n    def construct(self):\n        surface = FullScreenQuad(\n            self.renderer.context,\n            \"\"\"\n            #version 330\n\n            uniform float v_red;\n            uniform float v_green;\n            uniform float v_blue;\n            out vec4 frag_color;\n\n            void main() {\n              frag_color = vec4(v_red, v_green, v_blue, 1);\n            }\n            \"\"\",\n        )\n        surface.shader.set_uniform(\"v_red\", 0)\n        surface.shader.set_uniform(\"v_green\", 0)\n        surface.shader.set_uniform(\"v_blue\", 0)\n\n        increase = True\n        val = 0.5\n        surface.shader.set_uniform(\"v_red\", val)\n        surface.shader.set_uniform(\"v_green\", val)\n        surface.shader.set_uniform(\"v_blue\", val)\n\n        def update_surface(mesh, dt):\n            nonlocal increase\n            nonlocal val\n            if increase:\n                val += dt\n            else:\n                val -= dt\n            if val >= 1:\n                increase = False\n            elif val <= 0:\n                increase = True\n            surface.shader.set_uniform(\"v_red\", val)\n            surface.shader.set_uniform(\"v_green\", val)\n            surface.shader.set_uniform(\"v_blue\", val)\n\n        surface.add_updater(update_surface)\n\n        self.add(surface)\n        self.wait(5)\n\n\nclass InlineShaderExample(Scene):\n    def construct(self):\n        config[\"background_color\"] = \"#333333\"\n\n        c = Circle(fill_opacity=0.7).shift(UL)\n        self.add(c)\n\n        shader = Shader(\n            self.renderer.context,\n            source={\n                \"vertex_shader\": \"\"\"\n                #version 330\n\n                in vec4 in_vert;\n                in vec4 in_color;\n                out vec4 v_color;\n                uniform mat4 u_model_view_matrix;\n                uniform mat4 u_projection_matrix;\n\n                void main() {\n                    v_color = in_color;\n                    vec4 camera_space_vertex = u_model_view_matrix * in_vert;\n                    vec4 clip_space_vertex = u_projection_matrix * camera_space_vertex;\n                    gl_Position = clip_space_vertex;\n                }\n            \"\"\",\n                \"fragment_shader\": \"\"\"\n            #version 330\n\n            in vec4 v_color;\n            out vec4 frag_color;\n\n            void main() {\n              frag_color = v_color;\n            }\n            \"\"\",\n            },\n        )\n        shader.set_uniform(\"u_model_view_matrix\", opengl.view_matrix())\n        shader.set_uniform(\n            \"u_projection_matrix\",\n            opengl.orthographic_projection_matrix(),\n        )\n\n        attributes = np.zeros(\n            6,\n            dtype=[\n                (\"in_vert\", np.float32, (4,)),\n                (\"in_color\", np.float32, (4,)),\n            ],\n        )\n        attributes[\"in_vert\"] = np.array(\n            [\n                [-1, -1, 0, 1],\n                [-1, 1, 0, 1],\n                [1, 1, 0, 1],\n                [-1, -1, 0, 1],\n                [1, -1, 0, 1],\n                [1, 1, 0, 1],\n            ],\n        )\n        attributes[\"in_color\"] = np.array(\n            [\n                [0, 0, 1, 1],\n                [0, 0, 1, 1],\n                [0, 0, 1, 1],\n                [0, 0, 1, 1],\n                [0, 0, 1, 1],\n                [0, 0, 1, 1],\n            ],\n        )\n        mesh = Mesh(shader, attributes)\n        self.add(mesh)\n\n        self.wait(5)\n        # self.embed_2()\n\n\nclass NamedShaderExample(Scene):\n    def construct(self):\n        shader = Shader(self.renderer.context, \"manim_coords\")\n        shader.set_uniform(\"u_color\", (0.0, 1.0, 0.0, 1.0))\n\n        view_matrix = self.camera.formatted_view_matrix\n        shader.set_uniform(\"u_model_view_matrix\", view_matrix)\n        shader.set_uniform(\n            \"u_projection_matrix\",\n            opengl.perspective_projection_matrix(),\n        )\n        attributes = np.zeros(\n            6,\n            dtype=[\n                (\"in_vert\", np.float32, (4,)),\n            ],\n        )\n        attributes[\"in_vert\"] = np.array(\n            [\n                [-1, -1, 0, 1],\n                [-1, 1, 0, 1],\n                [1, 1, 0, 1],\n                [-1, -1, 0, 1],\n                [1, -1, 0, 1],\n                [1, 1, 0, 1],\n            ],\n        )\n        mesh = Mesh(shader, attributes)\n        self.add(mesh)\n\n        self.wait(5)\n\n\nclass InteractiveDevelopment(Scene):\n    def construct(self):\n        circle = Circle()\n        circle.set_fill(BLUE, opacity=0.5)\n        circle.set_stroke(BLUE_E, width=4)\n        square = Square()\n\n        self.play(Create(square))\n        self.wait()\n\n        # This opens an iPython terminal where you can keep writing\n        # lines as if they were part of this construct method.\n        # In particular, 'square', 'circle' and 'self' will all be\n        # part of the local namespace in that terminal.\n        # self.embed()\n\n        # Try copying and pasting some of the lines below into\n        # the interactive shell\n        self.play(ReplacementTransform(square, circle))\n        self.wait()\n        self.play(circle.animate.stretch(4, 0))\n        self.play(Rotate(circle, 90 * DEGREES))\n        self.play(circle.animate.shift(2 * RIGHT).scale(0.25))\n\n        # text = Text(\n        #     \"\"\"\n        #     In general, using the interactive shell\n        #     is very helpful when developing new scenes\n        # \"\"\"\n        # )\n        # self.play(Write(text))\n\n        # # In the interactive shell, you can just type\n        # # play, add, remove, clear, wait, save_state and restore,\n        # # instead of self.play, self.add, self.remove, etc.\n\n        # # To interact with the window, type touch().  You can then\n        # # scroll in the window, or zoom by holding down 'z' while scrolling,\n        # # and change camera perspective by holding down 'd' while moving\n        # # the mouse.  Press 'r' to reset to the standard camera position.\n        # # Press 'q' to stop interacting with the window and go back to\n        # # typing new commands into the shell.\n\n        # # In principle you can customize a scene to be responsive to\n        # # mouse and keyboard interactions\n        # always(circle.move_to, self.mouse_point)\n\n\nclass SurfaceExample(Scene):\n    def construct(self):\n        # surface_text = Text(\"For 3d scenes, try using surfaces\")\n        # surface_text.fix_in_frame()\n        # surface_text.to_edge(UP)\n        # self.add(surface_text)\n        # self.wait(0.1)\n\n        torus1 = Torus(major_radius=1, minor_radius=1)\n        torus2 = Torus(major_radius=3, minor_radius=1)\n        sphere = Sphere(radius=3, resolution=torus1.resolution)\n        # You can texture a surface with up to two images, which will\n        # be interpreted as the side towards the light, and away from\n        # the light.  These can be either urls, or paths to a local file\n        # in whatever you've set as the image directory in\n        # the custom_config.yml file\n\n        script_location = Path(__file__).resolve().parent\n        day_texture = (\n            script_location / \"assets\" / \"1280px-Whole_world_-_land_and_oceans.jpg\"\n        )\n        night_texture = script_location / \"assets\" / \"1280px-The_earth_at_night.jpg\"\n\n        surfaces = [\n            OpenGLTexturedSurface(surface, day_texture, night_texture)\n            for surface in [sphere, torus1, torus2]\n        ]\n\n        for mob in surfaces:\n            mob.shift(IN)\n            mob.mesh = OpenGLSurfaceMesh(mob)\n            mob.mesh.set_stroke(BLUE, 1, opacity=0.5)\n\n        # Set perspective\n        frame = self.renderer.camera\n        frame.set_euler_angles(\n            theta=-30 * DEGREES,\n            phi=70 * DEGREES,\n        )\n\n        surface = surfaces[0]\n\n        self.play(\n            FadeIn(surface),\n            Create(surface.mesh, lag_ratio=0.01, run_time=3),\n        )\n        for mob in surfaces:\n            mob.add(mob.mesh)\n        surface.save_state()\n        self.play(Rotate(surface, PI / 2), run_time=2)\n        for mob in surfaces[1:]:\n            mob.rotate(PI / 2)\n\n        self.play(Transform(surface, surfaces[1]), run_time=3)\n\n        self.play(\n            Transform(surface, surfaces[2]),\n            # Move camera frame during the transition\n            frame.animate.increment_phi(-10 * DEGREES),\n            frame.animate.increment_theta(-20 * DEGREES),\n            run_time=3,\n        )\n        # Add ambient rotation\n        frame.add_updater(lambda m, dt: m.increment_theta(-0.1 * dt))\n\n        # Play around with where the light is\n        # light_text = Text(\"You can move around the light source\")\n        # light_text.move_to(surface_text)\n        # light_text.fix_in_frame()\n\n        # self.play(FadeTransform(surface_text, light_text))\n        light = self.camera.light_source\n        self.add(light)\n        light.save_state()\n        self.play(light.animate.move_to(3 * IN), run_time=5)\n        self.play(light.animate.shift(10 * OUT), run_time=5)\n\n        # drag_text = Text(\"Try moving the mouse while pressing d or s\")\n        # drag_text.move_to(light_text)\n        # drag_text.fix_in_frame()\n"
  },
  {
    "path": "lgtm.yml",
    "content": "queries:\n  - exclude: py/init-calls-subclass\n  - exclude: py/unexpected-raise-in-special-method\n  - exclude: py/modification-of-locals\n  - exclude: py/multiple-calls-to-init\n  - exclude: py/missing-call-to-init\n"
  },
  {
    "path": "manim/__init__.py",
    "content": "#!/usr/bin/env python\nfrom __future__ import annotations\n\nfrom importlib.metadata import PackageNotFoundError, version\n\n# Use installed distribution version if available; otherwise fall back to a\n# sensible default so that importing from a source checkout works without an\n# editable install (pip install -e .).\ntry:\n    __version__ = version(__name__)\nexcept PackageNotFoundError:\n    # Package is not installed; provide a fallback version string.\n    __version__ = \"0.0.0+unknown\"\n\n\n# isort: off\n\n# Importing the config module should be the first thing we do, since other\n# modules depend on the global config dict for initialization.\nfrom ._config import *\n\n# many scripts depend on this -> has to be loaded first\nfrom .utils.commands import *\n\n# isort: on\nimport numpy as np\n\nfrom .animation.animation import *\nfrom .animation.changing import *\nfrom .animation.composition import *\nfrom .animation.creation import *\nfrom .animation.fading import *\nfrom .animation.growing import *\nfrom .animation.indication import *\nfrom .animation.movement import *\nfrom .animation.numbers import *\nfrom .animation.rotation import *\nfrom .animation.specialized import *\nfrom .animation.speedmodifier import *\nfrom .animation.transform import *\nfrom .animation.transform_matching_parts import *\nfrom .animation.updaters.mobject_update_utils import *\nfrom .animation.updaters.update import *\nfrom .camera.camera import *\nfrom .camera.mapping_camera import *\nfrom .camera.moving_camera import *\nfrom .camera.multi_camera import *\nfrom .camera.three_d_camera import *\nfrom .constants import *\nfrom .mobject.frame import *\nfrom .mobject.geometry.arc import *\nfrom .mobject.geometry.boolean_ops import *\nfrom .mobject.geometry.labeled import *\nfrom .mobject.geometry.line import *\nfrom .mobject.geometry.polygram import *\nfrom .mobject.geometry.shape_matchers import *\nfrom .mobject.geometry.tips import *\nfrom .mobject.graph import *\nfrom .mobject.graphing.coordinate_systems import *\nfrom .mobject.graphing.functions import *\nfrom .mobject.graphing.number_line import *\nfrom .mobject.graphing.probability import *\nfrom .mobject.graphing.scale import *\nfrom .mobject.logo import *\nfrom .mobject.matrix import *\nfrom .mobject.mobject import *\nfrom .mobject.opengl.dot_cloud import *\nfrom .mobject.opengl.opengl_point_cloud_mobject import *\nfrom .mobject.svg.brace import *\nfrom .mobject.svg.svg_mobject import *\nfrom .mobject.table import *\nfrom .mobject.text.code_mobject import *\nfrom .mobject.text.numbers import *\nfrom .mobject.text.tex_mobject import *\nfrom .mobject.text.text_mobject import *\nfrom .mobject.three_d.polyhedra import *\nfrom .mobject.three_d.three_d_utils import *\nfrom .mobject.three_d.three_dimensions import *\nfrom .mobject.types.image_mobject import *\nfrom .mobject.types.point_cloud_mobject import *\nfrom .mobject.types.vectorized_mobject import *\nfrom .mobject.value_tracker import *\nfrom .mobject.vector_field import *\nfrom .renderer.cairo_renderer import *\nfrom .scene.moving_camera_scene import *\nfrom .scene.scene import *\nfrom .scene.scene_file_writer import *\nfrom .scene.section import *\nfrom .scene.three_d_scene import *\nfrom .scene.vector_space_scene import *\nfrom .scene.zoomed_scene import *\nfrom .utils import color, rate_functions, unit\nfrom .utils.bezier import *\nfrom .utils.color import *\nfrom .utils.config_ops import *\nfrom .utils.debug import *\nfrom .utils.file_ops import *\nfrom .utils.images import *\nfrom .utils.iterables import *\nfrom .utils.paths import *\nfrom .utils.rate_functions import *\nfrom .utils.simple_functions import *\nfrom .utils.sounds import *\nfrom .utils.space_ops import *\nfrom .utils.tex import *\nfrom .utils.tex_templates import *\n\ntry:\n    from IPython import get_ipython\n\n    from .utils.ipython_magic import ManimMagic\nexcept ImportError:\n    pass\nelse:\n    ipy = get_ipython()\n    if ipy is not None:\n        ipy.register_magics(ManimMagic)\n\nfrom .plugins import *\n"
  },
  {
    "path": "manim/__main__.py",
    "content": "from __future__ import annotations\n\nimport click\nimport cloup\n\nfrom manim import __version__\nfrom manim._config import cli_ctx_settings, console\nfrom manim.cli.cfg.group import cfg\nfrom manim.cli.checkhealth.commands import checkhealth\nfrom manim.cli.default_group import DefaultGroup\nfrom manim.cli.init.commands import init\nfrom manim.cli.plugins.commands import plugins\nfrom manim.cli.render.commands import render\nfrom manim.constants import EPILOG\n\n\ndef show_splash(ctx: click.Context, param: click.Option, value: str | None) -> None:\n    \"\"\"When giving a value by console, show an initial message with the Manim\n    version before executing any other command: ``Manim Community vA.B.C``.\n\n    Parameters\n    ----------\n    ctx\n        The Click context.\n    param\n        A Click option.\n    value\n        A string value given by console, or None.\n    \"\"\"\n    if value:\n        console.print(f\"Manim Community [green]v{__version__}[/green]\\n\")\n\n\ndef print_version_and_exit(\n    ctx: click.Context, param: click.Option, value: str | None\n) -> None:\n    \"\"\"Same as :func:`show_splash`, but also exit when giving a value by\n    console.\n\n    Parameters\n    ----------\n    ctx\n        The Click context.\n    param\n        A Click option.\n    value\n        A string value given by console, or None.\n    \"\"\"\n    show_splash(ctx, param, value)\n    if value:\n        ctx.exit()\n\n\n@cloup.group(\n    context_settings=cli_ctx_settings,\n    cls=DefaultGroup,\n    default=\"render\",\n    no_args_is_help=True,\n    help=\"Animation engine for explanatory math videos.\",\n    epilog=\"See 'manim <command>' to read about a specific subcommand.\\n\\n\"\n    \"Note: the subcommand 'manim render' is called if no other subcommand \"\n    \"is specified. Run 'manim render --help' if you would like to know what the \"\n    f\"'-ql' or '-p' flags do, for example.\\n\\n{EPILOG}\",\n)\n@cloup.option(\n    \"--version\",\n    is_flag=True,\n    help=\"Show version and exit.\",\n    callback=print_version_and_exit,\n    is_eager=True,\n    expose_value=False,\n)\n@click.option(\n    \"--show-splash/--hide-splash\",\n    is_flag=True,\n    default=True,\n    help=\"Print splash message with version information.\",\n    callback=show_splash,\n    is_eager=True,\n    expose_value=False,\n)\n@cloup.pass_context\ndef main(ctx: click.Context) -> None:\n    \"\"\"The entry point for Manim.\n\n    Parameters\n    ----------\n    ctx\n        The Click context.\n    \"\"\"\n    pass\n\n\nmain.add_command(checkhealth)\nmain.add_command(cfg)\nmain.add_command(plugins)\nmain.add_command(init)\nmain.add_command(render)\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "manim/_config/__init__.py",
    "content": "\"\"\"Set the global config and logger.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfrom collections.abc import Generator\nfrom contextlib import contextmanager\nfrom typing import Any\n\nfrom .cli_colors import parse_cli_ctx\nfrom .logger_utils import make_logger\nfrom .utils import ManimConfig, ManimFrame, make_config_parser\n\n__all__ = [\n    \"logger\",\n    \"console\",\n    \"error_console\",\n    \"config\",\n    \"frame\",\n    \"tempconfig\",\n    \"cli_ctx_settings\",\n]\n\nparser = make_config_parser()\n\n# Logger usage: accessible globally as `manim.logger` or via `logging.getLogger(\"manim\")`.\n# For printing, use `manim.console.print()` instead of the built-in `print()`.\n# For error output, use `error_console`, which prints to stderr.\nlogger, console, error_console = make_logger(\n    parser[\"logger\"],\n    parser[\"CLI\"][\"verbosity\"],\n)\ncli_ctx_settings = parse_cli_ctx(parser[\"CLI_CTX\"])\n# TODO: temporary to have a clean terminal output when working with PIL or matplotlib\nlogging.getLogger(\"PIL\").setLevel(logging.INFO)\nlogging.getLogger(\"matplotlib\").setLevel(logging.INFO)\n\nconfig = ManimConfig().digest_parser(parser)\n# TODO: to be used in the future - see PR #620\n# https://github.com/ManimCommunity/manim/pull/620\nframe = ManimFrame(config)\n\n\n# This has to go here because it needs access to this module's config\n@contextmanager\ndef tempconfig(temp: ManimConfig | dict[str, Any]) -> Generator[None, None, None]:\n    \"\"\"Temporarily modifies the global ``config`` object using a context manager.\n\n    Inside the ``with`` statement, the modified config will be used.  After\n    context manager exits, the config will be restored to its original state.\n\n    Parameters\n    ----------\n    temp\n        Object whose keys will be used to temporarily update the global\n        ``config``.\n\n    Examples\n    --------\n\n    Use ``with tempconfig({...})`` to temporarily change the default values of\n    certain config options.\n\n    .. code-block:: pycon\n\n       >>> config[\"frame_height\"]\n       8.0\n       >>> with tempconfig({\"frame_height\": 100.0}):\n       ...     print(config[\"frame_height\"])\n       100.0\n       >>> config[\"frame_height\"]\n       8.0\n\n    \"\"\"\n    global config\n    original = config.copy()\n\n    temp = {k: v for k, v in temp.items() if k in original}\n\n    # In order to change the config that every module has access to, use\n    # update(), DO NOT use assignment.  Assigning config = some_dict will just\n    # make the local variable named config point to a new dictionary, it will\n    # NOT change the dictionary that every module has a reference to.\n    config.update(temp)\n    try:\n        yield\n    finally:\n        config.update(original)  # update, not assignment!\n"
  },
  {
    "path": "manim/_config/cli_colors.py",
    "content": "\"\"\"Parses CLI context settings from the configuration file and returns a Cloup Context settings dictionary.\n\nThis module reads configuration values for help formatting, theme styles, and alignment options\nused when rendering command-line interfaces in Manim.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport configparser\nfrom typing import Any\n\nfrom cloup import Context, HelpFormatter, HelpTheme, Style\n\n__all__ = [\"parse_cli_ctx\"]\n\n\ndef parse_cli_ctx(parser: configparser.SectionProxy) -> dict[str, Any]:\n    formatter_settings: dict[str, str | int | None] = {\n        \"indent_increment\": int(parser[\"indent_increment\"]),\n        \"width\": int(parser[\"width\"]),\n        \"col1_max_width\": int(parser[\"col1_max_width\"]),\n        \"col2_min_width\": int(parser[\"col2_min_width\"]),\n        \"col_spacing\": int(parser[\"col_spacing\"]),\n        \"row_sep\": parser[\"row_sep\"] if parser[\"row_sep\"] else None,\n    }\n    theme_settings = {}\n    theme_keys = {\n        \"command_help\",\n        \"invoked_command\",\n        \"heading\",\n        \"constraint\",\n        \"section_help\",\n        \"col1\",\n        \"col2\",\n        \"epilog\",\n    }\n    # Extract and apply any style-related keys defined in the config section.\n    for k, v in parser.items():\n        if k in theme_keys and v:\n            theme_settings.update({k: Style(v)})\n\n    formatter = {}\n    theme = parser[\"theme\"] if parser[\"theme\"] else None\n    if theme is None:\n        formatter = HelpFormatter.settings(\n            theme=HelpTheme(**theme_settings),\n            **formatter_settings,\n        )\n    elif theme.lower() == \"dark\":\n        formatter = HelpFormatter.settings(\n            theme=HelpTheme.dark().with_(**theme_settings),\n            **formatter_settings,\n        )\n    elif theme.lower() == \"light\":\n        formatter = HelpFormatter.settings(\n            theme=HelpTheme.light().with_(**theme_settings),\n            **formatter_settings,\n        )\n\n    return_val: dict[str, Any] = Context.settings(\n        align_option_groups=parser[\"align_option_groups\"].lower() == \"true\",\n        align_sections=parser[\"align_sections\"].lower() == \"true\",\n        show_constraints=True,\n        formatter_settings=formatter,\n    )\n\n    return return_val\n"
  },
  {
    "path": "manim/_config/default.cfg",
    "content": "# manim.cfg\n# Default configuration for manim\n\n# Configure how manim behaves when called from the command line without\n# specifying any flags\n[CLI]\n\n# Each of the following will be set to True if the corresponding CLI flag\n# is present when executing manim.  If the flag is not present, they will\n# be set to the value found here.  For example, running manim with the -w\n# flag will set WRITE_TO_MOVIE to True.  However, since the default value\n# of WRITE_TO_MOVIE defined in this file is also True, running manim\n# without the -w value will also output a movie file.  To change that, set\n# WRITE_TO_MOVIE = False so that running manim without the -w flag will not\n# generate a movie file.  Note all of the following accept boolean values.\n\n# --notify_outdated_version\nnotify_outdated_version = True\n\n# -w, --write_to_movie\nwrite_to_movie = True\n\nformat = mp4\n\n# -s, --save_last_frame\n# setting save_last_frame to True forces write_to_movie to False\nsave_last_frame = False\n\n# -a, --write_all\nwrite_all = False\n\n# -g, --save_pngs\nsave_pngs = False\n\n# -0, --zero_pad\nzero_pad = 4\n\n# -i, --save_as_gif\nsave_as_gif = False\n\n# --save_sections\nsave_sections = False\n\n# -p, --preview\npreview = False\n\n# -f, --show_in_file_browser\nshow_in_file_browser = False\n\n# -v, --verbosity\nverbosity = INFO\n\n# --progress_bar\nprogress_bar = display\n\n# -o, --output_file\noutput_file =\n\n# --log_to_file\nlog_to_file = False\n\n# -c, --background_color\nbackground_color = BLACK\n\n# --background_opacity\nbackground_opacity = 1\n\n# The following two are both set by the -n (or --from_animation_number)\n# flag.  See manim -h for more information.\nfrom_animation_number = 0\n\n# Use -1 to render all animations\nupto_animation_number = -1\n\n# The following are meant to be paths relative to the point of execution.\n# Set them at the CLI with the corresponding flag, or set their default\n# values here.\n\n# --media_dir\nmedia_dir = ./media\n\n# --log_dir\nlog_dir = {media_dir}/logs\n\n# --assets_dir\nassets_dir = ./\n\n# the following do not have CLI arguments but depend on media_dir\nvideo_dir = {media_dir}/videos/{module_name}/{quality}\nsections_dir = {video_dir}/sections\nimages_dir = {media_dir}/images/{module_name}\ntex_dir = {media_dir}/Tex\ntext_dir = {media_dir}/texts\npartial_movie_dir = {video_dir}/partial_movie_files/{scene_name}\n\n# --renderer [cairo|opengl]\nrenderer = cairo\n\n# --enable_gui\nenable_gui = False\n\n# --gui_location\ngui_location = 0,0\n\n# --fullscreen\nfullscreen = False\n\n# \"Set the position of preview window. You can use directions, e.g. UL/DR/LEFT/ORIGIN\n# or the position (pixel) of the upper left corner of the window, e.g. '960,540'\",\n# --window_position\nwindow_position = UR\n\n# Manually adjust the size of the window, or use default to automatically scale the window based on\n# the dimensions of the monitor.\n# --window_size\nwindow_size = default\n\n# --window_monitor\nwindow_monitor = 0\n\n# --force_window\nforce_window = False\n\n# --use_projection_fill_shaders\nuse_projection_fill_shaders = False\n\n# --use_projection_stroke_shaders\nuse_projection_stroke_shaders = False\n\nmovie_file_extension = .mp4\n\n# These now override the --quality option.\nframe_rate = 60\npixel_height = 1080\npixel_width = 1920\n\n# Use -1 to set max_files_cached to infinity.\nmax_files_cached = 100\n#Flush cache will delete all the cached partial-movie-files.\nflush_cache = False\ndisable_caching = False\n# Disable the warning when there are too much submobjects to hash.\ndisable_caching_warning = False\n\n# --enable_wireframe\nenable_wireframe = False\n\n# --dry_run\ndry_run = False\n\n# Default tex_template\n# --tex_template\ntex_template =\n\n# specify the plugins as comma separated values\n# manim will load that plugin if it specified here.\nplugins =\n\n# CLI Context/Formatter\n# Visit the cloup documentation to understand the formatting options available:\n# https://cloup.readthedocs.io/en/latest/index.html#a-simple-example\n[CLI_CTX]\n# CTX settings\nalign_option_groups = True\nalign_sections = True\nshow_constraints = True\n\n# Formatter settings\nindent_increment = 2\nwidth = 80\ncol1_max_width = 30\ncol2_min_width = 35\ncol_spacing = 2\nrow_sep =\n\n# Dark/Light, or leave empty\ntheme =\n\n# Theme Settings - The following options override the theme colors.\ncommand_help =\ninvoked_command =\nheading =\nconstraint =\nsection_help =\ncol1 =\ncol2 =\nepilog =\n\n# Overrides the default output folders, NOT the output file names.  Note that\n# if the custom_folders flag is present, the Tex and text files will not be put\n# under media_dir, as is the default.\n[custom_folders]\nmedia_dir = videos\nvideo_dir = {media_dir}\nsections_dir = {media_dir}\nimages_dir = {media_dir}\ntext_dir = {media_dir}/temp_files\ntex_dir = {media_dir}/temp_files\nlog_dir = {media_dir}/temp_files\npartial_movie_dir = {media_dir}/partial_movie_files/{scene_name}\n\n# Rich settings\n[logger]\nlogging_keyword = bold yellow\nlogging_level_notset = dim\nlogging_level_debug = green\nlogging_level_info = green\nlogging_level_warning = red\nlogging_level_error = red bold\nlogging_level_critical = red bold reverse\nlog_level =\nlog_time = cyan dim\nlog_message =\nlog_path = dim\nlog_width = -1\nlog_height = -1\nlog_timestamps = True\nrepr_number = green\n\n[ffmpeg]\n# Uncomment the following line to manually set the loglevel for ffmpeg. See\n# ffmpeg manpage for accepted values\nloglevel = ERROR\n\n[jupyter]\nmedia_embed = False\nmedia_width = 60%%\n"
  },
  {
    "path": "manim/_config/logger_utils.py",
    "content": "\"\"\"Utilities to create and set the logger.\n\nManim's logger can be accessed as ``manim.logger``, or as\n``logging.getLogger(\"manim\")``, once the library has been imported.  Manim also\nexports a second object, ``console``, which should be used to print on screen\nmessages that need not be logged.\n\nBoth ``logger`` and ``console`` use the ``rich`` library to produce rich text\nformat.\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport configparser\nimport copy\nimport json\nimport logging\nfrom typing import TYPE_CHECKING, Any\n\nfrom rich import color, errors\nfrom rich import print as printf\nfrom rich.console import Console\nfrom rich.logging import RichHandler\nfrom rich.theme import Theme\n\nif TYPE_CHECKING:\n    from pathlib import Path\n\n__all__ = [\"make_logger\", \"parse_theme\", \"set_file_logger\", \"JSONFormatter\"]\n\nHIGHLIGHTED_KEYWORDS = [  # these keywords are highlighted specially\n    \"Played\",\n    \"animations\",\n    \"scene\",\n    \"Reading\",\n    \"Writing\",\n    \"script\",\n    \"arguments\",\n    \"Invalid\",\n    \"Aborting\",\n    \"module\",\n    \"File\",\n    \"Rendering\",\n    \"Rendered\",\n]\n\nWRONG_COLOR_CONFIG_MSG = \"\"\"\n[logging.level.error]Your colour configuration couldn't be parsed.\nLoading the default color configuration.[/logging.level.error]\n\"\"\"\n\n\ndef make_logger(\n    parser: configparser.SectionProxy,\n    verbosity: str,\n) -> tuple[logging.Logger, Console, Console]:\n    \"\"\"Make the manim logger and console.\n\n    Parameters\n    ----------\n    parser\n        A parser containing any .cfg files in use.\n\n    verbosity\n        The verbosity level of the logger.\n\n    Returns\n    -------\n    :class:`logging.Logger`, :class:`rich.Console`, :class:`rich.Console`\n        The manim logger and consoles. The first console outputs\n        to stdout, the second to stderr. All use the theme returned by\n        :func:`parse_theme`.\n\n    See Also\n    --------\n    :func:`~._config.utils.make_config_parser`, :func:`parse_theme`\n\n    Notes\n    -----\n    The ``parser`` is assumed to contain only the options related to\n    configuring the logger at the top level.\n\n    \"\"\"\n    # Throughout the codebase, use console.print() instead of print()\n    theme = parse_theme(parser)\n    console = Console(theme=theme)\n\n    error_console = Console(theme=theme, stderr=True)\n\n    # set the rich handler\n    rich_handler = RichHandler(\n        console=console,\n        show_time=parser.getboolean(\"log_timestamps\", fallback=False),\n        keywords=HIGHLIGHTED_KEYWORDS,\n    )\n\n    # finally, the logger\n    logger = logging.getLogger(\"manim\")\n    logger.addHandler(rich_handler)\n    logger.setLevel(verbosity)\n    logger.propagate = False\n\n    if not (libav_logger := logging.getLogger()).hasHandlers():\n        libav_logger.addHandler(rich_handler)\n        libav_logger.setLevel(verbosity)\n\n    return logger, console, error_console\n\n\ndef parse_theme(parser: configparser.SectionProxy) -> Theme | None:\n    \"\"\"Configure the rich style of logger and console output.\n\n    Parameters\n    ----------\n    parser\n        A parser containing any .cfg files in use.\n\n    Returns\n    -------\n    :class:`rich.Theme`\n        The rich theme to be used by the manim logger.\n\n    See Also\n    --------\n    :func:`make_logger`.\n\n    \"\"\"\n    theme: dict[str, Any] = {key.replace(\"_\", \".\"): parser[key] for key in parser}\n\n    theme[\"log.width\"] = None if theme[\"log.width\"] == \"-1\" else int(theme[\"log.width\"])\n    theme[\"log.height\"] = (\n        None if theme[\"log.height\"] == \"-1\" else int(theme[\"log.height\"])\n    )\n    theme[\"log.timestamps\"] = False\n    try:\n        custom_theme = Theme(\n            {\n                k: v\n                for k, v in theme.items()\n                if k not in [\"log.width\", \"log.height\", \"log.timestamps\"]\n            },\n        )\n    except (color.ColorParseError, errors.StyleSyntaxError):\n        printf(WRONG_COLOR_CONFIG_MSG)\n        custom_theme = None\n\n    return custom_theme\n\n\ndef set_file_logger(scene_name: str, module_name: str, log_dir: Path) -> None:\n    \"\"\"Add a file handler to manim logger.\n\n    The path to the file is built using ``config.log_dir``.\n\n    Parameters\n    ----------\n    scene_name\n        The name of the scene, used in the name of the log file.\n    module_name\n        The name of the module, used in the name of the log file.\n    log_dir\n        Path to the folder where log files are stored.\n    \"\"\"\n    # Note: The log file name will be\n    # <name_of_animation_file>_<name_of_scene>.log, gotten from config.  So it\n    # can differ from the real name of the scene.  <name_of_scene> would only\n    # appear if scene name was provided when manim was called.\n    log_file_name = f\"{module_name}_{scene_name}.log\"\n    log_file_path = log_dir / log_file_name\n\n    file_handler = logging.FileHandler(log_file_path, mode=\"w\")\n    file_handler.setFormatter(JSONFormatter())\n\n    logger = logging.getLogger(\"manim\")\n    logger.addHandler(file_handler)\n    logger.info(\"Log file will be saved in %(logpath)s\", {\"logpath\": log_file_path})\n\n\nclass JSONFormatter(logging.Formatter):\n    \"\"\"A formatter that outputs logs in a custom JSON format.\n\n    This class is used internally for testing purposes.\n\n    \"\"\"\n\n    def format(self, record: logging.LogRecord) -> str:\n        \"\"\"Format the record in a custom JSON format.\"\"\"\n        record_c = copy.deepcopy(record)\n        if record_c.args:\n            if isinstance(record_c.args, dict):\n                for arg in record_c.args:\n                    record_c.args[arg] = \"<>\"\n            else:\n                record_c.args = (\"<>\",) * len(record_c.args)\n        return json.dumps(\n            {\n                \"levelname\": record_c.levelname,\n                \"module\": record_c.module,\n                \"message\": super().format(record_c),\n            },\n        )\n"
  },
  {
    "path": "manim/_config/utils.py",
    "content": "\"\"\"Utilities to create and set the config.\n\nThe main class exported by this module is :class:`ManimConfig`.  This class\ncontains all configuration options, including frame geometry (e.g. frame\nheight/width, frame rate), output (e.g. directories, logging), styling\n(e.g. background color, transparency), and general behavior (e.g. writing a\nmovie vs writing a single frame).\n\nSee :doc:`/guides/configuration` for an introduction to Manim's configuration system.\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport configparser\nimport copy\nimport errno\nimport logging\nimport os\nimport re\nimport sys\nfrom collections.abc import Iterator, Mapping, MutableMapping\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, Any, ClassVar, NoReturn\n\nimport numpy as np\n\nfrom manim import constants\nfrom manim.constants import RendererType\nfrom manim.utils.color import ManimColor\nfrom manim.utils.tex import TexTemplate\n\nif TYPE_CHECKING:\n    from enum import EnumMeta\n    from typing import Self\n\n    from manim.typing import StrPath, Vector3D\n\n__all__ = [\"config_file_paths\", \"make_config_parser\", \"ManimConfig\", \"ManimFrame\"]\n\nlogger = logging.getLogger(\"manim\")\n\n\ndef config_file_paths() -> list[Path]:\n    \"\"\"The paths where ``.cfg`` files will be searched for.\n\n    When manim is first imported, it processes any ``.cfg`` files it finds.  This\n    function returns the locations in which these files are searched for.  In\n    ascending order of precedence, these are: the library-wide config file, the\n    user-wide config file, and the folder-wide config file.\n\n    The library-wide config file determines manim's default behavior.  The\n    user-wide config file is stored in the user's home folder, and determines\n    the behavior of manim whenever the user invokes it from anywhere in the\n    system.  The folder-wide config file only affects scenes that are in the\n    same folder.  The latter two files are optional.\n\n    These files, if they exist, are meant to loaded into a single\n    :class:`configparser.ConfigParser` object, and then processed by\n    :class:`ManimConfig`.\n\n    Returns\n    -------\n    List[:class:`Path`]\n        List of paths which may contain ``.cfg`` files, in ascending order of\n        precedence.\n\n    See Also\n    --------\n    :func:`make_config_parser`, :meth:`ManimConfig.digest_file`,\n    :meth:`ManimConfig.digest_parser`\n\n    Notes\n    -----\n    The location of the user-wide config file is OS-specific.\n\n    \"\"\"\n    library_wide = Path.resolve(Path(__file__).parent / \"default.cfg\")\n    if sys.platform.startswith(\"win32\"):\n        user_wide = Path.home() / \"AppData\" / \"Roaming\" / \"Manim\" / \"manim.cfg\"\n    else:\n        user_wide = Path.home() / \".config\" / \"manim\" / \"manim.cfg\"\n    folder_wide = Path(\"manim.cfg\")\n    return [library_wide, user_wide, folder_wide]\n\n\ndef make_config_parser(\n    custom_file: StrPath | None = None,\n) -> configparser.ConfigParser:\n    \"\"\"Make a :class:`ConfigParser` object and load any ``.cfg`` files.\n\n    The user-wide file, if it exists, overrides the library-wide file.  The\n    folder-wide file, if it exists, overrides the other two.\n\n    The folder-wide file can be ignored by passing ``custom_file``.  However,\n    the user-wide and library-wide config files cannot be ignored.\n\n    Parameters\n    ----------\n    custom_file\n        Path to a custom config file.  If used, the folder-wide file in the\n        relevant directory will be ignored, if it exists.  If None, the\n        folder-wide file will be used, if it exists.\n\n    Returns\n    -------\n    :class:`ConfigParser`\n        A parser containing the config options found in the .cfg files that\n        were found.  It is guaranteed to contain at least the config options\n        found in the library-wide file.\n\n    See Also\n    --------\n    :func:`config_file_paths`\n\n    \"\"\"\n    library_wide, user_wide, folder_wide = config_file_paths()\n    # From the documentation: \"An application which requires initial values to\n    # be loaded from a file should load the required file or files using\n    # read_file() before calling read() for any optional files.\"\n    # https://docs.python.org/3/library/configparser.html#configparser.ConfigParser.read\n    parser = configparser.ConfigParser()\n    logger.info(f\"Reading config file: {library_wide}\")\n    with library_wide.open() as file:\n        parser.read_file(file)  # necessary file\n\n    other_files = [user_wide, Path(custom_file) if custom_file else folder_wide]\n    for path in other_files:\n        if path.exists():\n            logger.info(f\"Reading config file: {path}\")\n    parser.read(other_files)  # optional files\n\n    return parser\n\n\ndef _determine_quality(qual: str | None) -> str:\n    for quality, values in constants.QUALITIES.items():\n        if values[\"flag\"] is not None and values[\"flag\"] == qual:\n            return quality\n\n    return qual\n\n\nclass ManimConfig(MutableMapping):\n    \"\"\"Dict-like class storing all config options.\n\n    The global ``config`` object is an instance of this class, and acts as a\n    single source of truth for all of the library's customizable behavior.\n\n    The global ``config`` object is capable of digesting different types of\n    sources and converting them into a uniform interface.  These sources are\n    (in ascending order of precedence): configuration files, command line\n    arguments, and programmatic changes.  Regardless of how the user chooses to\n    set a config option, she can access its current value using\n    :class:`ManimConfig`'s attributes and properties.\n\n    Notes\n    -----\n    Each config option is implemented as a property of this class.\n\n    Each config option can be set via a config file, using the full name of the\n    property.  If a config option has an associated CLI flag, then the flag is\n    equal to the full name of the property.  Those that admit an alternative\n    flag or no flag at all are documented in the individual property's\n    docstring.\n\n    Examples\n    --------\n    We use a copy of the global configuration object in the following\n    examples for the sake of demonstration; you can skip these lines\n    and just import ``config`` directly if you actually want to modify\n    the configuration:\n\n    .. code-block:: pycon\n\n        >>> from manim import config as global_config\n        >>> config = global_config.copy()\n\n    Each config option allows for dict syntax and attribute syntax.  For\n    example, the following two lines are equivalent,\n\n    .. code-block:: pycon\n\n        >>> from manim import WHITE\n        >>> config.background_color = WHITE\n        >>> config[\"background_color\"] = WHITE\n\n    The former is preferred; the latter is provided mostly for backwards\n    compatibility.\n\n    The config options are designed to keep internal consistency.  For example,\n    setting ``frame_y_radius`` will affect ``frame_height``:\n\n    .. code-block:: pycon\n\n        >>> config.frame_height\n        8.0\n        >>> config.frame_y_radius = 5.0\n        >>> config.frame_height\n        10.0\n\n    There are many ways of interacting with config options.  Take for example\n    the config option ``background_color``.  There are three ways to change it:\n    via a config file, via CLI flags, or programmatically.\n\n    To set the background color via a config file, save the following\n    ``manim.cfg`` file with the following contents.\n\n    .. code-block::\n\n       [CLI]\n       background_color = WHITE\n\n    In order to have this ``.cfg`` file apply to a manim scene, it needs to be\n    placed in the same directory as the script,\n\n    .. code-block:: bash\n\n          project/\n          ├─scene.py\n          └─manim.cfg\n\n    Now, when the user executes\n\n    .. code-block:: bash\n\n        manim scene.py\n\n    the background of the scene will be set to ``WHITE``.  This applies regardless\n    of where the manim command is invoked from.\n\n    Command line arguments override ``.cfg`` files.  In the previous example,\n    executing\n\n    .. code-block:: bash\n\n        manim scene.py -c BLUE\n\n    will set the background color to BLUE, regardless of the contents of\n    ``manim.cfg``.\n\n    Finally, any programmatic changes made within the scene script itself will\n    override the command line arguments.  For example, if ``scene.py`` contains\n    the following\n\n    .. code-block:: python\n\n        from manim import *\n\n        config.background_color = RED\n\n\n        class MyScene(Scene): ...\n\n    the background color will be set to RED, regardless of the contents of\n    ``manim.cfg`` or the CLI arguments used when invoking manim.\n\n    \"\"\"\n\n    _OPTS = {\n        \"assets_dir\",\n        \"background_color\",\n        \"background_opacity\",\n        \"custom_folders\",\n        \"disable_caching\",\n        \"disable_caching_warning\",\n        \"dry_run\",\n        \"enable_wireframe\",\n        \"ffmpeg_loglevel\",\n        \"format\",\n        \"flush_cache\",\n        \"frame_height\",\n        \"frame_rate\",\n        \"frame_width\",\n        \"frame_x_radius\",\n        \"frame_y_radius\",\n        \"from_animation_number\",\n        \"images_dir\",\n        \"input_file\",\n        \"media_embed\",\n        \"media_width\",\n        \"log_dir\",\n        \"log_to_file\",\n        \"max_files_cached\",\n        \"media_dir\",\n        \"movie_file_extension\",\n        \"notify_outdated_version\",\n        \"output_file\",\n        \"partial_movie_dir\",\n        \"pixel_height\",\n        \"pixel_width\",\n        \"plugins\",\n        \"preview\",\n        \"progress_bar\",\n        \"quality\",\n        \"save_as_gif\",\n        \"save_sections\",\n        \"save_last_frame\",\n        \"save_pngs\",\n        \"scene_names\",\n        \"seed\",\n        \"show_in_file_browser\",\n        \"tex_dir\",\n        \"tex_template\",\n        \"tex_template_file\",\n        \"text_dir\",\n        \"upto_animation_number\",\n        \"renderer\",\n        \"enable_gui\",\n        \"gui_location\",\n        \"use_projection_fill_shaders\",\n        \"use_projection_stroke_shaders\",\n        \"verbosity\",\n        \"video_dir\",\n        \"sections_dir\",\n        \"fullscreen\",\n        \"window_position\",\n        \"window_size\",\n        \"window_monitor\",\n        \"write_all\",\n        \"write_to_movie\",\n        \"zero_pad\",\n        \"force_window\",\n        \"no_latex_cleanup\",\n        \"preview_command\",\n    }\n\n    def __init__(self) -> None:\n        self._d: dict[str, Any | None] = dict.fromkeys(self._OPTS)\n\n    # behave like a dict\n    def __iter__(self) -> Iterator[str]:\n        return iter(self._d)\n\n    def __len__(self) -> int:\n        return len(self._d)\n\n    def __contains__(self, key: object) -> bool:\n        try:\n            assert isinstance(key, str)\n            self.__getitem__(key)\n            return True\n        except AttributeError:\n            return False\n\n    def __getitem__(self, key: str) -> Any:\n        return getattr(self, key)\n\n    def __setitem__(self, key: str, val: Any) -> None:\n        getattr(ManimConfig, key).fset(self, val)  # fset is the property's setter\n\n    def update(self, obj: ManimConfig | dict[str, Any]) -> None:  # type: ignore[override]\n        \"\"\"Digest the options found in another :class:`ManimConfig` or in a dict.\n\n        Similar to :meth:`dict.update`, replaces the values of this object with\n        those of ``obj``.\n\n        Parameters\n        ----------\n        obj\n            The object to copy values from.\n\n        Returns\n        -------\n        None\n\n        Raises\n        -----\n        :class:`AttributeError`\n            If ``obj`` is a dict but contains keys that do not belong to any\n            config options.\n\n        See Also\n        --------\n        :meth:`~ManimConfig.digest_file`, :meth:`~ManimConfig.digest_args`,\n        :meth:`~ManimConfig.digest_parser`\n\n        \"\"\"\n        if isinstance(obj, ManimConfig):\n            self._d.update(obj._d)\n            if obj.tex_template:\n                self.tex_template = obj.tex_template\n\n        elif isinstance(obj, dict):\n            # First update the underlying _d, then update other properties\n            _dict = {k: v for k, v in obj.items() if k in self._d}\n            for k, v in _dict.items():\n                self[k] = v\n\n            _dict = {k: v for k, v in obj.items() if k not in self._d}\n            for k, v in _dict.items():\n                self[k] = v\n\n    # don't allow to delete anything\n    def __delitem__(self, key: str) -> NoReturn:\n        raise AttributeError(\"'ManimConfig' object does not support item deletion\")\n\n    def __delattr__(self, key: str) -> NoReturn:\n        raise AttributeError(\"'ManimConfig' object does not support item deletion\")\n\n    # copy functions\n    def copy(self) -> Self:\n        \"\"\"Deepcopy the contents of this ManimConfig.\n\n        Returns\n        -------\n        :class:`ManimConfig`\n            A copy of this object containing no shared references.\n\n        See Also\n        --------\n        :func:`tempconfig`\n\n        Notes\n        -----\n        This is the main mechanism behind :func:`tempconfig`.\n\n        \"\"\"\n        return copy.deepcopy(self)\n\n    def __copy__(self) -> Self:\n        \"\"\"See ManimConfig.copy().\"\"\"\n        return copy.deepcopy(self)\n\n    def __deepcopy__(self, memo: dict[str, Any]) -> Self:\n        \"\"\"See ManimConfig.copy().\"\"\"\n        c = type(self)()\n        # Deepcopying the underlying dict is enough because all properties\n        # either read directly from it or compute their value on the fly from\n        # values read directly from it.\n        c._d = copy.deepcopy(self._d, memo)  # type: ignore[arg-type]\n        return c\n\n    # helper type-checking methods\n    def _set_from_list(self, key: str, val: Any, values: list[Any]) -> None:\n        \"\"\"Set ``key`` to ``val`` if ``val`` is contained in ``values``.\"\"\"\n        if val in values:\n            self._d[key] = val\n        else:\n            raise ValueError(f\"attempted to set {key} to {val}; must be in {values}\")\n\n    def _set_from_enum(self, key: str, enum_value: Any, enum_class: EnumMeta) -> None:\n        \"\"\"Set ``key`` to the enum object with value ``enum_value`` in the given\n        ``enum_class``.\n\n        Tests::\n\n            >>> from enum import Enum\n            >>> class Fruit(Enum):\n            ...     APPLE = 1\n            ...     BANANA = 2\n            ...     CANTALOUPE = 3\n            >>> test_config = ManimConfig()\n            >>> test_config._set_from_enum(\"fruit\", 1, Fruit)\n            >>> test_config._d['fruit']\n            <Fruit.APPLE: 1>\n            >>> test_config._set_from_enum(\"fruit\", Fruit.BANANA, Fruit)\n            >>> test_config._d['fruit']\n            <Fruit.BANANA: 2>\n            >>> test_config._set_from_enum(\"fruit\", 42, Fruit)\n            Traceback (most recent call last):\n            ...\n            ValueError: 42 is not a valid Fruit\n        \"\"\"\n        self._d[key] = enum_class(enum_value)\n\n    def _set_boolean(self, key: str, val: Any) -> None:\n        \"\"\"Set ``key`` to ``val`` if ``val`` is Boolean.\"\"\"\n        if val in [True, False]:\n            self._d[key] = val\n        else:\n            raise ValueError(f\"{key} must be boolean\")\n\n    def _set_tuple(self, key: str, val: tuple[Any]) -> None:\n        if isinstance(val, tuple):\n            self._d[key] = val\n        else:\n            raise ValueError(f\"{key} must be tuple\")\n\n    def _set_str(self, key: str, val: Any) -> None:\n        \"\"\"Set ``key`` to ``val`` if ``val`` is a string.\"\"\"\n        if isinstance(val, str):\n            self._d[key] = val\n        elif not val:\n            self._d[key] = \"\"\n        else:\n            raise ValueError(f\"{key} must be str or falsy value\")\n\n    def _set_between(self, key: str, val: float, lo: float, hi: float) -> None:\n        \"\"\"Set ``key`` to ``val`` if lo <= val <= hi.\"\"\"\n        if lo <= val <= hi:\n            self._d[key] = val\n        else:\n            raise ValueError(f\"{key} must be {lo} <= {key} <= {hi}\")\n\n    def _set_int_between(self, key: str, val: int, lo: int, hi: int) -> None:\n        \"\"\"Set ``key`` to ``val`` if lo <= val <= hi.\"\"\"\n        if lo <= val <= hi:\n            self._d[key] = val\n        else:\n            raise ValueError(\n                f\"{key} must be an integer such that {lo} <= {key} <= {hi}\",\n            )\n\n    def _set_pos_number(self, key: str, val: int, allow_inf: bool) -> None:\n        \"\"\"Set ``key`` to ``val`` if ``val`` is a positive integer.\"\"\"\n        if isinstance(val, int) and val > -1:\n            self._d[key] = val\n        elif allow_inf and val in [-1, float(\"inf\")]:\n            self._d[key] = float(\"inf\")\n        else:\n            raise ValueError(\n                f\"{key} must be a non-negative integer (use -1 for infinity)\",\n            )\n\n    def __repr__(self) -> str:\n        rep = \"\"\n        for k, v in sorted(self._d.items(), key=lambda x: x[0]):\n            rep += f\"{k}: {v}, \"\n        return rep\n\n    # builders\n    def digest_parser(self, parser: configparser.ConfigParser) -> Self:\n        \"\"\"Process the config options present in a :class:`ConfigParser` object.\n\n        This method processes arbitrary parsers, not only those read from a\n        single file, whereas :meth:`~ManimConfig.digest_file` can only process one\n        file at a time.\n\n        Parameters\n        ----------\n        parser\n            An object reflecting the contents of one or many ``.cfg`` files.  In\n            particular, it may reflect the contents of multiple files that have\n            been parsed in a cascading fashion.\n\n        Returns\n        -------\n        self : :class:`ManimConfig`\n            This object, after processing the contents of ``parser``.\n\n        See Also\n        --------\n        :func:`make_config_parser`, :meth:`~.ManimConfig.digest_file`,\n        :meth:`~.ManimConfig.digest_args`,\n\n        Notes\n        -----\n        If there are multiple ``.cfg`` files to process, it is always more\n        efficient to parse them into a single :class:`ConfigParser` object\n        first, and then call this function once (instead of calling\n        :meth:`~.ManimConfig.digest_file` multiple times).\n\n        Examples\n        --------\n        To digest the config options set in two files, first create a\n        ConfigParser and parse both files and then digest the parser:\n\n        .. code-block:: python\n\n            parser = configparser.ConfigParser()\n            parser.read([file1, file2])\n            config = ManimConfig().digest_parser(parser)\n\n        In fact, the global ``config`` object is initialized like so:\n\n        .. code-block:: python\n\n            parser = make_config_parser()\n            config = ManimConfig().digest_parser(parser)\n\n        \"\"\"\n        self._parser = parser\n\n        # boolean keys\n        for key in [\n            \"notify_outdated_version\",\n            \"write_to_movie\",\n            \"save_last_frame\",\n            \"write_all\",\n            \"save_pngs\",\n            \"save_as_gif\",\n            \"save_sections\",\n            \"preview\",\n            \"show_in_file_browser\",\n            \"log_to_file\",\n            \"disable_caching\",\n            \"disable_caching_warning\",\n            \"flush_cache\",\n            \"custom_folders\",\n            \"enable_gui\",\n            \"fullscreen\",\n            \"use_projection_fill_shaders\",\n            \"use_projection_stroke_shaders\",\n            \"enable_wireframe\",\n            \"force_window\",\n            \"no_latex_cleanup\",\n            \"dry_run\",\n        ]:\n            setattr(self, key, parser[\"CLI\"].getboolean(key, fallback=False))\n\n        # int keys\n        for key in [\n            \"from_animation_number\",\n            \"upto_animation_number\",\n            \"max_files_cached\",\n            # the next two must be set BEFORE digesting frame_width and frame_height\n            \"pixel_height\",\n            \"pixel_width\",\n            \"seed\",\n            \"window_monitor\",\n            \"zero_pad\",\n        ]:\n            setattr(self, key, parser[\"CLI\"].getint(key))\n\n        # str keys\n        for key in [\n            \"assets_dir\",\n            \"verbosity\",\n            \"media_dir\",\n            \"log_dir\",\n            \"video_dir\",\n            \"sections_dir\",\n            \"images_dir\",\n            \"text_dir\",\n            \"tex_dir\",\n            \"partial_movie_dir\",\n            \"input_file\",\n            \"output_file\",\n            \"movie_file_extension\",\n            \"background_color\",\n            \"renderer\",\n            \"window_position\",\n            \"preview_command\",\n        ]:\n            setattr(self, key, parser[\"CLI\"].get(key, fallback=\"\", raw=True))\n\n        # float keys\n        for key in [\n            \"background_opacity\",\n            \"frame_rate\",\n            # the next two are floats but have their own logic, applied later\n            # \"frame_width\",\n            # \"frame_height\",\n        ]:\n            setattr(self, key, parser[\"CLI\"].getfloat(key))\n\n        # tuple keys\n        gui_location = tuple(\n            map(int, re.split(r\"[;,\\-]\", parser[\"CLI\"][\"gui_location\"])),\n        )\n        self.gui_location = gui_location\n\n        window_size = parser[\"CLI\"][\n            \"window_size\"\n        ]  # if not \"default\", get a tuple of the position\n        if window_size != \"default\":\n            window_size_numbers = tuple(map(int, re.split(r\"[;,\\-]\", window_size)))\n            self.window_size = window_size_numbers\n        else:\n            self.window_size = window_size\n\n        # plugins\n        plugins = parser[\"CLI\"].get(\"plugins\", fallback=\"\", raw=True)\n        plugin_list = [] if plugins is None or plugins == \"\" else plugins.split(\",\")\n        self.plugins = plugin_list\n        # the next two must be set AFTER digesting pixel_width and pixel_height\n        self[\"frame_height\"] = parser[\"CLI\"].getfloat(\"frame_height\", 8.0)\n        width = parser[\"CLI\"].getfloat(\"frame_width\", None)\n        if width is None:\n            self[\"frame_width\"] = self[\"frame_height\"] * self[\"aspect_ratio\"]\n        else:\n            self[\"frame_width\"] = width\n\n        # other logic\n        tex_template_file = parser[\"CLI\"].get(\"tex_template_file\")\n        if tex_template_file:\n            self.tex_template_file = Path(tex_template_file)\n\n        progress_bar = parser[\"CLI\"].get(\"progress_bar\")\n        if progress_bar:\n            self.progress_bar = progress_bar\n\n        ffmpeg_loglevel = parser[\"ffmpeg\"].get(\"loglevel\")\n        if ffmpeg_loglevel:\n            self.ffmpeg_loglevel = ffmpeg_loglevel\n\n        try:\n            media_embed = parser[\"jupyter\"].getboolean(\"media_embed\")\n        except ValueError:\n            media_embed = None\n        self.media_embed = media_embed\n\n        media_width = parser[\"jupyter\"].get(\"media_width\")\n        if media_width:\n            self.media_width = media_width\n\n        quality = parser[\"CLI\"].get(\"quality\", fallback=\"\", raw=True)\n        if quality:\n            self.quality = _determine_quality(quality)\n\n        return self\n\n    def digest_args(self, args: argparse.Namespace) -> Self:\n        \"\"\"Process the config options present in CLI arguments.\n\n        Parameters\n        ----------\n        args\n            An object returned by :func:`.main_utils.parse_args()`.\n\n        Returns\n        -------\n        self : :class:`ManimConfig`\n            This object, after processing the contents of ``parser``.\n\n        See Also\n        --------\n        :func:`.main_utils.parse_args()`, :meth:`~.ManimConfig.digest_parser`,\n        :meth:`~.ManimConfig.digest_file`\n\n        Notes\n        -----\n        If ``args.config_file`` is a non-empty string, ``ManimConfig`` tries to digest the\n        contents of said file with :meth:`~ManimConfig.digest_file` before\n        digesting any other CLI arguments.\n\n        \"\"\"\n        # if the input file is a config file, parse it properly\n        if args.file.suffix == \".cfg\":\n            args.config_file = args.file\n\n        # if args.file is `-`, the animation code has to be taken from STDIN, so the\n        # input file path shouldn't be absolute, since that file won't be read.\n        if str(args.file) == \"-\":\n            self.input_file = args.file\n\n        # if a config file has been passed, digest it first so that other CLI\n        # flags supersede it\n        if args.config_file:\n            self.digest_file(args.config_file)\n\n        # read input_file from the args if it wasn't set by the config file\n        if not self.input_file:\n            self.input_file = Path(args.file).absolute()\n\n        self.scene_names = args.scene_names if args.scene_names is not None else []\n        self.output_file = args.output_file\n\n        for key in [\n            \"notify_outdated_version\",\n            \"preview\",\n            \"show_in_file_browser\",\n            \"write_to_movie\",\n            \"save_last_frame\",\n            \"save_pngs\",\n            \"save_as_gif\",\n            \"save_sections\",\n            \"write_all\",\n            \"disable_caching\",\n            \"format\",\n            \"flush_cache\",\n            \"progress_bar\",\n            \"transparent\",\n            \"scene_names\",\n            \"verbosity\",\n            \"renderer\",\n            \"background_color\",\n            \"enable_gui\",\n            \"fullscreen\",\n            \"use_projection_fill_shaders\",\n            \"use_projection_stroke_shaders\",\n            \"zero_pad\",\n            \"enable_wireframe\",\n            \"force_window\",\n            \"dry_run\",\n            \"no_latex_cleanup\",\n            \"preview_command\",\n            \"seed\",\n        ]:\n            if hasattr(args, key):\n                attr = getattr(args, key)\n                # if attr is None, then no argument was passed and we should\n                # not change the current config\n                if attr is not None:\n                    self[key] = attr\n\n        for key in [\n            \"media_dir\",  # always set this one first\n            \"log_dir\",\n            \"log_to_file\",  # always set this one last\n        ]:\n            if hasattr(args, key):\n                attr = getattr(args, key)\n                # if attr is None, then no argument was passed and we should\n                # not change the current config\n                if attr is not None:\n                    self[key] = attr\n\n        if self[\"save_last_frame\"]:\n            self[\"write_to_movie\"] = False\n\n        # Handle the -n flag.\n        nflag = args.from_animation_number\n        if nflag:\n            self.from_animation_number = nflag[0]\n            try:\n                self.upto_animation_number = nflag[1]\n            except Exception:\n                logger.info(\n                    f\"No end scene number specified in -n option. Rendering from {nflag[0]} onwards...\",\n                )\n\n        # Handle the quality flags\n        self.quality = _determine_quality(getattr(args, \"quality\", None))\n\n        # Handle the -r flag.\n        rflag = args.resolution\n        if rflag:\n            self.pixel_width = int(rflag[0])\n            self.pixel_height = int(rflag[1])\n\n        fps = args.frame_rate\n        if fps:\n            self.frame_rate = float(fps)\n\n        # Handle --custom_folders\n        if args.custom_folders:\n            for opt in [\n                \"media_dir\",\n                \"video_dir\",\n                \"sections_dir\",\n                \"images_dir\",\n                \"text_dir\",\n                \"tex_dir\",\n                \"log_dir\",\n                \"partial_movie_dir\",\n            ]:\n                self[opt] = self._parser[\"custom_folders\"].get(opt, raw=True)\n            # --media_dir overrides the default.cfg file\n            if hasattr(args, \"media_dir\") and args.media_dir:\n                self.media_dir = args.media_dir\n\n        # Handle --tex_template\n        if args.tex_template:\n            self.tex_template = TexTemplate.from_file(args.tex_template)\n\n        if self.renderer == RendererType.OPENGL and args.write_to_movie is None:\n            # --write_to_movie was not passed on the command line, so don't generate video.\n            self[\"write_to_movie\"] = False\n\n        # Handle --gui_location flag.\n        if args.gui_location is not None:\n            self.gui_location = args.gui_location\n\n        return self\n\n    def digest_file(self, filename: StrPath) -> Self:\n        \"\"\"Process the config options present in a ``.cfg`` file.\n\n        This method processes a single ``.cfg`` file, whereas\n        :meth:`~ManimConfig.digest_parser` can process arbitrary parsers, built\n        perhaps from multiple ``.cfg`` files.\n\n        Parameters\n        ----------\n        filename\n            Path to the ``.cfg`` file.\n\n        Returns\n        -------\n        self : :class:`ManimConfig`\n            This object, after processing the contents of ``filename``.\n\n        See Also\n        --------\n        :meth:`~ManimConfig.digest_file`, :meth:`~ManimConfig.digest_args`,\n        :func:`make_config_parser`\n\n        Notes\n        -----\n        If there are multiple ``.cfg`` files to process, it is always more\n        efficient to parse them into a single :class:`ConfigParser` object\n        first and digesting them with one call to\n        :meth:`~ManimConfig.digest_parser`, instead of calling this method\n        multiple times.\n\n        \"\"\"\n        if not Path(filename).is_file():\n            raise FileNotFoundError(\n                errno.ENOENT,\n                \"Error: --config_file could not find a valid config file.\",\n                str(filename),\n            )\n\n        return self.digest_parser(make_config_parser(filename))\n\n    # config options are properties\n\n    @property\n    def preview(self) -> bool:\n        \"\"\"Whether to play the rendered movie (-p).\"\"\"\n        return self._d[\"preview\"] or self._d[\"enable_gui\"]\n\n    @preview.setter\n    def preview(self, value: bool) -> None:\n        self._set_boolean(\"preview\", value)\n\n    @property\n    def show_in_file_browser(self) -> bool:\n        \"\"\"Whether to show the output file in the file browser (-f).\"\"\"\n        return self._d[\"show_in_file_browser\"]\n\n    @show_in_file_browser.setter\n    def show_in_file_browser(self, value: bool) -> None:\n        self._set_boolean(\"show_in_file_browser\", value)\n\n    @property\n    def progress_bar(self) -> str:\n        \"\"\"Whether to show progress bars while rendering animations.\"\"\"\n        return self._d[\"progress_bar\"]\n\n    @progress_bar.setter\n    def progress_bar(self, value: str) -> None:\n        self._set_from_list(\"progress_bar\", value, [\"none\", \"display\", \"leave\"])\n\n    @property\n    def log_to_file(self) -> bool:\n        \"\"\"Whether to save logs to a file.\"\"\"\n        return self._d[\"log_to_file\"]\n\n    @log_to_file.setter\n    def log_to_file(self, value: bool) -> None:\n        self._set_boolean(\"log_to_file\", value)\n\n    @property\n    def notify_outdated_version(self) -> bool:\n        \"\"\"Whether to notify if there is a version update available.\"\"\"\n        return self._d[\"notify_outdated_version\"]\n\n    @notify_outdated_version.setter\n    def notify_outdated_version(self, value: bool) -> None:\n        self._set_boolean(\"notify_outdated_version\", value)\n\n    @property\n    def write_to_movie(self) -> bool:\n        \"\"\"Whether to render the scene to a movie file (-w).\"\"\"\n        return self._d[\"write_to_movie\"]\n\n    @write_to_movie.setter\n    def write_to_movie(self, value: bool) -> None:\n        self._set_boolean(\"write_to_movie\", value)\n\n    @property\n    def save_last_frame(self) -> bool:\n        \"\"\"Whether to save the last frame of the scene as an image file (-s).\"\"\"\n        return self._d[\"save_last_frame\"]\n\n    @save_last_frame.setter\n    def save_last_frame(self, value: bool) -> None:\n        self._set_boolean(\"save_last_frame\", value)\n\n    @property\n    def write_all(self) -> bool:\n        \"\"\"Whether to render all scenes in the input file (-a).\"\"\"\n        return self._d[\"write_all\"]\n\n    @write_all.setter\n    def write_all(self, value: bool) -> None:\n        self._set_boolean(\"write_all\", value)\n\n    @property\n    def save_pngs(self) -> bool:\n        \"\"\"Whether to save all frames in the scene as images files (-g).\"\"\"\n        return self._d[\"save_pngs\"]\n\n    @save_pngs.setter\n    def save_pngs(self, value: bool) -> None:\n        self._set_boolean(\"save_pngs\", value)\n\n    @property\n    def save_as_gif(self) -> bool:\n        \"\"\"Whether to save the rendered scene in .gif format (-i).\"\"\"\n        return self._d[\"save_as_gif\"]\n\n    @save_as_gif.setter\n    def save_as_gif(self, value: bool) -> None:\n        self._set_boolean(\"save_as_gif\", value)\n\n    @property\n    def save_sections(self) -> bool:\n        \"\"\"Whether to save single videos for each section in addition to the movie file.\"\"\"\n        return self._d[\"save_sections\"]\n\n    @save_sections.setter\n    def save_sections(self, value: bool) -> None:\n        self._set_boolean(\"save_sections\", value)\n\n    @property\n    def enable_wireframe(self) -> bool:\n        \"\"\"Whether to enable wireframe debugging mode in opengl.\"\"\"\n        return self._d[\"enable_wireframe\"]\n\n    @enable_wireframe.setter\n    def enable_wireframe(self, value: bool) -> None:\n        self._set_boolean(\"enable_wireframe\", value)\n\n    @property\n    def force_window(self) -> bool:\n        \"\"\"Whether to force window when using the opengl renderer.\"\"\"\n        return self._d[\"force_window\"]\n\n    @force_window.setter\n    def force_window(self, value: bool) -> None:\n        self._set_boolean(\"force_window\", value)\n\n    @property\n    def no_latex_cleanup(self) -> bool:\n        \"\"\"Prevents deletion of .aux, .dvi, and .log files produced by Tex and MathTex.\"\"\"\n        return self._d[\"no_latex_cleanup\"]\n\n    @no_latex_cleanup.setter\n    def no_latex_cleanup(self, value: bool) -> None:\n        self._set_boolean(\"no_latex_cleanup\", value)\n\n    @property\n    def preview_command(self) -> str:\n        return self._d[\"preview_command\"]\n\n    @preview_command.setter\n    def preview_command(self, value: str) -> None:\n        self._set_str(\"preview_command\", value)\n\n    @property\n    def verbosity(self) -> str:\n        \"\"\"Logger verbosity; \"DEBUG\", \"INFO\", \"WARNING\", \"ERROR\", or \"CRITICAL\" (-v).\"\"\"\n        return self._d[\"verbosity\"]\n\n    @verbosity.setter\n    def verbosity(self, val: str) -> None:\n        self._set_from_list(\n            \"verbosity\",\n            val,\n            [\"DEBUG\", \"INFO\", \"WARNING\", \"ERROR\", \"CRITICAL\"],\n        )\n        logger.setLevel(val)\n\n    @property\n    def format(self) -> str | None:\n        \"\"\"File format; \"png\", \"gif\", \"mp4\", \"webm\" or \"mov\".\"\"\"\n        return self._d[\"format\"]\n\n    @format.setter\n    def format(self, val: str) -> None:\n        self._set_from_list(\n            \"format\",\n            val,\n            [None, \"png\", \"gif\", \"mp4\", \"mov\", \"webm\"],\n        )\n        self.resolve_movie_file_extension(self.transparent)\n        if self.format == \"webm\":\n            logger.warning(\n                \"Output format set as webm, this can be slower than other formats\",\n            )\n\n    @property\n    def ffmpeg_loglevel(self) -> str:\n        \"\"\"Verbosity level of ffmpeg (no flag).\"\"\"\n        return self._d[\"ffmpeg_loglevel\"]\n\n    @ffmpeg_loglevel.setter\n    def ffmpeg_loglevel(self, val: str) -> None:\n        self._set_from_list(\n            \"ffmpeg_loglevel\",\n            val,\n            [\"DEBUG\", \"INFO\", \"WARNING\", \"ERROR\", \"CRITICAL\"],\n        )\n        logging.getLogger(\"libav\").setLevel(self.ffmpeg_loglevel)\n\n    @property\n    def media_embed(self) -> bool | None:\n        \"\"\"Whether to embed videos in Jupyter notebook.\"\"\"\n        return self._d[\"media_embed\"]\n\n    @media_embed.setter\n    def media_embed(self, value: bool) -> None:\n        self._set_boolean(\"media_embed\", value)\n\n    @property\n    def media_width(self) -> str:\n        \"\"\"Media width in Jupyter notebook.\"\"\"\n        return self._d[\"media_width\"]\n\n    @media_width.setter\n    def media_width(self, value: str) -> None:\n        self._set_str(\"media_width\", value)\n\n    @property\n    def pixel_width(self) -> int:\n        \"\"\"Frame width in pixels (--resolution, -r).\"\"\"\n        return self._d[\"pixel_width\"]\n\n    @pixel_width.setter\n    def pixel_width(self, value: int) -> None:\n        self._set_pos_number(\"pixel_width\", value, False)\n\n    @property\n    def pixel_height(self) -> int:\n        \"\"\"Frame height in pixels (--resolution, -r).\"\"\"\n        return self._d[\"pixel_height\"]\n\n    @pixel_height.setter\n    def pixel_height(self, value: int) -> None:\n        self._set_pos_number(\"pixel_height\", value, False)\n\n    @property\n    def aspect_ratio(self) -> float:\n        \"\"\"Aspect ratio (width / height) in pixels (--resolution, -r).\"\"\"\n        assert isinstance(self._d[\"pixel_width\"], int)\n        assert isinstance(self._d[\"pixel_height\"], int)\n        return self._d[\"pixel_width\"] / self._d[\"pixel_height\"]\n\n    @property\n    def frame_height(self) -> float:\n        \"\"\"Frame height in logical units (no flag).\"\"\"\n        return self._d[\"frame_height\"]\n\n    @frame_height.setter\n    def frame_height(self, value: float) -> None:\n        self._d.__setitem__(\"frame_height\", value)\n\n    @property\n    def frame_width(self) -> float:\n        \"\"\"Frame width in logical units (no flag).\"\"\"\n        return self._d[\"frame_width\"]\n\n    @frame_width.setter\n    def frame_width(self, value: float) -> None:\n        self._d.__setitem__(\"frame_width\", value)\n\n    @property\n    def frame_y_radius(self) -> float:\n        \"\"\"Half the frame height (no flag).\"\"\"\n        return self._d[\"frame_height\"] / 2  # type: ignore[operator]\n\n    @frame_y_radius.setter\n    def frame_y_radius(self, value: float) -> None:\n        self._d.__setitem__(\"frame_y_radius\", value) or self._d.__setitem__(  # type: ignore[func-returns-value]\n            \"frame_height\", 2 * value\n        )\n\n    @property\n    def frame_x_radius(self) -> float:\n        \"\"\"Half the frame width (no flag).\"\"\"\n        return self._d[\"frame_width\"] / 2  # type: ignore[operator]\n\n    @frame_x_radius.setter\n    def frame_x_radius(self, value: float) -> None:\n        self._d.__setitem__(\"frame_x_radius\", value) or self._d.__setitem__(  # type: ignore[func-returns-value]\n            \"frame_width\", 2 * value\n        )\n\n    @property\n    def top(self) -> Vector3D:\n        \"\"\"Coordinate at the center top of the frame.\"\"\"\n        return self.frame_y_radius * constants.UP\n\n    @property\n    def bottom(self) -> Vector3D:\n        \"\"\"Coordinate at the center bottom of the frame.\"\"\"\n        return self.frame_y_radius * constants.DOWN\n\n    @property\n    def left_side(self) -> Vector3D:\n        \"\"\"Coordinate at the middle left of the frame.\"\"\"\n        return self.frame_x_radius * constants.LEFT\n\n    @property\n    def right_side(self) -> Vector3D:\n        \"\"\"Coordinate at the middle right of the frame.\"\"\"\n        return self.frame_x_radius * constants.RIGHT\n\n    @property\n    def frame_rate(self) -> float:\n        \"\"\"Frame rate in frames per second.\"\"\"\n        return self._d[\"frame_rate\"]\n\n    @frame_rate.setter\n    def frame_rate(self, value: float) -> None:\n        self._d.__setitem__(\"frame_rate\", value)\n\n    # TODO: This was parsed before maybe add ManimColor(val), but results in circular import\n    @property\n    def background_color(self) -> ManimColor:\n        \"\"\"Background color of the scene (-c).\"\"\"\n        return self._d[\"background_color\"]\n\n    @background_color.setter\n    def background_color(self, value: Any) -> None:\n        self._d.__setitem__(\"background_color\", ManimColor(value))\n\n    @property\n    def from_animation_number(self) -> int:\n        \"\"\"Start rendering animations at this number (-n).\"\"\"\n        return self._d[\"from_animation_number\"]\n\n    @from_animation_number.setter\n    def from_animation_number(self, value: int) -> None:\n        self._d.__setitem__(\"from_animation_number\", value)\n\n    @property\n    def upto_animation_number(self) -> int:\n        \"\"\"Stop rendering animations at this number. Use -1 to avoid skipping (-n).\"\"\"\n        return self._d[\"upto_animation_number\"]\n\n    @upto_animation_number.setter\n    def upto_animation_number(self, value: int) -> None:\n        self._set_pos_number(\"upto_animation_number\", value, True)\n\n    @property\n    def max_files_cached(self) -> int:\n        \"\"\"Maximum number of files cached.  Use -1 for infinity (no flag).\"\"\"\n        return self._d[\"max_files_cached\"]\n\n    @max_files_cached.setter\n    def max_files_cached(self, value: int) -> None:\n        self._set_pos_number(\"max_files_cached\", value, True)\n\n    @property\n    def window_monitor(self) -> int:\n        \"\"\"The monitor on which the scene will be rendered.\"\"\"\n        return self._d[\"window_monitor\"]\n\n    @window_monitor.setter\n    def window_monitor(self, value: int) -> None:\n        self._set_pos_number(\"window_monitor\", value, True)\n\n    @property\n    def flush_cache(self) -> bool:\n        \"\"\"Whether to delete all the cached partial movie files.\"\"\"\n        return self._d[\"flush_cache\"]\n\n    @flush_cache.setter\n    def flush_cache(self, value: bool) -> None:\n        self._set_boolean(\"flush_cache\", value)\n\n    @property\n    def disable_caching(self) -> bool:\n        \"\"\"Whether to use scene caching.\"\"\"\n        return self._d[\"disable_caching\"]\n\n    @disable_caching.setter\n    def disable_caching(self, value: bool) -> None:\n        self._set_boolean(\"disable_caching\", value)\n\n    @property\n    def disable_caching_warning(self) -> bool:\n        \"\"\"Whether a warning is raised if there are too much submobjects to hash.\"\"\"\n        return self._d[\"disable_caching_warning\"]\n\n    @disable_caching_warning.setter\n    def disable_caching_warning(self, value: bool) -> None:\n        self._set_boolean(\"disable_caching_warning\", value)\n\n    @property\n    def movie_file_extension(self) -> str:\n        \"\"\"Either .mp4, .webm or .mov.\"\"\"\n        return self._d[\"movie_file_extension\"]\n\n    @movie_file_extension.setter\n    def movie_file_extension(self, value: str) -> None:\n        self._set_from_list(\"movie_file_extension\", value, [\".mp4\", \".mov\", \".webm\"])\n\n    @property\n    def background_opacity(self) -> float:\n        \"\"\"A number between 0.0 (fully transparent) and 1.0 (fully opaque).\"\"\"\n        return self._d[\"background_opacity\"]\n\n    @background_opacity.setter\n    def background_opacity(self, value: float) -> None:\n        self._set_between(\"background_opacity\", value, 0, 1)\n        if self.background_opacity < 1:\n            self.resolve_movie_file_extension(is_transparent=True)\n\n    @property\n    def frame_size(self) -> tuple[int, int]:\n        \"\"\"Tuple with (pixel width, pixel height) (no flag).\"\"\"\n        return (self._d[\"pixel_width\"], self._d[\"pixel_height\"])\n\n    @frame_size.setter\n    def frame_size(self, value: tuple[int, int]) -> None:\n        self._d.__setitem__(\"pixel_width\", value[0]) or self._d.__setitem__(  # type: ignore[func-returns-value]\n            \"pixel_height\", value[1]\n        )\n\n    @property\n    def quality(self) -> str | None:\n        \"\"\"Video quality (-q).\"\"\"\n        keys = [\"pixel_width\", \"pixel_height\", \"frame_rate\"]\n        q = {k: self[k] for k in keys}\n        for qual in constants.QUALITIES:\n            if all(q[k] == constants.QUALITIES[qual][k] for k in keys):  # type: ignore[literal-required]\n                return qual\n        return None\n\n    @quality.setter\n    def quality(self, value: str | None) -> None:\n        if value is None:\n            return\n        if value not in constants.QUALITIES:\n            raise KeyError(f\"quality must be one of {list(constants.QUALITIES.keys())}\")\n        q = constants.QUALITIES[value]\n        self.frame_size = q[\"pixel_width\"], q[\"pixel_height\"]\n        self.frame_rate = q[\"frame_rate\"]\n\n    @property\n    def transparent(self) -> bool:\n        \"\"\"Whether the background opacity is less than 1.0 (-t).\"\"\"\n        assert isinstance(self._d[\"background_opacity\"], float)\n        return self._d[\"background_opacity\"] < 1.0\n\n    @transparent.setter\n    def transparent(self, value: bool) -> None:\n        self._d[\"background_opacity\"] = float(not value)\n        self.resolve_movie_file_extension(value)\n\n    @property\n    def dry_run(self) -> bool:\n        \"\"\"Whether dry run is enabled.\"\"\"\n        return self._d[\"dry_run\"]\n\n    @dry_run.setter\n    def dry_run(self, val: bool) -> None:\n        self._d[\"dry_run\"] = val\n        if val:\n            self.write_to_movie = False\n            self.write_all = False\n            self.save_last_frame = False\n            self.format = None\n\n    @property\n    def renderer(self) -> RendererType:\n        \"\"\"The currently active renderer.\n\n        Populated with one of the available renderers in :class:`.RendererType`.\n\n        Tests::\n\n            >>> test_config = ManimConfig()\n            >>> test_config.renderer is None  # a new ManimConfig is unpopulated\n            True\n            >>> test_config.renderer = 'opengl'\n            >>> test_config.renderer\n            <RendererType.OPENGL: 'opengl'>\n            >>> test_config.renderer = 42\n            Traceback (most recent call last):\n            ...\n            ValueError: 42 is not a valid RendererType\n\n        Check that capitalization of renderer types is irrelevant::\n\n            >>> test_config.renderer = 'OpenGL'\n            >>> test_config.renderer = 'cAirO'\n        \"\"\"\n        return self._d[\"renderer\"]\n\n    @renderer.setter\n    def renderer(self, value: str | RendererType) -> None:\n        \"\"\"The setter of the renderer property.\n\n        Takes care of switching inheritance bases using the\n        :class:`.ConvertToOpenGL` metaclass.\n        \"\"\"\n        if isinstance(value, str):\n            value = value.lower()\n        renderer = RendererType(value)\n        try:\n            from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\n            from manim.mobject.opengl.opengl_mobject import OpenGLMobject\n            from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject\n\n            from ..mobject.mobject import Mobject\n            from ..mobject.types.vectorized_mobject import VMobject\n\n            for cls in ConvertToOpenGL._converted_classes:\n                if renderer == RendererType.OPENGL:\n                    conversion_dict = {\n                        Mobject: OpenGLMobject,\n                        VMobject: OpenGLVMobject,\n                    }\n                else:\n                    conversion_dict = {\n                        OpenGLMobject: Mobject,\n                        OpenGLVMobject: VMobject,\n                    }\n\n                cls.__bases__ = tuple(\n                    conversion_dict.get(base, base) for base in cls.__bases__\n                )\n        except ImportError:\n            # The renderer is set during the initial import of the\n            # library for the first time. The imports above cause an\n            # ImportError due to circular imports. However, the\n            # metaclass sets stuff up correctly in this case, so we\n            # can just do nothing.\n            pass\n\n        self._set_from_enum(\"renderer\", renderer, RendererType)\n\n    @property\n    def media_dir(self) -> str:\n        \"\"\"Main output directory.  See :meth:`ManimConfig.get_dir`.\"\"\"\n        return self._d[\"media_dir\"]\n\n    @media_dir.setter\n    def media_dir(self, value: str | Path) -> None:\n        self._set_dir(\"media_dir\", value)\n\n    @property\n    def window_position(self) -> str:\n        \"\"\"Set the position of preview window. You can use directions, e.g. UL/DR/ORIGIN/LEFT...or the position(pixel) of the upper left corner of the window, e.g. '960,540'.\"\"\"\n        return self._d[\"window_position\"]\n\n    @window_position.setter\n    def window_position(self, value: str) -> None:\n        self._d.__setitem__(\"window_position\", value)\n\n    @property\n    def window_size(self) -> str | tuple[int, ...]:\n        \"\"\"The size of the opengl window. 'default' to automatically scale the window based on the display monitor.\"\"\"\n        return self._d[\"window_size\"]\n\n    @window_size.setter\n    def window_size(self, value: str | tuple[int, ...]) -> None:\n        self._d.__setitem__(\"window_size\", value)\n\n    def resolve_movie_file_extension(self, is_transparent: bool) -> None:\n        prev_file_extension = self.movie_file_extension\n        if is_transparent:\n            self.movie_file_extension = \".webm\" if self.format == \"webm\" else \".mov\"\n        elif self.format == \"webm\":\n            self.movie_file_extension = \".webm\"\n        elif self.format == \"mov\":\n            self.movie_file_extension = \".mov\"\n        else:\n            self.movie_file_extension = \".mp4\"\n        if self.movie_file_extension != prev_file_extension:\n            logger.warning(\n                f\"Output format changed to '{self.movie_file_extension}' \"\n                \"to support transparency\",\n            )\n\n    @property\n    def enable_gui(self) -> bool:\n        \"\"\"Enable GUI interaction.\"\"\"\n        return self._d[\"enable_gui\"]\n\n    @enable_gui.setter\n    def enable_gui(self, value: bool) -> None:\n        self._set_boolean(\"enable_gui\", value)\n\n    @property\n    def gui_location(self) -> tuple[int, ...]:\n        \"\"\"Location parameters for the GUI window (e.g., screen coordinates or layout settings).\"\"\"\n        return self._d[\"gui_location\"]\n\n    @gui_location.setter\n    def gui_location(self, value: tuple[Any]) -> None:\n        self._set_tuple(\"gui_location\", value)\n\n    @property\n    def fullscreen(self) -> bool:\n        \"\"\"Expand the window to its maximum possible size.\"\"\"\n        return self._d[\"fullscreen\"]\n\n    @fullscreen.setter\n    def fullscreen(self, value: bool) -> None:\n        self._set_boolean(\"fullscreen\", value)\n\n    @property\n    def use_projection_fill_shaders(self) -> bool:\n        \"\"\"Use shaders for OpenGLVMobject fill which are compatible with transformation matrices.\"\"\"\n        return self._d[\"use_projection_fill_shaders\"]\n\n    @use_projection_fill_shaders.setter\n    def use_projection_fill_shaders(self, value: bool) -> None:\n        self._set_boolean(\"use_projection_fill_shaders\", value)\n\n    @property\n    def use_projection_stroke_shaders(self) -> bool:\n        \"\"\"Use shaders for OpenGLVMobject stroke which are compatible with transformation matrices.\"\"\"\n        return self._d[\"use_projection_stroke_shaders\"]\n\n    @use_projection_stroke_shaders.setter\n    def use_projection_stroke_shaders(self, value: bool) -> None:\n        self._set_boolean(\"use_projection_stroke_shaders\", value)\n\n    @property\n    def zero_pad(self) -> int:\n        \"\"\"PNG zero padding. A number between 0 (no zero padding) and 9 (9 columns minimum).\"\"\"\n        return self._d[\"zero_pad\"]\n\n    @zero_pad.setter\n    def zero_pad(self, value: int) -> None:\n        self._set_int_between(\"zero_pad\", value, 0, 9)\n\n    def get_dir(self, key: str, **kwargs: Any) -> Path:\n        \"\"\"Resolve a config option that stores a directory.\n\n        Config options that store directories may depend on one another.  This\n        method is used to provide the actual directory to the end user.\n\n        Parameters\n        ----------\n        key\n            The config option to be resolved.  Must be an option ending in\n            ``'_dir'``, for example ``'media_dir'`` or ``'video_dir'``.\n\n        kwargs\n            Any strings to be used when resolving the directory.\n\n        Returns\n        -------\n        :class:`pathlib.Path`\n            Path to the requested directory.  If the path resolves to the empty\n            string, return ``None`` instead.\n\n        Raises\n        ------\n        :class:`KeyError`\n            When ``key`` is not a config option that stores a directory and\n            thus :meth:`~ManimConfig.get_dir` is not appropriate; or when\n            ``key`` is appropriate but there is not enough information to\n            resolve the directory.\n\n        Notes\n        -----\n        Standard :meth:`str.format` syntax is used to resolve the paths so the\n        paths may contain arbitrary placeholders using f-string notation.\n        However, these will require ``kwargs`` to contain the required values.\n\n        Examples\n        --------\n\n        The value of ``config.tex_dir`` is ``'{media_dir}/Tex'`` by default,\n        i.e. it is a subfolder of wherever ``config.media_dir`` is located.  In\n        order to get the *actual* directory, use :meth:`~ManimConfig.get_dir`.\n\n        .. code-block:: pycon\n\n            >>> from manim import config as globalconfig\n            >>> config = globalconfig.copy()\n            >>> config.tex_dir\n            '{media_dir}/Tex'\n            >>> config.media_dir\n            './media'\n            >>> config.get_dir(\"tex_dir\").as_posix()\n            'media/Tex'\n\n        Resolving directories is done in a lazy way, at the last possible\n        moment, to reflect any changes in other config options:\n\n        .. code-block:: pycon\n\n            >>> config.media_dir = \"my_media_dir\"\n            >>> config.get_dir(\"tex_dir\").as_posix()\n            'my_media_dir/Tex'\n\n        Some directories depend on information that is not available to\n        :class:`ManimConfig`. For example, the default value of `video_dir`\n        includes the name of the input file and the video quality\n        (e.g. 480p15). This informamtion has to be supplied via ``kwargs``:\n\n        .. code-block:: pycon\n\n            >>> config.video_dir\n            '{media_dir}/videos/{module_name}/{quality}'\n            >>> config.get_dir(\"video_dir\")\n            Traceback (most recent call last):\n            KeyError: 'video_dir {media_dir}/videos/{module_name}/{quality} requires the following keyword arguments: module_name'\n            >>> config.get_dir(\"video_dir\", module_name=\"myfile\").as_posix()\n            'my_media_dir/videos/myfile/1080p60'\n\n        Note the quality does not need to be passed as keyword argument since\n        :class:`ManimConfig` does store information about quality.\n\n        Directories may be recursively defined.  For example, the config option\n        ``partial_movie_dir`` depends on ``video_dir``, which in turn depends\n        on ``media_dir``:\n\n        .. code-block:: pycon\n\n            >>> config.partial_movie_dir\n            '{video_dir}/partial_movie_files/{scene_name}'\n            >>> config.get_dir(\"partial_movie_dir\")\n            Traceback (most recent call last):\n            KeyError: 'partial_movie_dir {video_dir}/partial_movie_files/{scene_name} requires the following keyword arguments: scene_name'\n            >>> config.get_dir(\n            ...     \"partial_movie_dir\", module_name=\"myfile\", scene_name=\"myscene\"\n            ... ).as_posix()\n            'my_media_dir/videos/myfile/1080p60/partial_movie_files/myscene'\n\n        Standard f-string syntax is used.  Arbitrary names can be used when\n        defining directories, as long as the corresponding values are passed to\n        :meth:`ManimConfig.get_dir` via ``kwargs``.\n\n        .. code-block:: pycon\n\n            >>> config.media_dir = \"{dir1}/{dir2}\"\n            >>> config.get_dir(\"media_dir\")\n            Traceback (most recent call last):\n            KeyError: 'media_dir {dir1}/{dir2} requires the following keyword arguments: dir1'\n            >>> config.get_dir(\"media_dir\", dir1=\"foo\", dir2=\"bar\").as_posix()\n            'foo/bar'\n            >>> config.media_dir = \"./media\"\n            >>> config.get_dir(\"media_dir\").as_posix()\n            'media'\n\n        \"\"\"\n        dirs = [\n            \"assets_dir\",\n            \"media_dir\",\n            \"video_dir\",\n            \"sections_dir\",\n            \"images_dir\",\n            \"text_dir\",\n            \"tex_dir\",\n            \"log_dir\",\n            \"input_file\",\n            \"output_file\",\n            \"partial_movie_dir\",\n        ]\n        if key not in dirs:\n            raise KeyError(\n                \"must pass one of \"\n                \"{media,video,images,text,tex,log}_dir \"\n                \"or {input,output}_file\",\n            )\n\n        dirs.remove(key)  # a path cannot contain itself\n\n        all_args = {k: self._d[k] for k in dirs}\n        all_args.update(kwargs)\n        all_args[\"quality\"] = f\"{self.pixel_height}p{self.frame_rate:g}\"\n\n        path = self._d[key]\n        assert isinstance(path, str)\n        while \"{\" in path:\n            try:\n                path = path.format(**all_args)\n            except KeyError as exc:\n                raise KeyError(\n                    f\"{key} {self._d[key]} requires the following \"\n                    + \"keyword arguments: \"\n                    + \" \".join(exc.args),\n                ) from exc\n        return Path(path) if path else None\n\n    def _set_dir(self, key: str, val: str | Path) -> None:\n        if isinstance(val, Path):\n            self._d.__setitem__(key, str(val))\n        else:\n            self._d.__setitem__(key, val)\n\n    @property\n    def assets_dir(self) -> str:\n        \"\"\"Directory to locate video assets (no flag).\"\"\"\n        return self._d[\"assets_dir\"]\n\n    @assets_dir.setter\n    def assets_dir(self, value: str | Path) -> None:\n        self._set_dir(\"assets_dir\", value)\n\n    @property\n    def log_dir(self) -> str:\n        \"\"\"Directory to place logs. See :meth:`ManimConfig.get_dir`.\"\"\"\n        return self._d[\"log_dir\"]\n\n    @log_dir.setter\n    def log_dir(self, value: str | Path) -> None:\n        self._set_dir(\"log_dir\", value)\n\n    @property\n    def video_dir(self) -> str:\n        \"\"\"Directory to place videos (no flag). See :meth:`ManimConfig.get_dir`.\"\"\"\n        return self._d[\"video_dir\"]\n\n    @video_dir.setter\n    def video_dir(self, value: str | Path) -> None:\n        self._set_dir(\"video_dir\", value)\n\n    @property\n    def sections_dir(self) -> str:\n        \"\"\"Directory to place section videos (no flag). See :meth:`ManimConfig.get_dir`.\"\"\"\n        return self._d[\"sections_dir\"]\n\n    @sections_dir.setter\n    def sections_dir(self, value: str | Path) -> None:\n        self._set_dir(\"sections_dir\", value)\n\n    @property\n    def images_dir(self) -> str:\n        \"\"\"Directory to place images (no flag).  See :meth:`ManimConfig.get_dir`.\"\"\"\n        return self._d[\"images_dir\"]\n\n    @images_dir.setter\n    def images_dir(self, value: str | Path) -> None:\n        self._set_dir(\"images_dir\", value)\n\n    @property\n    def text_dir(self) -> str:\n        \"\"\"Directory to place text (no flag).  See :meth:`ManimConfig.get_dir`.\"\"\"\n        return self._d[\"text_dir\"]\n\n    @text_dir.setter\n    def text_dir(self, value: str | Path) -> None:\n        self._set_dir(\"text_dir\", value)\n\n    @property\n    def tex_dir(self) -> str:\n        \"\"\"Directory to place tex (no flag).  See :meth:`ManimConfig.get_dir`.\"\"\"\n        return self._d[\"tex_dir\"]\n\n    @tex_dir.setter\n    def tex_dir(self, value: str | Path) -> None:\n        self._set_dir(\"tex_dir\", value)\n\n    @property\n    def partial_movie_dir(self) -> str:\n        \"\"\"Directory to place partial movie files (no flag).  See :meth:`ManimConfig.get_dir`.\"\"\"\n        return self._d[\"partial_movie_dir\"]\n\n    @partial_movie_dir.setter\n    def partial_movie_dir(self, value: str | Path) -> None:\n        self._set_dir(\"partial_movie_dir\", value)\n\n    @property\n    def custom_folders(self) -> str:\n        \"\"\"Whether to use custom folder output.\"\"\"\n        return self._d[\"custom_folders\"]\n\n    @custom_folders.setter\n    def custom_folders(self, value: str | Path) -> None:\n        self._set_dir(\"custom_folders\", value)\n\n    @property\n    def input_file(self) -> str | Path:\n        \"\"\"Input file name.\"\"\"\n        return self._d[\"input_file\"]\n\n    @input_file.setter\n    def input_file(self, value: str | Path) -> None:\n        self._set_dir(\"input_file\", value)\n\n    @property\n    def output_file(self) -> str:\n        \"\"\"Output file name (-o).\"\"\"\n        return self._d[\"output_file\"]\n\n    @output_file.setter\n    def output_file(self, value: str | Path) -> None:\n        self._set_dir(\"output_file\", value)\n\n    @property\n    def scene_names(self) -> list[str]:\n        \"\"\"Scenes to play from file.\"\"\"\n        return self._d[\"scene_names\"]\n\n    @scene_names.setter\n    def scene_names(self, value: list[str]) -> None:\n        self._d.__setitem__(\"scene_names\", value)\n\n    @property\n    def tex_template(self) -> TexTemplate:\n        \"\"\"Template used when rendering Tex.  See :class:`.TexTemplate`.\"\"\"\n        if not hasattr(self, \"_tex_template\") or not self._tex_template:  # type: ignore[has-type]\n            fn = self._d[\"tex_template_file\"]\n            if fn:\n                self._tex_template = TexTemplate.from_file(fn)\n            else:\n                self._tex_template = TexTemplate()\n        return self._tex_template\n\n    @tex_template.setter\n    def tex_template(self, val: TexTemplate) -> None:\n        if isinstance(val, TexTemplate):\n            self._tex_template = val\n\n    @property\n    def tex_template_file(self) -> Path:\n        \"\"\"File to read Tex template from (no flag).  See :class:`.TexTemplate`.\"\"\"\n        return self._d[\"tex_template_file\"]\n\n    @tex_template_file.setter\n    def tex_template_file(self, val: str) -> None:\n        if val:\n            if not os.access(val, os.R_OK):\n                logger.warning(\n                    f\"Custom TeX template {val} not found or not readable.\",\n                )\n            else:\n                self._d[\"tex_template_file\"] = Path(val)\n        else:\n            self._d[\"tex_template_file\"] = val  # actually set the falsy value\n\n    @property\n    def plugins(self) -> list[str]:\n        \"\"\"List of plugins to enable.\"\"\"\n        return self._d[\"plugins\"]\n\n    @plugins.setter\n    def plugins(self, value: list[str]) -> None:\n        self._d[\"plugins\"] = value\n\n    @property\n    def seed(self) -> int | None:\n        \"\"\"Random seed for reproducibility. None means no seed is set.\"\"\"\n        return self._d[\"seed\"]\n\n    @seed.setter\n    def seed(self, value: int | None) -> None:\n        if value is None:\n            return\n        self._set_pos_number(\"seed\", value, False)\n\n\n# TODO: to be used in the future - see PR #620\n# https://github.com/ManimCommunity/manim/pull/620\nclass ManimFrame(Mapping):\n    _OPTS: ClassVar[set[str]] = {\n        \"pixel_width\",\n        \"pixel_height\",\n        \"aspect_ratio\",\n        \"frame_height\",\n        \"frame_width\",\n        \"frame_y_radius\",\n        \"frame_x_radius\",\n        \"top\",\n        \"bottom\",\n        \"left_side\",\n        \"right_side\",\n    }\n    _CONSTANTS: ClassVar[dict[str, Vector3D]] = {\n        \"UP\": np.array((0.0, 1.0, 0.0)),\n        \"DOWN\": np.array((0.0, -1.0, 0.0)),\n        \"RIGHT\": np.array((1.0, 0.0, 0.0)),\n        \"LEFT\": np.array((-1.0, 0.0, 0.0)),\n        \"IN\": np.array((0.0, 0.0, -1.0)),\n        \"OUT\": np.array((0.0, 0.0, 1.0)),\n        \"ORIGIN\": np.array((0.0, 0.0, 0.0)),\n        \"X_AXIS\": np.array((1.0, 0.0, 0.0)),\n        \"Y_AXIS\": np.array((0.0, 1.0, 0.0)),\n        \"Z_AXIS\": np.array((0.0, 0.0, 1.0)),\n        \"UL\": np.array((-1.0, 1.0, 0.0)),\n        \"UR\": np.array((1.0, 1.0, 0.0)),\n        \"DL\": np.array((-1.0, -1.0, 0.0)),\n        \"DR\": np.array((1.0, -1.0, 0.0)),\n    }\n\n    _c: ManimConfig\n\n    def __init__(self, c: ManimConfig) -> None:\n        if not isinstance(c, ManimConfig):\n            raise TypeError(\"argument must be instance of 'ManimConfig'\")\n        # need to use __dict__ directly because setting attributes is not\n        # allowed (see __setattr__)\n        self.__dict__[\"_c\"] = c\n\n    # there are required by parent class Mapping to behave like a dict\n    def __getitem__(self, key: str) -> Any:\n        if key in self._OPTS:\n            return self._c[key]\n        elif key in self._CONSTANTS:\n            return self._CONSTANTS[key]\n        else:\n            raise KeyError(key)\n\n    def __iter__(self) -> Iterator[Any]:\n        return iter(list(self._OPTS) + list(self._CONSTANTS))\n\n    def __len__(self) -> int:\n        return len(self._OPTS)\n\n    # make this truly immutable\n    def __setattr__(self, attr: Any, val: Any) -> NoReturn:\n        raise TypeError(\"'ManimFrame' object does not support item assignment\")\n\n    def __setitem__(self, key: Any, val: Any) -> NoReturn:\n        raise TypeError(\"'ManimFrame' object does not support item assignment\")\n\n    def __delitem__(self, key: Any) -> NoReturn:\n        raise TypeError(\"'ManimFrame' object does not support item deletion\")\n\n\nfor opt in list(ManimFrame._OPTS) + list(ManimFrame._CONSTANTS):\n    setattr(ManimFrame, opt, property(lambda self, o=opt: self[o]))  # type: ignore[misc]\n"
  },
  {
    "path": "manim/animation/__init__.py",
    "content": ""
  },
  {
    "path": "manim/animation/animation.py",
    "content": "\"\"\"Animate mobjects.\"\"\"\n\nfrom __future__ import annotations\n\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\n\nfrom .. import config, logger\nfrom ..constants import RendererType\nfrom ..mobject import mobject\nfrom ..mobject.mobject import Group, Mobject\nfrom ..mobject.opengl import opengl_mobject\nfrom ..utils.rate_functions import linear, smooth\n\n__all__ = [\"Animation\", \"Wait\", \"Add\", \"override_animation\"]\n\n\nfrom collections.abc import Callable, Iterable, Sequence\nfrom copy import deepcopy\nfrom functools import partialmethod\nfrom typing import TYPE_CHECKING, Any, Self\n\nif TYPE_CHECKING:\n    from manim.scene.scene import Scene\n\n\nDEFAULT_ANIMATION_RUN_TIME: float = 1.0\nDEFAULT_ANIMATION_LAG_RATIO: float = 0.0\n\n\nclass Animation:\n    \"\"\"An animation.\n\n    Animations have a fixed time span.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to be animated. This is not required for all types of animations.\n    lag_ratio\n        Defines the delay after which the animation is applied to submobjects. This lag\n        is relative to the duration of the animation.\n\n        This does not influence the total\n        runtime of the animation. Instead the runtime of individual animations is\n        adjusted so that the complete animation has the defined run time.\n\n    run_time\n        The duration of the animation in seconds.\n    rate_func\n        The function defining the animation progress based on the relative runtime (see  :mod:`~.rate_functions`) .\n\n        For example ``rate_func(0.5)`` is the proportion of the animation that is done\n        after half of the animations run time.\n\n    reverse_rate_function\n        Reverses the rate function of the animation. Setting ``reverse_rate_function``\n        does not have any effect on ``remover`` or ``introducer``. These need to be\n        set explicitly if an introducer-animation should be turned into a remover one\n        and vice versa.\n    name\n        The name of the animation. This gets displayed while rendering the animation.\n        Defaults to <class-name>(<Mobject-name>).\n    remover\n        Whether the given mobject should be removed from the scene after this animation.\n    suspend_mobject_updating\n        Whether updaters of the mobject should be suspended during the animation.\n\n\n    .. NOTE::\n\n        In the current implementation of this class, the specified rate function is applied\n        within :meth:`.Animation.interpolate_mobject` call as part of the call to\n        :meth:`.Animation.interpolate_submobject`. For subclasses of :class:`.Animation`\n        that are implemented by overriding :meth:`interpolate_mobject`, the rate function\n        has to be applied manually (e.g., by passing ``self.rate_func(alpha)`` instead\n        of just ``alpha``).\n\n\n    Examples\n    --------\n\n    .. manim:: LagRatios\n\n        class LagRatios(Scene):\n            def construct(self):\n                ratios = [0, 0.1, 0.5, 1, 2]  # demonstrated lag_ratios\n\n                # Create dot groups\n                group = VGroup(*[Dot() for _ in range(4)]).arrange_submobjects()\n                groups = VGroup(*[group.copy() for _ in ratios]).arrange_submobjects(buff=1)\n                self.add(groups)\n\n                # Label groups\n                self.add(Text(\"lag_ratio = \", font_size=36).next_to(groups, UP, buff=1.5))\n                for group, ratio in zip(groups, ratios):\n                    self.add(Text(str(ratio), font_size=36).next_to(group, UP))\n\n                #Animate groups with different lag_ratios\n                self.play(AnimationGroup(*[\n                    group.animate(lag_ratio=ratio, run_time=1.5).shift(DOWN * 2)\n                    for group, ratio in zip(groups, ratios)\n                ]))\n\n                # lag_ratio also works recursively on nested submobjects:\n                self.play(groups.animate(run_time=1, lag_ratio=0.1).shift(UP * 2))\n\n    \"\"\"\n\n    def __new__(\n        cls,\n        mobject=None,\n        *args,\n        use_override=True,\n        **kwargs,\n    ) -> Self:\n        if isinstance(mobject, Mobject) and use_override:\n            func = mobject.animation_override_for(cls)\n            if func is not None:\n                anim = func(mobject, *args, **kwargs)\n                logger.debug(\n                    f\"The {cls.__name__} animation has been overridden for \"\n                    f\"{type(mobject).__name__} mobjects. use_override = False can \"\n                    f\" be used as keyword argument to prevent animation overriding.\",\n                )\n                return anim\n        return super().__new__(cls)\n\n    def __init__(\n        self,\n        mobject: Mobject | OpenGLMobject | None,\n        lag_ratio: float = DEFAULT_ANIMATION_LAG_RATIO,\n        run_time: float = DEFAULT_ANIMATION_RUN_TIME,\n        rate_func: Callable[[float], float] = smooth,\n        reverse_rate_function: bool = False,\n        name: str = None,\n        remover: bool = False,  # remove a mobject from the screen?\n        suspend_mobject_updating: bool = True,\n        introducer: bool = False,\n        *,\n        _on_finish: Callable[[], None] = lambda _: None,\n        use_override: bool = True,  # included here to avoid TypeError if passed from a subclass' constructor\n    ) -> None:\n        self._typecheck_input(mobject)\n        self.run_time: float = run_time\n        self.rate_func: Callable[[float], float] = rate_func\n        self.reverse_rate_function: bool = reverse_rate_function\n        self.name: str | None = name\n        self.remover: bool = remover\n        self.introducer: bool = introducer\n        self.suspend_mobject_updating: bool = suspend_mobject_updating\n        self.lag_ratio: float = lag_ratio\n        self._on_finish: Callable[[Scene], None] = _on_finish\n        if config[\"renderer\"] == RendererType.OPENGL:\n            self.starting_mobject: OpenGLMobject = OpenGLMobject()\n            self.mobject: OpenGLMobject = (\n                mobject if mobject is not None else OpenGLMobject()\n            )\n        else:\n            self.starting_mobject: Mobject = Mobject()\n            self.mobject: Mobject = mobject if mobject is not None else Mobject()\n\n        if hasattr(self, \"CONFIG\"):\n            logger.error(\n                (\n                    \"CONFIG has been removed from ManimCommunity.\",\n                    \"Please use keyword arguments instead.\",\n                ),\n            )\n\n    @property\n    def run_time(self) -> float:\n        return self._run_time\n\n    @run_time.setter\n    def run_time(self, value: float) -> None:\n        if value < 0:\n            raise ValueError(\n                f\"The run_time of {self.__class__.__name__} cannot be \"\n                f\"negative. The given value was {value}.\"\n            )\n        self._run_time = value\n\n    def _typecheck_input(self, mobject: Mobject | None) -> None:\n        if mobject is None:\n            logger.debug(\"Animation with empty mobject\")\n        elif not isinstance(mobject, (Mobject, OpenGLMobject)):\n            raise TypeError(\"Animation only works on Mobjects\")\n\n    def __str__(self) -> str:\n        if self.name:\n            return self.name\n        return f\"{self.__class__.__name__}({str(self.mobject)})\"\n\n    def __repr__(self) -> str:\n        return str(self)\n\n    def begin(self) -> None:\n        \"\"\"Begin the animation.\n\n        This method is called right as an animation is being played. As much\n        initialization as possible, especially any mobject copying, should live in this\n        method.\n\n        \"\"\"\n        self.starting_mobject = self.create_starting_mobject()\n        if self.suspend_mobject_updating:\n            # All calls to self.mobject's internal updaters\n            # during the animation, either from this Animation\n            # or from the surrounding scene, should do nothing.\n            # It is, however, okay and desirable to call\n            # the internal updaters of self.starting_mobject,\n            # or any others among self.get_all_mobjects()\n            self.mobject.suspend_updating()\n        self.interpolate(0)\n\n    def finish(self) -> None:\n        # TODO: begin and finish should require a scene as parameter.\n        # That way Animation.clean_up_from_screen and Scene.add_mobjects_from_animations\n        # could be removed as they fulfill basically the same purpose.\n        \"\"\"Finish the animation.\n\n        This method gets called when the animation is over.\n\n        \"\"\"\n        self.interpolate(1)\n        if self.suspend_mobject_updating and self.mobject is not None:\n            self.mobject.resume_updating()\n\n    def clean_up_from_scene(self, scene: Scene) -> None:\n        \"\"\"Clean up the :class:`~.Scene` after finishing the animation.\n\n        This includes to :meth:`~.Scene.remove` the Animation's\n        :class:`~.Mobject` if the animation is a remover.\n\n        Parameters\n        ----------\n        scene\n            The scene the animation should be cleaned up from.\n        \"\"\"\n        self._on_finish(scene)\n        if self.is_remover():\n            scene.remove(self.mobject)\n\n    def _setup_scene(self, scene: Scene) -> None:\n        \"\"\"Setup up the :class:`~.Scene` before starting the animation.\n\n        This includes to :meth:`~.Scene.add` the Animation's\n        :class:`~.Mobject` if the animation is an introducer.\n\n        Parameters\n        ----------\n        scene\n            The scene the animation should be cleaned up from.\n        \"\"\"\n        if scene is None:\n            return\n        if (\n            self.is_introducer()\n            and self.mobject not in scene.get_mobject_family_members()\n        ):\n            scene.add(self.mobject)\n\n    def create_starting_mobject(self) -> Mobject | OpenGLMobject:\n        # Keep track of where the mobject starts\n        return self.mobject.copy()\n\n    def get_all_mobjects(self) -> Sequence[Mobject | OpenGLMobject]:\n        \"\"\"Get all mobjects involved in the animation.\n\n        Ordering must match the ordering of arguments to interpolate_submobject\n\n        Returns\n        -------\n        Sequence[Mobject]\n            The sequence of mobjects.\n        \"\"\"\n        return self.mobject, self.starting_mobject\n\n    def get_all_families_zipped(self) -> Iterable[tuple]:\n        if config[\"renderer\"] == RendererType.OPENGL:\n            return zip(\n                *(mob.get_family() for mob in self.get_all_mobjects()), strict=False\n            )\n        return zip(\n            *(mob.family_members_with_points() for mob in self.get_all_mobjects()),\n            strict=False,\n        )\n\n    def update_mobjects(self, dt: float) -> None:\n        \"\"\"\n        Updates things like starting_mobject, and (for\n        Transforms) target_mobject.  Note, since typically\n        (always?) self.mobject will have its updating\n        suspended during the animation, this will do\n        nothing to self.mobject.\n        \"\"\"\n        for mob in self.get_all_mobjects_to_update():\n            mob.update(dt)\n\n    def get_all_mobjects_to_update(self) -> list[Mobject]:\n        \"\"\"Get all mobjects to be updated during the animation.\n\n        Returns\n        -------\n        List[Mobject]\n            The list of mobjects to be updated during the animation.\n        \"\"\"\n        # The surrounding scene typically handles\n        # updating of self.mobject.  Besides, in\n        # most cases its updating is suspended anyway\n        return list(filter(lambda m: m is not self.mobject, self.get_all_mobjects()))\n\n    def copy(self) -> Animation:\n        \"\"\"Create a copy of the animation.\n\n        Returns\n        -------\n        Animation\n            A copy of ``self``\n        \"\"\"\n        return deepcopy(self)\n\n    # Methods for interpolation, the mean of an Animation\n\n    # TODO: stop using alpha as parameter name in different meanings.\n    def interpolate(self, alpha: float) -> None:\n        \"\"\"Set the animation progress.\n\n        This method gets called for every frame during an animation.\n\n        Parameters\n        ----------\n        alpha\n            The relative time to set the animation to, 0 meaning the start, 1 meaning\n            the end.\n        \"\"\"\n        self.interpolate_mobject(alpha)\n\n    def interpolate_mobject(self, alpha: float) -> None:\n        \"\"\"Interpolates the mobject of the :class:`Animation` based on alpha value.\n\n        Parameters\n        ----------\n        alpha\n            A float between 0 and 1 expressing the ratio to which the animation\n            is completed. For example, alpha-values of 0, 0.5, and 1 correspond\n            to the animation being completed 0%, 50%, and 100%, respectively.\n        \"\"\"\n        families = list(self.get_all_families_zipped())\n        for i, mobs in enumerate(families):\n            sub_alpha = self.get_sub_alpha(alpha, i, len(families))\n            self.interpolate_submobject(*mobs, sub_alpha)\n\n    def interpolate_submobject(\n        self,\n        submobject: Mobject,\n        starting_submobject: Mobject,\n        # target_copy: Mobject, #Todo: fix - signature of interpolate_submobject differs in Transform().\n        alpha: float,\n    ) -> Animation:\n        # Typically implemented by subclass\n        pass\n\n    def get_sub_alpha(self, alpha: float, index: int, num_submobjects: int) -> float:\n        \"\"\"Get the animation progress of any submobjects subanimation.\n\n        Parameters\n        ----------\n        alpha\n            The overall animation progress\n        index\n            The index of the subanimation.\n        num_submobjects\n            The total count of subanimations.\n\n        Returns\n        -------\n        float\n            The progress of the subanimation.\n        \"\"\"\n        # TODO, make this more understandable, and/or combine\n        # its functionality with AnimationGroup's method\n        # build_animations_with_timings\n        lag_ratio = self.lag_ratio\n        full_length = (num_submobjects - 1) * lag_ratio + 1\n        value = alpha * full_length\n        lower = index * lag_ratio\n        if self.reverse_rate_function:\n            return self.rate_func(1 - (value - lower))\n        else:\n            return self.rate_func(value - lower)\n\n    # Getters and setters\n    def set_run_time(self, run_time: float) -> Animation:\n        \"\"\"Set the run time of the animation.\n\n        Parameters\n        ----------\n        run_time\n            The new time the animation should take in seconds.\n\n        .. note::\n\n            The run_time of an animation should not be changed while it is already\n            running.\n\n        Returns\n        -------\n        Animation\n            ``self``\n        \"\"\"\n        self.run_time = run_time\n        return self\n\n    # TODO: is this getter even necessary?\n    def get_run_time(self) -> float:\n        \"\"\"Get the run time of the animation.\n\n        Returns\n        -------\n        float\n            The time the animation takes in seconds.\n        \"\"\"\n        return self.run_time\n\n    def set_rate_func(\n        self,\n        rate_func: Callable[[float], float],\n    ) -> Animation:\n        \"\"\"Set the rate function of the animation.\n\n        Parameters\n        ----------\n        rate_func\n            The new function defining the animation progress based on the\n            relative runtime (see :mod:`~.rate_functions`).\n\n        Returns\n        -------\n        Animation\n            ``self``\n        \"\"\"\n        self.rate_func = rate_func\n        return self\n\n    def get_rate_func(\n        self,\n    ) -> Callable[[float], float]:\n        \"\"\"Get the rate function of the animation.\n\n        Returns\n        -------\n        Callable[[float], float]\n            The rate function of the animation.\n        \"\"\"\n        return self.rate_func\n\n    def set_name(self, name: str) -> Animation:\n        \"\"\"Set the name of the animation.\n\n        Parameters\n        ----------\n        name\n            The new name of the animation.\n\n        Returns\n        -------\n        Animation\n            ``self``\n        \"\"\"\n        self.name = name\n        return self\n\n    def is_remover(self) -> bool:\n        \"\"\"Test if the animation is a remover.\n\n        Returns\n        -------\n        bool\n            ``True`` if the animation is a remover, ``False`` otherwise.\n        \"\"\"\n        return self.remover\n\n    def is_introducer(self) -> bool:\n        \"\"\"Test if the animation is an introducer.\n\n        Returns\n        -------\n        bool\n            ``True`` if the animation is an introducer, ``False`` otherwise.\n        \"\"\"\n        return self.introducer\n\n    @classmethod\n    def __init_subclass__(cls, **kwargs) -> None:\n        super().__init_subclass__(**kwargs)\n\n        cls._original__init__ = cls.__init__\n\n    _original__init__ = __init__  # needed if set_default() is called with no kwargs directly from Animation\n\n    @classmethod\n    def set_default(cls, **kwargs) -> None:\n        \"\"\"Sets the default values of keyword arguments.\n\n        If this method is called without any additional keyword\n        arguments, the original default values of the initialization\n        method of this class are restored.\n\n        Parameters\n        ----------\n\n        kwargs\n            Passing any keyword argument will update the default\n            values of the keyword arguments of the initialization\n            function of this class.\n\n        Examples\n        --------\n\n        .. manim:: ChangeDefaultAnimation\n\n            class ChangeDefaultAnimation(Scene):\n                def construct(self):\n                    Rotate.set_default(run_time=2, rate_func=rate_functions.linear)\n                    Indicate.set_default(color=None)\n\n                    S = Square(color=BLUE, fill_color=BLUE, fill_opacity=0.25)\n                    self.add(S)\n                    self.play(Rotate(S, PI))\n                    self.play(Indicate(S))\n\n                    Rotate.set_default()\n                    Indicate.set_default()\n\n        \"\"\"\n        if kwargs:\n            cls.__init__ = partialmethod(cls.__init__, **kwargs)\n        else:\n            cls.__init__ = cls._original__init__\n\n\ndef prepare_animation(\n    anim: Animation | mobject._AnimationBuilder | opengl_mobject._AnimationBuilder,\n) -> Animation:\n    r\"\"\"Returns either an unchanged animation, or the animation built\n    from a passed animation factory.\n\n    Examples\n    --------\n\n    ::\n\n        >>> from manim import Square, FadeIn\n        >>> s = Square()\n        >>> prepare_animation(FadeIn(s))\n        FadeIn(Square)\n\n    ::\n\n        >>> prepare_animation(s.animate.scale(2).rotate(42))\n        _MethodAnimation(Square)\n\n    ::\n\n        >>> prepare_animation(42)\n        Traceback (most recent call last):\n        ...\n        TypeError: Object 42 cannot be converted to an animation\n\n    \"\"\"\n    if isinstance(anim, mobject._AnimationBuilder):\n        return anim.build()\n\n    if isinstance(anim, opengl_mobject._AnimationBuilder):\n        return anim.build()\n\n    if isinstance(anim, Animation):\n        return anim\n\n    raise TypeError(f\"Object {anim} cannot be converted to an animation\")\n\n\nclass Wait(Animation):\n    \"\"\"A \"no operation\" animation.\n\n    Parameters\n    ----------\n    run_time\n        The amount of time that should pass.\n    stop_condition\n        A function without positional arguments that evaluates to a boolean.\n        The function is evaluated after every new frame has been rendered.\n        Playing the animation stops after the return value is truthy, or\n        after the specified ``run_time`` has passed.\n    frozen_frame\n        Controls whether or not the wait animation is static, i.e., corresponds\n        to a frozen frame. If ``False`` is passed, the render loop still\n        progresses through the animation as usual and (among other things)\n        continues to call updater functions. If ``None`` (the default value),\n        the :meth:`.Scene.play` call tries to determine whether the Wait call\n        can be static or not itself via :meth:`.Scene.should_mobjects_update`.\n    kwargs\n        Keyword arguments to be passed to the parent class, :class:`.Animation`.\n    \"\"\"\n\n    def __init__(\n        self,\n        run_time: float = 1,\n        stop_condition: Callable[[], bool] | None = None,\n        frozen_frame: bool | None = None,\n        rate_func: Callable[[float], float] = linear,\n        **kwargs,\n    ):\n        if stop_condition and frozen_frame:\n            raise ValueError(\"A static Wait animation cannot have a stop condition.\")\n\n        self.duration: float = run_time\n        self.stop_condition = stop_condition\n        self.is_static_wait: bool = frozen_frame\n        super().__init__(None, run_time=run_time, rate_func=rate_func, **kwargs)\n        # quick fix to work in opengl setting:\n        self.mobject.shader_wrapper_list = []\n\n    def begin(self) -> None:\n        pass\n\n    def finish(self) -> None:\n        pass\n\n    def clean_up_from_scene(self, scene: Scene) -> None:\n        pass\n\n    def update_mobjects(self, dt: float) -> None:\n        pass\n\n    def interpolate(self, alpha: float) -> None:\n        pass\n\n\nclass Add(Animation):\n    \"\"\"Add Mobjects to a scene, without animating them in any other way. This\n    is similar to the :meth:`.Scene.add` method, but :class:`Add` is an\n    animation which can be grouped into other animations.\n\n    Parameters\n    ----------\n    mobjects\n        One :class:`~.Mobject` or more to add to a scene.\n    run_time\n        The duration of the animation after adding the ``mobjects``. Defaults\n        to 0, which means this is an instant animation without extra wait time\n        after adding them.\n    **kwargs\n        Additional arguments to pass to the parent :class:`Animation` class.\n\n    Examples\n    --------\n\n    .. manim:: DefaultAddScene\n\n        class DefaultAddScene(Scene):\n            def construct(self):\n                text_1 = Text(\"I was added with Add!\")\n                text_2 = Text(\"Me too!\")\n                text_3 = Text(\"And me!\")\n                texts = VGroup(text_1, text_2, text_3).arrange(DOWN)\n                rect = SurroundingRectangle(texts, buff=0.5)\n\n                self.play(\n                    Create(rect, run_time=3.0),\n                    Succession(\n                        Wait(1.0),\n                        # You can Add a Mobject in the middle of an animation...\n                        Add(text_1),\n                        Wait(1.0),\n                        # ...or multiple Mobjects at once!\n                        Add(text_2, text_3),\n                    ),\n                )\n                self.wait()\n\n    .. manim:: AddWithRunTimeScene\n\n        class AddWithRunTimeScene(Scene):\n            def construct(self):\n                # A 5x5 grid of circles\n                circles = VGroup(\n                    *[Circle(radius=0.5) for _ in range(25)]\n                ).arrange_in_grid(5, 5)\n\n                self.play(\n                    Succession(\n                        # Add a run_time of 0.2 to wait for 0.2 seconds after\n                        # adding the circle, instead of using Wait(0.2) after Add!\n                        *[Add(circle, run_time=0.2) for circle in circles],\n                        rate_func=smooth,\n                    )\n                )\n                self.wait()\n    \"\"\"\n\n    def __init__(\n        self, *mobjects: Mobject, run_time: float = 0.0, **kwargs: Any\n    ) -> None:\n        mobject = mobjects[0] if len(mobjects) == 1 else Group(*mobjects)\n        super().__init__(mobject, run_time=run_time, introducer=True, **kwargs)\n\n    def begin(self) -> None:\n        pass\n\n    def finish(self) -> None:\n        pass\n\n    def clean_up_from_scene(self, scene: Scene) -> None:\n        pass\n\n    def update_mobjects(self, dt: float) -> None:\n        pass\n\n    def interpolate(self, alpha: float) -> None:\n        pass\n\n\ndef override_animation(\n    animation_class: type[Animation],\n) -> Callable[[Callable], Callable]:\n    \"\"\"Decorator used to mark methods as overrides for specific :class:`~.Animation` types.\n\n    Should only be used to decorate methods of classes derived from :class:`~.Mobject`.\n    ``Animation`` overrides get inherited to subclasses of the ``Mobject`` who defined\n    them. They don't override subclasses of the ``Animation`` they override.\n\n    See Also\n    --------\n    :meth:`~.Mobject.add_animation_override`\n\n    Parameters\n    ----------\n    animation_class\n        The animation to be overridden.\n\n    Returns\n    -------\n    Callable[[Callable], Callable]\n        The actual decorator. This marks the method as overriding an animation.\n\n    Examples\n    --------\n\n    .. manim:: OverrideAnimationExample\n\n        class MySquare(Square):\n            @override_animation(FadeIn)\n            def _fade_in_override(self, **kwargs):\n                return Create(self, **kwargs)\n\n        class OverrideAnimationExample(Scene):\n            def construct(self):\n                self.play(FadeIn(MySquare()))\n\n    \"\"\"\n\n    def decorator(func):\n        func._override_animation = animation_class\n        return func\n\n    return decorator\n"
  },
  {
    "path": "manim/animation/changing.py",
    "content": "\"\"\"Animation of a mobject boundary and tracing of points.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"AnimatedBoundary\", \"TracedPath\"]\n\nfrom collections.abc import Callable, Sequence\nfrom typing import Any, Self\n\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.types.vectorized_mobject import VGroup, VMobject\nfrom manim.utils.color import (\n    BLUE_B,\n    BLUE_D,\n    BLUE_E,\n    GREY_BROWN,\n    WHITE,\n    ParsableManimColor,\n)\nfrom manim.utils.rate_functions import RateFunction, smooth\n\n\nclass AnimatedBoundary(VGroup):\n    \"\"\"Boundary of a :class:`.VMobject` with animated color change.\n\n    Examples\n    --------\n    .. manim:: AnimatedBoundaryExample\n\n        class AnimatedBoundaryExample(Scene):\n            def construct(self):\n                text = Text(\"So shiny!\")\n                boundary = AnimatedBoundary(text, colors=[RED, GREEN, BLUE],\n                                            cycle_rate=3)\n                self.add(text, boundary)\n                self.wait(2)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        vmobject: VMobject,\n        colors: Sequence[ParsableManimColor] = [BLUE_D, BLUE_B, BLUE_E, GREY_BROWN],\n        max_stroke_width: float = 3,\n        cycle_rate: float = 0.5,\n        back_and_forth: bool = True,\n        draw_rate_func: RateFunction = smooth,\n        fade_rate_func: RateFunction = smooth,\n        **kwargs: Any,\n    ):\n        super().__init__(**kwargs)\n        self.colors = colors\n        self.max_stroke_width = max_stroke_width\n        self.cycle_rate = cycle_rate\n        self.back_and_forth = back_and_forth\n        self.draw_rate_func = draw_rate_func\n        self.fade_rate_func = fade_rate_func\n        self.vmobject = vmobject\n        self.boundary_copies = [\n            vmobject.copy().set_style(stroke_width=0, fill_opacity=0) for x in range(2)\n        ]\n        self.add(*self.boundary_copies)\n        self.total_time = 0.0\n        self.add_updater(lambda m, dt: self.update_boundary_copies(dt))\n\n    def update_boundary_copies(self, dt: float) -> None:\n        # Not actual time, but something which passes at\n        # an altered rate to make the implementation below\n        # cleaner\n        time = self.total_time * self.cycle_rate\n        growing, fading = self.boundary_copies\n        colors = self.colors\n        msw = self.max_stroke_width\n        vmobject = self.vmobject\n\n        index = int(time % len(colors))\n        alpha = time % 1\n        draw_alpha = self.draw_rate_func(alpha)\n        fade_alpha = self.fade_rate_func(alpha)\n\n        if self.back_and_forth and int(time) % 2 == 1:\n            bounds = (1.0 - draw_alpha, 1.0)\n        else:\n            bounds = (0.0, draw_alpha)\n        self.full_family_become_partial(growing, vmobject, *bounds)\n        growing.set_stroke(colors[index], width=msw)\n\n        if time >= 1:\n            self.full_family_become_partial(fading, vmobject, 0, 1)\n            fading.set_stroke(color=colors[index - 1], width=(1 - fade_alpha) * msw)\n\n        self.total_time += dt\n\n    def full_family_become_partial(\n        self, mob1: VMobject, mob2: VMobject, a: float, b: float\n    ) -> Self:\n        family1 = mob1.family_members_with_points()\n        family2 = mob2.family_members_with_points()\n        for sm1, sm2 in zip(family1, family2, strict=False):\n            sm1.pointwise_become_partial(sm2, a, b)\n        return self\n\n\nclass TracedPath(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"Traces the path of a point returned by a function call.\n\n    Parameters\n    ----------\n    traced_point_func\n        The function to be traced.\n    stroke_width\n        The width of the trace.\n    stroke_color\n        The color of the trace.\n    dissipating_time\n        The time taken for the path to dissipate. Default set to ``None``\n        which disables dissipation.\n\n    Examples\n    --------\n    .. manim:: TracedPathExample\n\n        class TracedPathExample(Scene):\n            def construct(self):\n                circ = Circle(color=RED).shift(4*LEFT)\n                dot = Dot(color=RED).move_to(circ.get_start())\n                rolling_circle = VGroup(circ, dot)\n                trace = TracedPath(circ.get_start)\n                rolling_circle.add_updater(lambda m: m.rotate(-0.3))\n                self.add(trace, rolling_circle)\n                self.play(rolling_circle.animate.shift(8*RIGHT), run_time=4, rate_func=linear)\n\n    .. manim:: DissipatingPathExample\n\n        class DissipatingPathExample(Scene):\n            def construct(self):\n                a = Dot(RIGHT * 2)\n                b = TracedPath(a.get_center, dissipating_time=0.5, stroke_opacity=[0, 1])\n                self.add(a, b)\n                self.play(a.animate(path_arc=PI / 4).shift(LEFT * 2))\n                self.play(a.animate(path_arc=-PI / 4).shift(LEFT * 2))\n                self.wait()\n\n    \"\"\"\n\n    def __init__(\n        self,\n        traced_point_func: Callable,\n        stroke_width: float = 2,\n        stroke_color: ParsableManimColor | None = WHITE,\n        dissipating_time: float | None = None,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(stroke_color=stroke_color, stroke_width=stroke_width, **kwargs)\n        self.traced_point_func = traced_point_func\n        self.dissipating_time = dissipating_time\n        self.time = 1.0 if self.dissipating_time else None\n        self.add_updater(self.update_path)\n\n    def update_path(self, mob: Mobject, dt: float) -> None:\n        new_point = self.traced_point_func()\n        if not self.has_points():\n            self.start_new_path(new_point)\n        self.add_line_to(new_point)\n        if self.dissipating_time:\n            assert self.time is not None\n            self.time += dt\n            if self.time - 1 > self.dissipating_time:\n                nppcc = self.n_points_per_curve\n                self.set_points(self.points[nppcc:])\n"
  },
  {
    "path": "manim/animation/composition.py",
    "content": "\"\"\"Tools for displaying multiple animations at once.\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import Callable, Iterable, Sequence\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom manim._config import config\nfrom manim.animation.animation import Animation, prepare_animation\nfrom manim.constants import RendererType\nfrom manim.mobject.mobject import Group, Mobject\nfrom manim.mobject.opengl.opengl_mobject import OpenGLGroup, OpenGLMobject\nfrom manim.scene.scene import Scene\nfrom manim.utils.iterables import remove_list_redundancies\nfrom manim.utils.parameter_parsing import flatten_iterable_parameters\nfrom manim.utils.rate_functions import linear\n\nif TYPE_CHECKING:\n    from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVGroup\n    from manim.mobject.types.vectorized_mobject import VGroup\n\n__all__ = [\"AnimationGroup\", \"Succession\", \"LaggedStart\", \"LaggedStartMap\"]\n\n\nDEFAULT_LAGGED_START_LAG_RATIO: float = 0.05\n\n\nclass AnimationGroup(Animation):\n    \"\"\"Plays a group or series of :class:`~.Animation`.\n\n    Parameters\n    ----------\n    animations\n        Sequence of :class:`~.Animation` objects to be played.\n    group\n        A group of multiple :class:`~.Mobject`.\n    run_time\n        The duration of the animation in seconds.\n    rate_func\n        The function defining the animation progress based on the relative\n        runtime (see :mod:`~.rate_functions`) .\n    lag_ratio\n        Defines the delay after which the animation is applied to submobjects. A lag_ratio of\n        ``n.nn`` means the next animation will play when ``nnn%`` of the current animation has played.\n        Defaults to 0.0, meaning that all animations will be played together.\n\n        This does not influence the total runtime of the animation. Instead the runtime\n        of individual animations is adjusted so that the complete animation has the defined\n        run time.\n    \"\"\"\n\n    def __init__(\n        self,\n        *animations: Animation | Iterable[Animation],\n        group: Group | VGroup | OpenGLGroup | OpenGLVGroup | None = None,\n        run_time: float | None = None,\n        rate_func: Callable[[float], float] = linear,\n        lag_ratio: float = 0,\n        **kwargs: Any,\n    ):\n        arg_anim = flatten_iterable_parameters(animations)\n        self.animations = [prepare_animation(anim) for anim in arg_anim]\n        self.rate_func = rate_func\n        if group is None:\n            mobjects = remove_list_redundancies(\n                [anim.mobject for anim in self.animations if not anim.is_introducer()],\n            )\n            if config[\"renderer\"] == RendererType.OPENGL:\n                self.group: Group | VGroup | OpenGLGroup | OpenGLVGroup = OpenGLGroup(\n                    *mobjects\n                )\n            else:\n                self.group = Group(*mobjects)\n        else:\n            self.group = group\n        super().__init__(\n            self.group, rate_func=self.rate_func, lag_ratio=lag_ratio, **kwargs\n        )\n        self.run_time: float = self.init_run_time(run_time)\n\n    def get_all_mobjects(self) -> Sequence[Mobject | OpenGLMobject]:\n        return list(self.group)\n\n    def begin(self) -> None:\n        if not self.animations:\n            raise ValueError(\n                f\"Trying to play {self} without animations, this is not supported. \"\n                \"Please add at least one subanimation.\"\n            )\n        self.anim_group_time = 0.0\n        if self.suspend_mobject_updating:\n            self.group.suspend_updating()\n        for anim in self.animations:\n            anim.begin()\n\n    def _setup_scene(self, scene: Scene) -> None:\n        for anim in self.animations:\n            anim._setup_scene(scene)\n\n    def finish(self) -> None:\n        for anim in self.animations:\n            anim.finish()\n        self.anims_begun[:] = True\n        self.anims_finished[:] = True\n        if self.suspend_mobject_updating:\n            self.group.resume_updating()\n\n    def clean_up_from_scene(self, scene: Scene) -> None:\n        self._on_finish(scene)\n        for anim in self.animations:\n            if self.remover:\n                anim.remover = self.remover\n            anim.clean_up_from_scene(scene)\n\n    def update_mobjects(self, dt: float) -> None:\n        for anim in self.anims_with_timings[\"anim\"][\n            self.anims_begun & ~self.anims_finished\n        ]:\n            anim.update_mobjects(dt)\n\n    def init_run_time(self, run_time: float | None) -> float:\n        \"\"\"Calculates the run time of the animation, if different from ``run_time``.\n\n        Parameters\n        ----------\n        run_time\n            The duration of the animation in seconds.\n\n        Returns\n        -------\n        run_time\n            The duration of the animation in seconds.\n        \"\"\"\n        self.build_animations_with_timings()\n        # Note: if lag_ratio < 1, then not necessarily the final animation's\n        # end time will be the max end time! Therefore we must calculate the\n        # maximum over all the end times, and not just take the last one.\n        # Example: if you want to play 2 animations of 10s and 1s with a\n        # lag_ratio of 0.1, the 1st one will end at t=10 and the 2nd one will\n        # end at t=2, so the AnimationGroup will end at t=10.\n        self.max_end_time = max(self.anims_with_timings[\"end\"], default=0)\n        return self.max_end_time if run_time is None else run_time\n\n    def build_animations_with_timings(self) -> None:\n        \"\"\"Creates a list of triplets of the form (anim, start_time, end_time).\"\"\"\n        run_times = np.array([anim.run_time for anim in self.animations])\n        num_animations = run_times.shape[0]\n        dtype = [(\"anim\", \"O\"), (\"start\", \"f8\"), (\"end\", \"f8\")]\n        self.anims_with_timings: np.ndarray = np.zeros(num_animations, dtype=dtype)\n        self.anims_begun: np.ndarray = np.zeros(num_animations, dtype=bool)\n        self.anims_finished: np.ndarray = np.zeros(num_animations, dtype=bool)\n        if num_animations == 0:\n            return\n\n        lags = run_times[:-1] * self.lag_ratio\n        self.anims_with_timings[\"anim\"] = self.animations\n        self.anims_with_timings[\"start\"][1:] = np.add.accumulate(lags)\n        self.anims_with_timings[\"end\"] = self.anims_with_timings[\"start\"] + run_times\n\n    def interpolate(self, alpha: float) -> None:\n        # Note, if the run_time of AnimationGroup has been\n        # set to something other than its default, these\n        # times might not correspond to actual times,\n        # e.g. of the surrounding scene.  Instead they'd\n        # be a rescaled version.  But that's okay!\n        anim_group_time = self.rate_func(alpha) * self.max_end_time\n        time_goes_back = anim_group_time < self.anim_group_time\n\n        # Only update ongoing animations\n        awt = self.anims_with_timings\n        new_begun = anim_group_time >= awt[\"start\"]\n        new_finished = anim_group_time > awt[\"end\"]\n        to_update = awt[\n            (self.anims_begun | new_begun) & (~self.anims_finished | ~new_finished)\n        ]\n\n        run_times = to_update[\"end\"] - to_update[\"start\"]\n        with_zero_run_time = run_times == 0\n        run_times[with_zero_run_time] = 1\n        sub_alphas = (anim_group_time - to_update[\"start\"]) / run_times\n        if time_goes_back:\n            sub_alphas[(sub_alphas < 0) | with_zero_run_time] = 0\n        else:\n            sub_alphas[(sub_alphas > 1) | with_zero_run_time] = 1\n\n        for anim_to_update, sub_alpha in zip(\n            to_update[\"anim\"], sub_alphas, strict=True\n        ):\n            anim_to_update.interpolate(sub_alpha)\n\n        self.anim_group_time = anim_group_time\n        self.anims_begun = new_begun\n        self.anims_finished = new_finished\n\n\nclass Succession(AnimationGroup):\n    \"\"\"Plays a series of animations in succession.\n\n    Parameters\n    ----------\n    animations\n        Sequence of :class:`~.Animation` objects to be played.\n    lag_ratio\n        Defines the delay after which the animation is applied to submobjects. A lag_ratio of\n        ``n.nn`` means the next animation will play when ``nnn%`` of the current animation has played.\n        Defaults to 1.0, meaning that the next animation will begin when 100% of the current\n        animation has played.\n\n        This does not influence the total runtime of the animation. Instead the runtime\n        of individual animations is adjusted so that the complete animation has the defined\n        run time.\n\n    Examples\n    --------\n    .. manim:: SuccessionExample\n\n        class SuccessionExample(Scene):\n            def construct(self):\n                dot1 = Dot(point=LEFT * 2 + UP * 2, radius=0.16, color=BLUE)\n                dot2 = Dot(point=LEFT * 2 + DOWN * 2, radius=0.16, color=MAROON)\n                dot3 = Dot(point=RIGHT * 2 + DOWN * 2, radius=0.16, color=GREEN)\n                dot4 = Dot(point=RIGHT * 2 + UP * 2, radius=0.16, color=YELLOW)\n                self.add(dot1, dot2, dot3, dot4)\n\n                self.play(Succession(\n                    dot1.animate.move_to(dot2),\n                    dot2.animate.move_to(dot3),\n                    dot3.animate.move_to(dot4),\n                    dot4.animate.move_to(dot1)\n                ))\n    \"\"\"\n\n    def __init__(self, *animations: Animation, lag_ratio: float = 1, **kwargs: Any):\n        super().__init__(*animations, lag_ratio=lag_ratio, **kwargs)\n\n    def begin(self) -> None:\n        if not self.animations:\n            raise ValueError(\n                f\"Trying to play {self} without animations, this is not supported. \"\n                \"Please add at least one subanimation.\"\n            )\n        self.update_active_animation(0)\n\n    def finish(self) -> None:\n        while self.active_animation is not None:\n            self.next_animation()\n\n    def update_mobjects(self, dt: float) -> None:\n        if self.active_animation:\n            self.active_animation.update_mobjects(dt)\n\n    def _setup_scene(self, scene: Scene | None) -> None:\n        if scene is None:\n            return\n        if self.is_introducer():\n            for anim in self.animations:\n                if not anim.is_introducer() and anim.mobject is not None:\n                    scene.add(anim.mobject)\n\n        self.scene = scene\n\n    def update_active_animation(self, index: int) -> None:\n        self.active_index = index\n        if index >= len(self.animations):\n            self.active_animation: Animation | None = None\n            self.active_start_time: float | None = None\n            self.active_end_time: float | None = None\n        else:\n            self.active_animation = self.animations[index]\n            self.active_animation._setup_scene(self.scene)\n            self.active_animation.begin()\n            self.active_start_time = self.anims_with_timings[index][\"start\"]\n            self.active_end_time = self.anims_with_timings[index][\"end\"]\n\n    def next_animation(self) -> None:\n        \"\"\"Proceeds to the next animation.\n\n        This method is called right when the active animation finishes.\n        \"\"\"\n        if self.active_animation is not None:\n            self.active_animation.finish()\n        self.update_active_animation(self.active_index + 1)\n\n    def interpolate(self, alpha: float) -> None:\n        current_time = self.rate_func(alpha) * self.max_end_time\n        while self.active_end_time is not None and current_time >= self.active_end_time:\n            self.next_animation()\n        if self.active_animation is not None and self.active_start_time is not None:\n            elapsed = current_time - self.active_start_time\n            active_run_time = self.active_animation.run_time\n            subalpha = elapsed / active_run_time if active_run_time != 0.0 else 1.0\n            self.active_animation.interpolate(subalpha)\n\n\nclass LaggedStart(AnimationGroup):\n    \"\"\"Adjusts the timing of a series of :class:`~.Animation` according to ``lag_ratio``.\n\n    Parameters\n    ----------\n    animations\n        Sequence of :class:`~.Animation` objects to be played.\n    lag_ratio\n        Defines the delay after which the animation is applied to submobjects. A lag_ratio of\n        ``n.nn`` means the next animation will play when ``nnn%`` of the current animation has played.\n        Defaults to 0.05, meaning that the next animation will begin when 5% of the current\n        animation has played.\n\n        This does not influence the total runtime of the animation. Instead the runtime\n        of individual animations is adjusted so that the complete animation has the defined\n        run time.\n\n    Examples\n    --------\n    .. manim:: LaggedStartExample\n\n        class LaggedStartExample(Scene):\n            def construct(self):\n                title = Text(\"lag_ratio = 0.25\").to_edge(UP)\n\n                dot1 = Dot(point=LEFT * 2 + UP, radius=0.16)\n                dot2 = Dot(point=LEFT * 2, radius=0.16)\n                dot3 = Dot(point=LEFT * 2 + DOWN, radius=0.16)\n                line_25 = DashedLine(\n                    start=LEFT + UP * 2,\n                    end=LEFT + DOWN * 2,\n                    color=RED\n                )\n                label = Text(\"25%\", font_size=24).next_to(line_25, UP)\n                self.add(title, dot1, dot2, dot3, line_25, label)\n\n                self.play(LaggedStart(\n                    dot1.animate.shift(RIGHT * 4),\n                    dot2.animate.shift(RIGHT * 4),\n                    dot3.animate.shift(RIGHT * 4),\n                    lag_ratio=0.25,\n                    run_time=4\n                ))\n    \"\"\"\n\n    def __init__(\n        self,\n        *animations: Animation,\n        lag_ratio: float = DEFAULT_LAGGED_START_LAG_RATIO,\n        **kwargs: Any,\n    ):\n        super().__init__(*animations, lag_ratio=lag_ratio, **kwargs)\n\n\nclass LaggedStartMap(LaggedStart):\n    \"\"\"Plays a series of :class:`~.Animation` while mapping a function to submobjects.\n\n    Parameters\n    ----------\n    animation_class\n        :class:`~.Animation` to apply to mobject.\n    mobject\n        :class:`~.Mobject` whose submobjects the animation, and optionally the function,\n        are to be applied.\n    arg_creator\n        Function which will be applied to :class:`~.Mobject`.\n    run_time\n        The duration of the animation in seconds.\n    lag_ratio\n        Defines the delay after which the animation is applied to submobjects. A lag_ratio of\n        ``n.nn`` means the next animation will play when ``nnn%`` of the current animation has played.\n        Defaults to 0.05, meaning that the next animation will begin when 5% of the current\n        animation has played.\n\n        This does not influence the total runtime of the animation. Instead the runtime\n        of individual animations is adjusted so that the complete animation has the defined\n        run time.\n    kwargs\n        Further keyword arguments that are passed to `animation_class`.\n\n    Examples\n    --------\n    .. manim:: LaggedStartMapExample\n\n        class LaggedStartMapExample(Scene):\n            def construct(self):\n                title = Tex(\"LaggedStartMap\").to_edge(UP, buff=LARGE_BUFF)\n                dots = VGroup(\n                    *[Dot(radius=0.16) for _ in range(35)]\n                    ).arrange_in_grid(rows=5, cols=7, buff=MED_LARGE_BUFF)\n                self.add(dots, title)\n\n                # Animate yellow ripple effect\n                for mob in dots, title:\n                    self.play(LaggedStartMap(\n                        ApplyMethod, mob,\n                        lambda m : (m.set_color, YELLOW),\n                        lag_ratio = 0.1,\n                        rate_func = there_and_back,\n                        run_time = 2\n                    ))\n    \"\"\"\n\n    def __init__(\n        self,\n        animation_class: type[Animation],\n        mobject: Mobject,\n        arg_creator: Callable[[Mobject], Iterable[Any]] | None = None,\n        run_time: float = 2,\n        lag_ratio: float = DEFAULT_LAGGED_START_LAG_RATIO,\n        **kwargs: Any,\n    ):\n        if arg_creator is None:\n\n            def identity(mob: Mobject) -> Mobject:\n                return mob\n\n            arg_creator = identity\n\n        args_list = [arg_creator(submob) for submob in mobject]\n        anim_kwargs = dict(kwargs)\n        if \"lag_ratio\" in anim_kwargs:\n            anim_kwargs.pop(\"lag_ratio\")\n        animations = [animation_class(*args, **anim_kwargs) for args in args_list]\n        super().__init__(*animations, run_time=run_time, lag_ratio=lag_ratio)\n"
  },
  {
    "path": "manim/animation/creation.py",
    "content": "r\"\"\"Animate the display or removal of a mobject from a scene.\n\n.. manim:: CreationModule\n    :hide_source:\n\n    from manim import ManimBanner\n    class CreationModule(Scene):\n        def construct(self):\n            s1 = Square()\n            s2 = Square()\n            s3 = Square()\n            s4 = Square()\n            VGroup(s1, s2, s3, s4).set_x(0).arrange(buff=1.9).shift(UP)\n            s5 = Square()\n            s6 = Square()\n            s7 = Square()\n            VGroup(s5, s6, s7).set_x(0).arrange(buff=2.6).shift(2 * DOWN)\n            t1 = Text(\"Write\", font_size=24).next_to(s1, UP)\n            t2 = Text(\"AddTextLetterByLetter\", font_size=24).next_to(s2, UP)\n            t3 = Text(\"Create\", font_size=24).next_to(s3, UP)\n            t4 = Text(\"Uncreate\", font_size=24).next_to(s4, UP)\n            t5 = Text(\"DrawBorderThenFill\", font_size=24).next_to(s5, UP)\n            t6 = Text(\"ShowIncreasingSubsets\", font_size=22).next_to(s6, UP)\n            t7 = Text(\"ShowSubmobjectsOneByOne\", font_size=22).next_to(s7, UP)\n\n            self.add(s1, s2, s3, s4, s5, s6, s7, t1, t2, t3, t4, t5, t6, t7)\n\n            texts = [Text(\"manim\", font_size=29), Text(\"manim\", font_size=29)]\n            texts[0].move_to(s1.get_center())\n            texts[1].move_to(s2.get_center())\n            self.add(*texts)\n\n            objs = [ManimBanner().scale(0.25) for _ in range(5)]\n            objs[0].move_to(s3.get_center())\n            objs[1].move_to(s4.get_center())\n            objs[2].move_to(s5.get_center())\n            objs[3].move_to(s6.get_center())\n            objs[4].move_to(s7.get_center())\n            self.add(*objs)\n\n            self.play(\n                # text creation\n                Write(texts[0]),\n                AddTextLetterByLetter(texts[1]),\n                # mobject creation\n                Create(objs[0]),\n                Uncreate(objs[1]),\n                DrawBorderThenFill(objs[2]),\n                ShowIncreasingSubsets(objs[3]),\n                ShowSubmobjectsOneByOne(objs[4]),\n                run_time=3,\n            )\n\n            self.wait()\n\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"Create\",\n    \"Uncreate\",\n    \"DrawBorderThenFill\",\n    \"Write\",\n    \"Unwrite\",\n    \"ShowPartial\",\n    \"ShowIncreasingSubsets\",\n    \"SpiralIn\",\n    \"AddTextLetterByLetter\",\n    \"RemoveTextLetterByLetter\",\n    \"ShowSubmobjectsOneByOne\",\n    \"AddTextWordByWord\",\n    \"TypeWithCursor\",\n    \"UntypeWithCursor\",\n]\n\n\nimport itertools as it\nfrom collections.abc import Callable, Iterable, Sequence\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\n\nif TYPE_CHECKING:\n    from manim.mobject.text.text_mobject import Text\n    from manim.scene.scene import Scene\n\nfrom manim.constants import RIGHT, TAU\nfrom manim.mobject.opengl.opengl_surface import OpenGLSurface\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject\nfrom manim.utils.color import ManimColor\n\nfrom .. import config\nfrom ..animation.animation import Animation\nfrom ..animation.composition import Succession\nfrom ..mobject.mobject import Group, Mobject\nfrom ..mobject.types.vectorized_mobject import VMobject\nfrom ..utils.bezier import integer_interpolate\nfrom ..utils.rate_functions import double_smooth, linear\n\n\nclass ShowPartial(Animation):\n    \"\"\"Abstract class for Animations that show the VMobject partially.\n\n    Raises\n    ------\n    :class:`TypeError`\n        If ``mobject`` is not an instance of :class:`~.VMobject`.\n\n    See Also\n    --------\n    :class:`Create`, :class:`~.ShowPassingFlash`\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: VMobject | OpenGLVMobject | OpenGLSurface | None,\n        **kwargs,\n    ):\n        pointwise = getattr(mobject, \"pointwise_become_partial\", None)\n        if not callable(pointwise):\n            raise TypeError(f\"{self.__class__.__name__} only works for VMobjects.\")\n        super().__init__(mobject, **kwargs)\n\n    def interpolate_submobject(\n        self,\n        submobject: Mobject,\n        starting_submobject: Mobject,\n        alpha: float,\n    ) -> None:\n        submobject.pointwise_become_partial(\n            starting_submobject, *self._get_bounds(alpha)\n        )\n\n    def _get_bounds(self, alpha: float) -> tuple[float, float]:\n        raise NotImplementedError(\"Please use Create or ShowPassingFlash\")\n\n\nclass Create(ShowPartial):\n    \"\"\"Incrementally show a VMobject.\n\n    Parameters\n    ----------\n    mobject\n        The VMobject to animate.\n\n    Raises\n    ------\n    :class:`TypeError`\n        If ``mobject`` is not an instance of :class:`~.VMobject`.\n\n    Examples\n    --------\n    .. manim:: CreateScene\n\n        class CreateScene(Scene):\n            def construct(self):\n                self.play(Create(Square()))\n\n    See Also\n    --------\n    :class:`~.ShowPassingFlash`\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: VMobject | OpenGLVMobject | OpenGLSurface,\n        lag_ratio: float = 1.0,\n        introducer: bool = True,\n        **kwargs,\n    ) -> None:\n        super().__init__(mobject, lag_ratio=lag_ratio, introducer=introducer, **kwargs)\n\n    def _get_bounds(self, alpha: float) -> tuple[float, float]:\n        return (0, alpha)\n\n\nclass Uncreate(Create):\n    \"\"\"Like :class:`Create` but in reverse.\n\n    Examples\n    --------\n    .. manim:: ShowUncreate\n\n        class ShowUncreate(Scene):\n            def construct(self):\n                self.play(Uncreate(Square()))\n\n    See Also\n    --------\n    :class:`Create`\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: VMobject | OpenGLVMobject,\n        reverse_rate_function: bool = True,\n        remover: bool = True,\n        **kwargs,\n    ) -> None:\n        super().__init__(\n            mobject,\n            reverse_rate_function=reverse_rate_function,\n            introducer=False,\n            remover=remover,\n            **kwargs,\n        )\n\n\nclass DrawBorderThenFill(Animation):\n    \"\"\"Draw the border first and then show the fill.\n\n    Examples\n    --------\n    .. manim:: ShowDrawBorderThenFill\n\n        class ShowDrawBorderThenFill(Scene):\n            def construct(self):\n                self.play(DrawBorderThenFill(Square(fill_opacity=1, fill_color=ORANGE)))\n    \"\"\"\n\n    def __init__(\n        self,\n        vmobject: VMobject | OpenGLVMobject,\n        run_time: float = 2,\n        rate_func: Callable[[float], float] = double_smooth,\n        stroke_width: float = 2,\n        stroke_color: str = None,\n        introducer: bool = True,\n        **kwargs,\n    ) -> None:\n        self._typecheck_input(vmobject)\n        super().__init__(\n            vmobject,\n            run_time=run_time,\n            introducer=introducer,\n            rate_func=rate_func,\n            **kwargs,\n        )\n        self.stroke_width = stroke_width\n        self.stroke_color = stroke_color\n        self.outline = self.get_outline()\n\n    def _typecheck_input(self, vmobject: VMobject | OpenGLVMobject) -> None:\n        if not isinstance(vmobject, (VMobject, OpenGLVMobject)):\n            raise TypeError(\n                f\"{self.__class__.__name__} only works for vectorized Mobjects\"\n            )\n\n    def begin(self) -> None:\n        self.outline = self.get_outline()\n        super().begin()\n\n    def get_outline(self) -> Mobject:\n        outline = self.mobject.copy()\n        outline.set_fill(opacity=0)\n        for sm in outline.family_members_with_points():\n            sm.set_stroke(color=self.get_stroke_color(sm), width=self.stroke_width)\n        return outline\n\n    def get_stroke_color(self, vmobject: VMobject | OpenGLVMobject) -> ManimColor:\n        if self.stroke_color:\n            return self.stroke_color\n        elif vmobject.get_stroke_width() > 0:\n            return vmobject.get_stroke_color()\n        return vmobject.get_color()\n\n    def get_all_mobjects(self) -> Sequence[Mobject]:\n        return [*super().get_all_mobjects(), self.outline]\n\n    def interpolate_submobject(\n        self,\n        submobject: Mobject,\n        starting_submobject: Mobject,\n        outline,\n        alpha: float,\n    ) -> None:  # Fixme: not matching the parent class? What is outline doing here?\n        index: int\n        subalpha: float\n        index, subalpha = integer_interpolate(0, 2, alpha)\n        if index == 0:\n            submobject.pointwise_become_partial(outline, 0, subalpha)\n            submobject.match_style(outline)\n        else:\n            submobject.interpolate(outline, starting_submobject, subalpha)\n\n\nclass Write(DrawBorderThenFill):\n    \"\"\"Simulate hand-writing a :class:`~.Text` or hand-drawing a :class:`~.VMobject`.\n\n    Examples\n    --------\n    .. manim:: ShowWrite\n\n        class ShowWrite(Scene):\n            def construct(self):\n                self.play(Write(Text(\"Hello\", font_size=144)))\n\n    .. manim:: ShowWriteReversed\n\n        class ShowWriteReversed(Scene):\n            def construct(self):\n                self.play(Write(Text(\"Hello\", font_size=144), reverse=True, remover=False))\n\n    Tests\n    -----\n\n    Check that creating empty :class:`.Write` animations works::\n\n        >>> from manim import Write, Text\n        >>> Write(Text(''))\n        Write(Text(''))\n    \"\"\"\n\n    def __init__(\n        self,\n        vmobject: VMobject | OpenGLVMobject,\n        rate_func: Callable[[float], float] = linear,\n        reverse: bool = False,\n        **kwargs,\n    ) -> None:\n        run_time: float | None = kwargs.pop(\"run_time\", None)\n        lag_ratio: float | None = kwargs.pop(\"lag_ratio\", None)\n        run_time, lag_ratio = self._set_default_config_from_length(\n            vmobject,\n            run_time,\n            lag_ratio,\n        )\n        self.reverse = reverse\n        if \"remover\" not in kwargs:\n            kwargs[\"remover\"] = reverse\n        super().__init__(\n            vmobject,\n            rate_func=rate_func,\n            run_time=run_time,\n            lag_ratio=lag_ratio,\n            introducer=not reverse,\n            **kwargs,\n        )\n\n    def _set_default_config_from_length(\n        self,\n        vmobject: VMobject | OpenGLVMobject,\n        run_time: float | None,\n        lag_ratio: float | None,\n    ) -> tuple[float, float]:\n        length = len(vmobject.family_members_with_points())\n        if run_time is None:\n            run_time = 1 if length < 15 else 2\n        if lag_ratio is None:\n            lag_ratio = min(4.0 / max(1.0, length), 0.2)\n        return run_time, lag_ratio\n\n    def reverse_submobjects(self) -> None:\n        self.mobject.invert(recursive=True)\n\n    def begin(self) -> None:\n        if self.reverse:\n            self.reverse_submobjects()\n        super().begin()\n\n    def finish(self) -> None:\n        super().finish()\n        if self.reverse:\n            self.reverse_submobjects()\n\n\nclass Unwrite(Write):\n    \"\"\"Simulate erasing by hand a :class:`~.Text` or a :class:`~.VMobject`.\n\n    Parameters\n    ----------\n    reverse\n        Set True to have the animation start erasing from the last submobject first.\n\n    Examples\n    --------\n\n    .. manim :: UnwriteReverseTrue\n\n        class UnwriteReverseTrue(Scene):\n            def construct(self):\n                text = Tex(\"Alice and Bob\").scale(3)\n                self.add(text)\n                self.play(Unwrite(text))\n\n    .. manim:: UnwriteReverseFalse\n\n        class UnwriteReverseFalse(Scene):\n            def construct(self):\n                text = Tex(\"Alice and Bob\").scale(3)\n                self.add(text)\n                self.play(Unwrite(text, reverse=False))\n    \"\"\"\n\n    def __init__(\n        self,\n        vmobject: VMobject,\n        rate_func: Callable[[float], float] = linear,\n        reverse: bool = True,\n        **kwargs,\n    ) -> None:\n        run_time: float | None = kwargs.pop(\"run_time\", None)\n        lag_ratio: float | None = kwargs.pop(\"lag_ratio\", None)\n        run_time, lag_ratio = self._set_default_config_from_length(\n            vmobject,\n            run_time,\n            lag_ratio,\n        )\n        super().__init__(\n            vmobject,\n            run_time=run_time,\n            lag_ratio=lag_ratio,\n            reverse_rate_function=True,\n            reverse=reverse,\n            **kwargs,\n        )\n\n\nclass SpiralIn(Animation):\n    r\"\"\"Create the Mobject with sub-Mobjects flying in on spiral trajectories.\n\n    Parameters\n    ----------\n    shapes\n        The Mobject on which to be operated.\n\n    scale_factor\n        The factor used for scaling the effect.\n\n    fade_in_fraction\n        Fractional duration of initial fade-in of sub-Mobjects as they fly inward.\n\n    Examples\n    --------\n    .. manim :: SpiralInExample\n\n        class SpiralInExample(Scene):\n            def construct(self):\n                pi = MathTex(r\"\\pi\").scale(7)\n                pi.shift(2.25 * LEFT + 1.5 * UP)\n                circle = Circle(color=GREEN_C, fill_opacity=1).shift(LEFT)\n                square = Square(color=BLUE_D, fill_opacity=1).shift(UP)\n                shapes = VGroup(pi, circle, square)\n                self.play(SpiralIn(shapes))\n    \"\"\"\n\n    def __init__(\n        self,\n        shapes: Mobject,\n        scale_factor: float = 8,\n        fade_in_fraction=0.3,\n        **kwargs,\n    ) -> None:\n        self.shapes = shapes.copy()\n        self.scale_factor = scale_factor\n        self.shape_center = shapes.get_center()\n        self.fade_in_fraction = fade_in_fraction\n        for shape in shapes:\n            shape.final_position = shape.get_center()\n            shape.initial_position = (\n                shape.final_position\n                + (shape.final_position - self.shape_center) * self.scale_factor\n            )\n            shape.move_to(shape.initial_position)\n            shape.save_state()\n\n        super().__init__(shapes, introducer=True, **kwargs)\n\n    def interpolate_mobject(self, alpha: float) -> None:\n        alpha = self.rate_func(alpha)\n        for original_shape, shape in zip(self.shapes, self.mobject, strict=True):\n            shape.restore()\n            fill_opacity = original_shape.get_fill_opacity()\n            stroke_opacity = original_shape.get_stroke_opacity()\n            new_fill_opacity = min(\n                fill_opacity, alpha * fill_opacity / self.fade_in_fraction\n            )\n            new_stroke_opacity = min(\n                stroke_opacity, alpha * stroke_opacity / self.fade_in_fraction\n            )\n            shape.shift((shape.final_position - shape.initial_position) * alpha)\n            shape.rotate(TAU * alpha, about_point=self.shape_center)\n            shape.rotate(-TAU * alpha, about_point=shape.get_center_of_mass())\n            shape.set_fill(opacity=new_fill_opacity)\n            shape.set_stroke(opacity=new_stroke_opacity)\n\n\nclass ShowIncreasingSubsets(Animation):\n    \"\"\"Show one submobject at a time, leaving all previous ones displayed on screen.\n\n    Examples\n    --------\n\n    .. manim:: ShowIncreasingSubsetsScene\n\n        class ShowIncreasingSubsetsScene(Scene):\n            def construct(self):\n                p = VGroup(Dot(), Square(), Triangle())\n                self.add(p)\n                self.play(ShowIncreasingSubsets(p))\n                self.wait()\n    \"\"\"\n\n    def __init__(\n        self,\n        group: Mobject,\n        suspend_mobject_updating: bool = False,\n        int_func: Callable[[np.ndarray], np.ndarray] = np.floor,\n        reverse_rate_function=False,\n        **kwargs,\n    ) -> None:\n        self.all_submobs = list(group.submobjects)\n        self.int_func = int_func\n        for mobj in self.all_submobs:\n            mobj.set_opacity(0)\n        super().__init__(\n            group,\n            suspend_mobject_updating=suspend_mobject_updating,\n            reverse_rate_function=reverse_rate_function,\n            **kwargs,\n        )\n\n    def interpolate_mobject(self, alpha: float) -> None:\n        n_submobs = len(self.all_submobs)\n        value = (\n            1 - self.rate_func(alpha)\n            if self.reverse_rate_function\n            else self.rate_func(alpha)\n        )\n        index = int(self.int_func(value * n_submobs))\n        self.update_submobject_list(index)\n\n    def update_submobject_list(self, index: int) -> None:\n        for mobj in self.all_submobs[:index]:\n            mobj.set_opacity(1)\n        for mobj in self.all_submobs[index:]:\n            mobj.set_opacity(0)\n\n\nclass AddTextLetterByLetter(ShowIncreasingSubsets):\n    \"\"\"Show a :class:`~.Text` letter by letter on the scene.\n\n    Parameters\n    ----------\n    time_per_char\n        Frequency of appearance of the letters.\n\n    .. tip::\n\n        This is currently only possible for class:`~.Text` and not for class:`~.MathTex`\n\n    \"\"\"\n\n    def __init__(\n        self,\n        text: Text,\n        suspend_mobject_updating: bool = False,\n        int_func: Callable[[np.ndarray], np.ndarray] = np.ceil,\n        rate_func: Callable[[float], float] = linear,\n        time_per_char: float = 0.1,\n        run_time: float | None = None,\n        reverse_rate_function=False,\n        introducer=True,\n        **kwargs,\n    ) -> None:\n        self.time_per_char = time_per_char\n        # Check for empty text using family_members_with_points()\n        if not text.family_members_with_points():\n            raise ValueError(\n                f\"The text mobject {text} does not seem to contain any characters.\"\n            )\n        if run_time is None:\n            # minimum time per character is 1/frame_rate, otherwise\n            # the animation does not finish.\n            run_time = np.max((1 / config.frame_rate, self.time_per_char)) * len(text)\n        super().__init__(\n            text,\n            suspend_mobject_updating=suspend_mobject_updating,\n            int_func=int_func,\n            rate_func=rate_func,\n            run_time=run_time,\n            reverse_rate_function=reverse_rate_function,\n            introducer=introducer,\n            **kwargs,\n        )\n\n\nclass RemoveTextLetterByLetter(AddTextLetterByLetter):\n    \"\"\"Remove a :class:`~.Text` letter by letter from the scene.\n\n    Parameters\n    ----------\n    time_per_char\n        Frequency of appearance of the letters.\n\n    .. tip::\n\n        This is currently only possible for class:`~.Text` and not for class:`~.MathTex`\n\n    \"\"\"\n\n    def __init__(\n        self,\n        text: Text,\n        suspend_mobject_updating: bool = False,\n        int_func: Callable[[np.ndarray], np.ndarray] = np.ceil,\n        rate_func: Callable[[float], float] = linear,\n        time_per_char: float = 0.1,\n        run_time: float | None = None,\n        reverse_rate_function=True,\n        introducer=False,\n        remover=True,\n        **kwargs,\n    ) -> None:\n        super().__init__(\n            text,\n            suspend_mobject_updating=suspend_mobject_updating,\n            int_func=int_func,\n            rate_func=rate_func,\n            time_per_char=time_per_char,\n            run_time=run_time,\n            reverse_rate_function=reverse_rate_function,\n            introducer=introducer,\n            remover=remover,\n            **kwargs,\n        )\n\n\nclass ShowSubmobjectsOneByOne(ShowIncreasingSubsets):\n    \"\"\"Show one submobject at a time, removing all previously displayed ones from screen.\"\"\"\n\n    def __init__(\n        self,\n        group: Iterable[Mobject],\n        int_func: Callable[[np.ndarray], np.ndarray] = np.ceil,\n        **kwargs,\n    ) -> None:\n        new_group = Group(*group)\n        super().__init__(new_group, int_func=int_func, **kwargs)\n\n    def update_submobject_list(self, index: int) -> None:\n        current_submobjects = self.all_submobs[:index]\n        for mobj in current_submobjects[:-1]:\n            mobj.set_opacity(0)\n        if len(current_submobjects) > 0:\n            current_submobjects[-1].set_opacity(1)\n\n\n# TODO, this is broken...\nclass AddTextWordByWord(Succession):\n    \"\"\"Show a :class:`~.Text` word by word on the scene. Note: currently broken.\"\"\"\n\n    def __init__(\n        self,\n        text_mobject: Text,\n        run_time: float = None,\n        time_per_char: float = 0.06,\n        **kwargs,\n    ) -> None:\n        self.time_per_char = time_per_char\n        tpc = self.time_per_char\n        anims = it.chain(\n            *(\n                [\n                    ShowIncreasingSubsets(word, run_time=tpc * len(word)),\n                    Animation(word, run_time=0.005 * len(word) ** 1.5),\n                ]\n                for word in text_mobject\n            )\n        )\n        super().__init__(*anims, **kwargs)\n\n\nclass TypeWithCursor(AddTextLetterByLetter):\n    \"\"\"Similar to :class:`~.AddTextLetterByLetter` , but with an additional cursor mobject at the end.\n\n    Parameters\n    ----------\n    time_per_char\n        Frequency of appearance of the letters.\n    cursor\n        :class:`~.Mobject` shown after the last added letter.\n    buff\n        Controls how far away the cursor is to the right of the last added letter.\n    keep_cursor_y\n        If ``True``, the cursor's y-coordinate is set to the center of the ``Text`` and remains the same throughout the animation. Otherwise, it is set to the center of the last added letter.\n    leave_cursor_on\n        Whether to show the cursor after the animation.\n\n    .. tip::\n        This is currently only possible for class:`~.Text` and not for class:`~.MathTex`.\n\n\n    Examples\n    --------\n\n    .. manim:: InsertingTextExample\n        :ref_classes: Blink\n\n        class InsertingTextExample(Scene):\n            def construct(self):\n                text = Text(\"Inserting\", color=PURPLE).scale(1.5).to_edge(LEFT)\n                cursor = Rectangle(\n                    color = GREY_A,\n                    fill_color = GREY_A,\n                    fill_opacity = 1.0,\n                    height = 1.1,\n                    width = 0.5,\n                ).move_to(text[0]) # Position the cursor\n\n                self.play(TypeWithCursor(text, cursor))\n                self.play(Blink(cursor, blinks=2))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        text: Text,\n        cursor: Mobject,\n        buff: float = 0.1,\n        keep_cursor_y: bool = True,\n        leave_cursor_on: bool = True,\n        time_per_char: float = 0.1,\n        reverse_rate_function=False,\n        introducer=True,\n        **kwargs,\n    ) -> None:\n        self.cursor = cursor\n        self.buff = buff\n        self.keep_cursor_y = keep_cursor_y\n        self.leave_cursor_on = leave_cursor_on\n        super().__init__(\n            text,\n            time_per_char=time_per_char,\n            reverse_rate_function=reverse_rate_function,\n            introducer=introducer,\n            **kwargs,\n        )\n\n    def begin(self) -> None:\n        self.y_cursor = self.cursor.get_y()\n        self.cursor.initial_position = self.mobject.get_center()\n        if self.keep_cursor_y:\n            self.cursor.set_y(self.y_cursor)\n\n        self.cursor.set_opacity(0)\n        self.mobject.add(self.cursor)\n        super().begin()\n\n    def finish(self) -> None:\n        if self.leave_cursor_on:\n            self.cursor.set_opacity(1)\n        else:\n            self.cursor.set_opacity(0)\n            self.mobject.remove(self.cursor)\n        super().finish()\n\n    def clean_up_from_scene(self, scene: Scene) -> None:\n        if not self.leave_cursor_on:\n            scene.remove(self.cursor)\n        super().clean_up_from_scene(scene)\n\n    def update_submobject_list(self, index: int) -> None:\n        for mobj in self.all_submobs[:index]:\n            mobj.set_opacity(1)\n\n        for mobj in self.all_submobs[index:]:\n            mobj.set_opacity(0)\n\n        if index != 0:\n            self.cursor.next_to(\n                self.all_submobs[index - 1], RIGHT, buff=self.buff\n            ).set_y(self.cursor.initial_position[1])\n        else:\n            self.cursor.move_to(self.all_submobs[0]).set_y(\n                self.cursor.initial_position[1]\n            )\n\n        if self.keep_cursor_y:\n            self.cursor.set_y(self.y_cursor)\n        self.cursor.set_opacity(1)\n\n\nclass UntypeWithCursor(TypeWithCursor):\n    \"\"\"Similar to :class:`~.RemoveTextLetterByLetter` , but with an additional cursor mobject at the end.\n\n    Parameters\n    ----------\n    time_per_char\n        Frequency of appearance of the letters.\n    cursor\n        :class:`~.Mobject` shown after the last added letter.\n    buff\n        Controls how far away the cursor is to the right of the last added letter.\n    keep_cursor_y\n        If ``True``, the cursor's y-coordinate is set to the center of the ``Text`` and remains the same throughout the animation. Otherwise, it is set to the center of the last added letter.\n    leave_cursor_on\n        Whether to show the cursor after the animation.\n\n    .. tip::\n        This is currently only possible for class:`~.Text` and not for class:`~.MathTex`.\n\n\n    Examples\n    --------\n\n    .. manim:: DeletingTextExample\n        :ref_classes: Blink\n\n        class DeletingTextExample(Scene):\n            def construct(self):\n                text = Text(\"Deleting\", color=PURPLE).scale(1.5).to_edge(LEFT)\n                cursor = Rectangle(\n                    color = GREY_A,\n                    fill_color = GREY_A,\n                    fill_opacity = 1.0,\n                    height = 1.1,\n                    width = 0.5,\n                ).move_to(text[0]) # Position the cursor\n\n                self.play(UntypeWithCursor(text, cursor))\n                self.play(Blink(cursor, blinks=2))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        text: Text,\n        cursor: VMobject | None = None,\n        time_per_char: float = 0.1,\n        reverse_rate_function=True,\n        introducer=False,\n        remover=True,\n        **kwargs,\n    ) -> None:\n        super().__init__(\n            text,\n            cursor=cursor,\n            time_per_char=time_per_char,\n            reverse_rate_function=reverse_rate_function,\n            introducer=introducer,\n            remover=remover,\n            **kwargs,\n        )\n"
  },
  {
    "path": "manim/animation/fading.py",
    "content": "\"\"\"Fading in and out of view.\n\n.. manim:: Fading\n\n    class Fading(Scene):\n        def construct(self):\n            tex_in = Tex(\"Fade\", \"In\").scale(3)\n            tex_out = Tex(\"Fade\", \"Out\").scale(3)\n            self.play(FadeIn(tex_in, shift=DOWN, scale=0.66))\n            self.play(ReplacementTransform(tex_in, tex_out))\n            self.play(FadeOut(tex_out, shift=DOWN * 2, scale=1.5))\n\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"FadeOut\",\n    \"FadeIn\",\n]\n\nfrom typing import Any\n\nimport numpy as np\n\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\n\nfrom ..animation.transform import Transform\nfrom ..constants import ORIGIN\nfrom ..mobject.mobject import Group, Mobject\nfrom ..scene.scene import Scene\n\n\nclass _Fade(Transform):\n    \"\"\"Fade :class:`~.Mobject` s in or out.\n\n    Parameters\n    ----------\n    mobjects\n        The mobjects to be faded.\n    shift\n        The vector by which the mobject shifts while being faded.\n    target_position\n        The position to/from which the mobject moves while being faded in. In case\n        another mobject is given as target position, its center is used.\n    scale\n        The factor by which the mobject is scaled initially before being rescaling to\n        its original size while being faded in.\n\n    \"\"\"\n\n    def __init__(\n        self,\n        *mobjects: Mobject,\n        shift: np.ndarray | None = None,\n        target_position: np.ndarray | Mobject | None = None,\n        scale: float = 1,\n        **kwargs: Any,\n    ) -> None:\n        if not mobjects:\n            raise ValueError(\"At least one mobject must be passed.\")\n        mobject = mobjects[0] if len(mobjects) == 1 else Group(*mobjects)\n\n        self.point_target = False\n        if shift is None:\n            if target_position is not None:\n                if isinstance(target_position, (Mobject, OpenGLMobject)):\n                    target_position = target_position.get_center()\n                shift = target_position - mobject.get_center()\n                self.point_target = True\n            else:\n                shift = ORIGIN\n        self.shift_vector = shift\n        self.scale_factor = scale\n        super().__init__(mobject, **kwargs)\n\n    def _create_faded_mobject(self, fadeIn: bool) -> Mobject:\n        \"\"\"Create a faded, shifted and scaled copy of the mobject.\n\n        Parameters\n        ----------\n        fadeIn\n            Whether the faded mobject is used to fade in.\n\n        Returns\n        -------\n        Mobject\n            The faded, shifted and scaled copy of the mobject.\n        \"\"\"\n        faded_mobject: Mobject = self.mobject.copy()  # type: ignore[assignment]\n        faded_mobject.fade(1)\n        direction_modifier = -1 if fadeIn and not self.point_target else 1\n        faded_mobject.shift(self.shift_vector * direction_modifier)\n        faded_mobject.scale(self.scale_factor)\n        return faded_mobject\n\n\nclass FadeIn(_Fade):\n    r\"\"\"Fade in :class:`~.Mobject` s.\n\n    Parameters\n    ----------\n    mobjects\n        The mobjects to be faded in.\n    shift\n        The vector by which the mobject shifts while being faded in.\n    target_position\n        The position from which the mobject starts while being faded in. In case\n        another mobject is given as target position, its center is used.\n    scale\n        The factor by which the mobject is scaled initially before being rescaling to\n        its original size while being faded in.\n\n    Examples\n    --------\n\n    .. manim :: FadeInExample\n\n        class FadeInExample(Scene):\n            def construct(self):\n                dot = Dot(UP * 2 + LEFT)\n                self.add(dot)\n                tex = Tex(\n                    \"FadeIn with \", \"shift \", r\" or target\\_position\", \" and scale\"\n                ).scale(1)\n                animations = [\n                    FadeIn(tex[0]),\n                    FadeIn(tex[1], shift=DOWN),\n                    FadeIn(tex[2], target_position=dot),\n                    FadeIn(tex[3], scale=1.5),\n                ]\n                self.play(AnimationGroup(*animations, lag_ratio=0.5))\n\n    \"\"\"\n\n    def __init__(self, *mobjects: Mobject, **kwargs: Any) -> None:\n        super().__init__(*mobjects, introducer=True, **kwargs)\n\n    def create_target(self) -> Mobject:\n        return self.mobject  # type: ignore[return-value]\n\n    def create_starting_mobject(self) -> Mobject:\n        return self._create_faded_mobject(fadeIn=True)\n\n\nclass FadeOut(_Fade):\n    r\"\"\"Fade out :class:`~.Mobject` s.\n\n    Parameters\n    ----------\n    mobjects\n        The mobjects to be faded out.\n    shift\n        The vector by which the mobject shifts while being faded out.\n    target_position\n        The position to which the mobject moves while being faded out. In case another\n        mobject is given as target position, its center is used.\n    scale\n        The factor by which the mobject is scaled while being faded out.\n\n    Examples\n    --------\n\n    .. manim :: FadeInExample\n\n        class FadeInExample(Scene):\n            def construct(self):\n                dot = Dot(UP * 2 + LEFT)\n                self.add(dot)\n                tex = Tex(\n                    \"FadeOut with \", \"shift \", r\" or target\\_position\", \" and scale\"\n                ).scale(1)\n                animations = [\n                    FadeOut(tex[0]),\n                    FadeOut(tex[1], shift=DOWN),\n                    FadeOut(tex[2], target_position=dot),\n                    FadeOut(tex[3], scale=0.5),\n                ]\n                self.play(AnimationGroup(*animations, lag_ratio=0.5))\n\n\n    \"\"\"\n\n    def __init__(self, *mobjects: Mobject, **kwargs: Any) -> None:\n        super().__init__(*mobjects, remover=True, **kwargs)\n\n    def create_target(self) -> Mobject:\n        return self._create_faded_mobject(fadeIn=False)\n\n    def clean_up_from_scene(self, scene: Scene) -> None:\n        super().clean_up_from_scene(scene)\n        self.interpolate(0)\n"
  },
  {
    "path": "manim/animation/growing.py",
    "content": "\"\"\"Animations that introduce mobjects to scene by growing them from points.\n\n.. manim:: Growing\n\n    class Growing(Scene):\n        def construct(self):\n            square = Square()\n            circle = Circle()\n            triangle = Triangle()\n            arrow = Arrow(LEFT, RIGHT)\n            star = Star()\n\n            VGroup(square, circle, triangle).set_x(0).arrange(buff=1.5).set_y(2)\n            VGroup(arrow, star).move_to(DOWN).set_x(0).arrange(buff=1.5).set_y(-2)\n\n            self.play(GrowFromPoint(square, ORIGIN))\n            self.play(GrowFromCenter(circle))\n            self.play(GrowFromEdge(triangle, DOWN))\n            self.play(GrowArrow(arrow))\n            self.play(SpinInFromNothing(star))\n\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"GrowFromPoint\",\n    \"GrowFromCenter\",\n    \"GrowFromEdge\",\n    \"GrowArrow\",\n    \"SpinInFromNothing\",\n]\n\nfrom typing import TYPE_CHECKING, Any\n\nfrom ..animation.transform import Transform\nfrom ..constants import PI\nfrom ..utils.paths import spiral_path\n\nif TYPE_CHECKING:\n    from manim.mobject.geometry.line import Arrow\n    from manim.mobject.opengl.opengl_mobject import OpenGLMobject\n    from manim.typing import Point3DLike, Vector3DLike\n    from manim.utils.color import ParsableManimColor\n\n    from ..mobject.mobject import Mobject\n\n\nclass GrowFromPoint(Transform):\n    \"\"\"Introduce an :class:`~.Mobject` by growing it from a point.\n\n    Parameters\n    ----------\n    mobject\n        The mobjects to be introduced.\n    point\n        The point from which the mobject grows.\n    point_color\n        Initial color of the mobject before growing to its full size. Leave empty to match mobject's color.\n\n    Examples\n    --------\n\n    .. manim :: GrowFromPointExample\n\n        class GrowFromPointExample(Scene):\n            def construct(self):\n                dot = Dot(3 * UR, color=GREEN)\n                squares = [Square() for _ in range(4)]\n                VGroup(*squares).set_x(0).arrange(buff=1)\n                self.add(dot)\n                self.play(GrowFromPoint(squares[0], ORIGIN))\n                self.play(GrowFromPoint(squares[1], [-2, 2, 0]))\n                self.play(GrowFromPoint(squares[2], [3, -2, 0], RED))\n                self.play(GrowFromPoint(squares[3], dot, dot.get_color()))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        point: Point3DLike,\n        point_color: ParsableManimColor | None = None,\n        **kwargs: Any,\n    ):\n        self.point = point\n        self.point_color = point_color\n        super().__init__(mobject, introducer=True, **kwargs)\n\n    def create_target(self) -> Mobject | OpenGLMobject:\n        return self.mobject\n\n    def create_starting_mobject(self) -> Mobject | OpenGLMobject:\n        start = super().create_starting_mobject()\n        start.scale(0)\n        start.move_to(self.point)\n        if self.point_color:\n            start.set_color(self.point_color)\n        return start\n\n\nclass GrowFromCenter(GrowFromPoint):\n    \"\"\"Introduce an :class:`~.Mobject` by growing it from its center.\n\n    Parameters\n    ----------\n    mobject\n        The mobjects to be introduced.\n    point_color\n        Initial color of the mobject before growing to its full size. Leave empty to match mobject's color.\n\n    Examples\n    --------\n\n    .. manim :: GrowFromCenterExample\n\n        class GrowFromCenterExample(Scene):\n            def construct(self):\n                squares = [Square() for _ in range(2)]\n                VGroup(*squares).set_x(0).arrange(buff=2)\n                self.play(GrowFromCenter(squares[0]))\n                self.play(GrowFromCenter(squares[1], point_color=RED))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        point_color: ParsableManimColor | None = None,\n        **kwargs: Any,\n    ):\n        point = mobject.get_center()\n        super().__init__(mobject, point, point_color=point_color, **kwargs)\n\n\nclass GrowFromEdge(GrowFromPoint):\n    \"\"\"Introduce an :class:`~.Mobject` by growing it from one of its bounding box edges.\n\n    Parameters\n    ----------\n    mobject\n        The mobjects to be introduced.\n    edge\n        The direction to seek bounding box edge of mobject.\n    point_color\n        Initial color of the mobject before growing to its full size. Leave empty to match mobject's color.\n\n    Examples\n    --------\n\n    .. manim :: GrowFromEdgeExample\n\n        class GrowFromEdgeExample(Scene):\n            def construct(self):\n                squares = [Square() for _ in range(4)]\n                VGroup(*squares).set_x(0).arrange(buff=1)\n                self.play(GrowFromEdge(squares[0], DOWN))\n                self.play(GrowFromEdge(squares[1], RIGHT))\n                self.play(GrowFromEdge(squares[2], UR))\n                self.play(GrowFromEdge(squares[3], UP, point_color=RED))\n\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        edge: Vector3DLike,\n        point_color: ParsableManimColor | None = None,\n        **kwargs: Any,\n    ):\n        point = mobject.get_critical_point(edge)\n        super().__init__(mobject, point, point_color=point_color, **kwargs)\n\n\nclass GrowArrow(GrowFromPoint):\n    \"\"\"Introduce an :class:`~.Arrow` by growing it from its start toward its tip.\n\n    Parameters\n    ----------\n    arrow\n        The arrow to be introduced.\n    point_color\n        Initial color of the arrow before growing to its full size. Leave empty to match arrow's color.\n\n    Examples\n    --------\n\n    .. manim :: GrowArrowExample\n\n        class GrowArrowExample(Scene):\n            def construct(self):\n                arrows = [Arrow(2 * LEFT, 2 * RIGHT), Arrow(2 * DR, 2 * UL)]\n                VGroup(*arrows).set_x(0).arrange(buff=2)\n                self.play(GrowArrow(arrows[0]))\n                self.play(GrowArrow(arrows[1], point_color=RED))\n\n    \"\"\"\n\n    def __init__(\n        self, arrow: Arrow, point_color: ParsableManimColor | None = None, **kwargs: Any\n    ):\n        point = arrow.get_start()\n        super().__init__(arrow, point, point_color=point_color, **kwargs)\n\n    def create_starting_mobject(self) -> Mobject | OpenGLMobject:\n        start_arrow = self.mobject.copy()\n        start_arrow.scale(0, scale_tips=True, about_point=self.point)\n        if self.point_color:\n            start_arrow.set_color(self.point_color)\n        return start_arrow\n\n\nclass SpinInFromNothing(GrowFromCenter):\n    \"\"\"Introduce an :class:`~.Mobject` spinning and growing it from its center.\n\n    Parameters\n    ----------\n    mobject\n        The mobjects to be introduced.\n    angle\n        The amount of spinning before mobject reaches its full size. E.g. 2*PI means\n        that the object will do one full spin before being fully introduced.\n    point_color\n        Initial color of the mobject before growing to its full size. Leave empty to match mobject's color.\n\n    Examples\n    --------\n\n    .. manim :: SpinInFromNothingExample\n\n        class SpinInFromNothingExample(Scene):\n            def construct(self):\n                squares = [Square() for _ in range(3)]\n                VGroup(*squares).set_x(0).arrange(buff=2)\n                self.play(SpinInFromNothing(squares[0]))\n                self.play(SpinInFromNothing(squares[1], angle=2 * PI))\n                self.play(SpinInFromNothing(squares[2], point_color=RED))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        angle: float = PI / 2,\n        point_color: ParsableManimColor | None = None,\n        **kwargs: Any,\n    ):\n        self.angle = angle\n        super().__init__(\n            mobject, path_func=spiral_path(angle), point_color=point_color, **kwargs\n        )\n"
  },
  {
    "path": "manim/animation/indication.py",
    "content": "\"\"\"Animations drawing attention to particular mobjects.\n\nExamples\n--------\n\n.. manim:: Indications\n\n    class Indications(Scene):\n        def construct(self):\n            indications = [ApplyWave,Circumscribe,Flash,FocusOn,Indicate,ShowPassingFlash,Wiggle]\n            names = [Tex(i.__name__).scale(3) for i in indications]\n\n            self.add(names[0])\n            for i in range(len(names)):\n                if indications[i] is Flash:\n                    self.play(Flash(UP))\n                elif indications[i] is ShowPassingFlash:\n                    self.play(ShowPassingFlash(Underline(names[i])))\n                else:\n                    self.play(indications[i](names[i]))\n                self.play(AnimationGroup(\n                    FadeOut(names[i], shift=UP*1.5),\n                    FadeIn(names[(i+1)%len(names)], shift=UP*1.5),\n                ))\n\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"FocusOn\",\n    \"Indicate\",\n    \"Flash\",\n    \"ShowPassingFlash\",\n    \"ShowPassingFlashWithThinningStrokeWidth\",\n    \"ApplyWave\",\n    \"Circumscribe\",\n    \"Wiggle\",\n    \"Blink\",\n]\n\nfrom collections.abc import Iterable\nfrom typing import Any, Self\n\nimport numpy as np\n\nfrom manim.mobject.geometry.arc import Circle, Dot\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.geometry.polygram import Rectangle\nfrom manim.mobject.geometry.shape_matchers import SurroundingRectangle\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.scene.scene import Scene\n\nfrom .. import config\nfrom ..animation.animation import Animation\nfrom ..animation.composition import AnimationGroup, Succession\nfrom ..animation.creation import Create, ShowPartial, Uncreate\nfrom ..animation.fading import FadeIn, FadeOut\nfrom ..animation.movement import Homotopy\nfrom ..animation.transform import Transform\nfrom ..animation.updaters.update import UpdateFromFunc\nfrom ..constants import *\nfrom ..mobject.mobject import Mobject\nfrom ..mobject.types.vectorized_mobject import VGroup, VMobject\nfrom ..typing import Point3D, Point3DLike, Vector3DLike\nfrom ..utils.bezier import interpolate, inverse_interpolate\nfrom ..utils.color import GREY, PURE_YELLOW, ParsableManimColor\nfrom ..utils.rate_functions import RateFunction, smooth, there_and_back, wiggle\nfrom ..utils.space_ops import normalize\n\n\nclass FocusOn(Transform):\n    \"\"\"Shrink a spotlight to a position.\n\n    Parameters\n    ----------\n    focus_point\n        The point at which to shrink the spotlight. If it is a :class:`.~Mobject` its center will be used.\n    opacity\n        The opacity of the spotlight.\n    color\n        The color of the spotlight.\n    run_time\n        The duration of the animation.\n\n    Examples\n    --------\n    .. manim:: UsingFocusOn\n\n        class UsingFocusOn(Scene):\n            def construct(self):\n                dot = Dot(color=PURE_YELLOW).shift(DOWN)\n                self.add(Tex(\"Focusing on the dot below:\"), dot)\n                self.play(FocusOn(dot))\n                self.wait()\n    \"\"\"\n\n    def __init__(\n        self,\n        focus_point: Point3DLike | Mobject,\n        opacity: float = 0.2,\n        color: ParsableManimColor = GREY,\n        run_time: float = 2,\n        **kwargs: Any,\n    ):\n        self.focus_point = focus_point\n        self.color = color\n        self.opacity = opacity\n        remover = True\n        starting_dot = Dot(\n            radius=config[\"frame_x_radius\"] + config[\"frame_y_radius\"],\n            stroke_width=0,\n            fill_color=self.color,\n            fill_opacity=0,\n        )\n        super().__init__(starting_dot, run_time=run_time, remover=remover, **kwargs)\n\n    def create_target(self) -> Dot:\n        little_dot = Dot(radius=0)\n        little_dot.set_fill(self.color, opacity=self.opacity)\n        little_dot.add_updater(lambda d: d.move_to(self.focus_point))\n        return little_dot\n\n\nclass Indicate(Transform):\n    \"\"\"Indicate a Mobject by temporarily resizing and recoloring it.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to indicate.\n    scale_factor\n        The factor by which the mobject will be temporally scaled\n    color\n        The color the mobject temporally takes.\n    rate_func\n        The function defining the animation progress at every point in time.\n    kwargs\n        Additional arguments to be passed to the :class:`~.Succession` constructor\n\n    Examples\n    --------\n    .. manim:: UsingIndicate\n\n        class UsingIndicate(Scene):\n            def construct(self):\n                tex = Tex(\"Indicate\").scale(3)\n                self.play(Indicate(tex))\n                self.wait()\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        scale_factor: float = 1.2,\n        color: ParsableManimColor = PURE_YELLOW,\n        rate_func: RateFunction = there_and_back,\n        **kwargs: Any,\n    ):\n        self.color = color\n        self.scale_factor = scale_factor\n        super().__init__(mobject, rate_func=rate_func, **kwargs)\n\n    def create_target(self) -> Mobject | OpenGLMobject:\n        target = self.mobject.copy()\n        target.scale(self.scale_factor)\n        target.set_color(self.color)\n        return target\n\n\nclass Flash(AnimationGroup):\n    \"\"\"Send out lines in all directions.\n\n    Parameters\n    ----------\n    point\n        The center of the flash lines. If it is a :class:`.~Mobject` its center will be used.\n    line_length\n        The length of the flash lines.\n    num_lines\n        The number of flash lines.\n    flash_radius\n        The distance from `point` at which the flash lines start.\n    line_stroke_width\n        The stroke width of the flash lines.\n    color\n        The color of the flash lines.\n    time_width\n        The time width used for the flash lines. See :class:`.~ShowPassingFlash` for more details.\n    run_time\n        The duration of the animation.\n    kwargs\n        Additional arguments to be passed to the :class:`~.Succession` constructor\n\n    Examples\n    --------\n    .. manim:: UsingFlash\n\n        class UsingFlash(Scene):\n            def construct(self):\n                dot = Dot(color=PURE_YELLOW).shift(DOWN)\n                self.add(Tex(\"Flash the dot below:\"), dot)\n                self.play(Flash(dot))\n                self.wait()\n\n    .. manim:: FlashOnCircle\n\n        class FlashOnCircle(Scene):\n            def construct(self):\n                radius = 2\n                circle = Circle(radius)\n                self.add(circle)\n                self.play(Flash(\n                    circle, line_length=1,\n                    num_lines=30, color=RED,\n                    flash_radius=radius+SMALL_BUFF,\n                    time_width=0.3, run_time=2,\n                    rate_func = rush_from\n                ))\n    \"\"\"\n\n    def __init__(\n        self,\n        point: Point3DLike | Mobject,\n        line_length: float = 0.2,\n        num_lines: int = 12,\n        flash_radius: float = 0.1,\n        line_stroke_width: int = 3,\n        color: ParsableManimColor = PURE_YELLOW,\n        time_width: float = 1,\n        run_time: float = 1.0,\n        **kwargs: Any,\n    ):\n        if isinstance(point, Mobject):\n            self.point: Point3D = point.get_center()\n        else:\n            self.point = np.asarray(point)\n        self.color = color\n        self.line_length = line_length\n        self.num_lines = num_lines\n        self.flash_radius = flash_radius\n        self.line_stroke_width = line_stroke_width\n        self.run_time = run_time\n        self.time_width = time_width\n        self.animation_config = kwargs\n\n        self.lines = self.create_lines()\n        animations = self.create_line_anims()\n        super().__init__(*animations, group=self.lines)\n\n    def create_lines(self) -> VGroup:\n        lines = VGroup()\n        for angle in np.arange(0, TAU, TAU / self.num_lines):\n            line = Line(self.point, self.point + self.line_length * RIGHT)\n            line.shift((self.flash_radius) * RIGHT)\n            line.rotate(angle, about_point=self.point)\n            lines.add(line)\n        lines.set_color(self.color)\n        lines.set_stroke(width=self.line_stroke_width)\n        return lines\n\n    def create_line_anims(self) -> Iterable[ShowPassingFlash]:\n        return [\n            ShowPassingFlash(\n                line,\n                time_width=self.time_width,\n                run_time=self.run_time,\n                **self.animation_config,\n            )\n            for line in self.lines\n        ]\n\n\nclass ShowPassingFlash(ShowPartial):\n    r\"\"\"Show only a sliver of the VMobject each frame.\n\n    Parameters\n    ----------\n    mobject\n        The mobject whose stroke is animated.\n    time_width\n        The length of the sliver relative to the length of the stroke.\n\n    Examples\n    --------\n    .. manim:: TimeWidthValues\n\n        class TimeWidthValues(Scene):\n            def construct(self):\n                p = RegularPolygon(5, color=DARK_GRAY, stroke_width=6).scale(3)\n                lbl = VMobject()\n                self.add(p, lbl)\n                p = p.copy().set_color(BLUE)\n                for time_width in [0.2, 0.5, 1, 2]:\n                    lbl.become(Tex(r\"\\texttt{time\\_width={{%.1f}}}\"%time_width))\n                    self.play(ShowPassingFlash(\n                        p.copy().set_color(BLUE),\n                        run_time=2,\n                        time_width=time_width\n                    ))\n\n    See Also\n    --------\n    :class:`~.Create`\n\n    \"\"\"\n\n    def __init__(\n        self, mobject: VMobject, time_width: float = 0.1, **kwargs: Any\n    ) -> None:\n        self.time_width = time_width\n        super().__init__(mobject, remover=True, introducer=True, **kwargs)\n\n    def _get_bounds(self, alpha: float) -> tuple[float, float]:\n        tw = self.time_width\n        upper = interpolate(0, 1 + tw, alpha)\n        lower = upper - tw\n        upper = min(upper, 1)\n        lower = max(lower, 0)\n        return (lower, upper)\n\n    def clean_up_from_scene(self, scene: Scene) -> None:\n        super().clean_up_from_scene(scene)\n        for submob, start in self.get_all_families_zipped():\n            submob.pointwise_become_partial(start, 0, 1)\n\n\nclass ShowPassingFlashWithThinningStrokeWidth(AnimationGroup):\n    def __init__(\n        self,\n        vmobject: VMobject,\n        n_segments: int = 10,\n        time_width: float = 0.1,\n        remover: bool = True,\n        **kwargs: Any,\n    ):\n        self.n_segments = n_segments\n        self.time_width = time_width\n        self.remover = remover\n        max_stroke_width = vmobject.get_stroke_width()\n        max_time_width = kwargs.pop(\"time_width\", self.time_width)\n        super().__init__(\n            *(\n                ShowPassingFlash(\n                    vmobject.copy().set_stroke(width=stroke_width),\n                    time_width=time_width,\n                    **kwargs,\n                )\n                for stroke_width, time_width in zip(\n                    np.linspace(0, max_stroke_width, self.n_segments),\n                    np.linspace(max_time_width, 0, self.n_segments),\n                    strict=True,\n                )\n            ),\n        )\n\n\nclass ApplyWave(Homotopy):\n    \"\"\"Send a wave through the Mobject distorting it temporarily.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to be distorted.\n    direction\n        The direction in which the wave nudges points of the shape\n    amplitude\n        The distance points of the shape get shifted\n    wave_func\n        The function defining the shape of one wave flank.\n    time_width\n        The length of the wave relative to the width of the mobject.\n    ripples\n        The number of ripples of the wave\n    run_time\n        The duration of the animation.\n\n    Examples\n    --------\n\n    .. manim:: ApplyingWaves\n\n        class ApplyingWaves(Scene):\n            def construct(self):\n                tex = Tex(\"WaveWaveWaveWaveWave\").scale(2)\n                self.play(ApplyWave(tex))\n                self.play(ApplyWave(\n                    tex,\n                    direction=RIGHT,\n                    time_width=0.5,\n                    amplitude=0.3\n                ))\n                self.play(ApplyWave(\n                    tex,\n                    rate_func=linear,\n                    ripples=4\n                ))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        direction: Vector3DLike = UP,\n        amplitude: float = 0.2,\n        wave_func: RateFunction = smooth,\n        time_width: float = 1,\n        ripples: int = 1,\n        run_time: float = 2,\n        **kwargs: Any,\n    ):\n        x_min = mobject.get_left()[0]\n        x_max = mobject.get_right()[0]\n        vect = amplitude * normalize(direction)\n\n        def wave(t: float) -> float:\n            # Creates a wave with n ripples from a simple rate_func\n            # This wave is build up as follows:\n            # The time is split into 2*ripples phases. In every phase the amplitude\n            # either rises to one or goes down to zero. Consecutive ripples will have\n            # their amplitudes in opposing directions (first ripple from 0 to 1 to 0,\n            # second from 0 to -1 to 0 and so on). This is how two ripples would be\n            # divided into phases:\n\n            #         ####|####        |            |\n            #       ##    |    ##      |            |\n            #     ##      |      ##    |            |\n            # ####        |        ####|####        |        ####\n            #             |            |    ##      |      ##\n            #             |            |      ##    |    ##\n            #             |            |        ####|####\n\n            # However, this looks weird in the middle between two ripples. Therefore the\n            # middle phases do actually use only one appropriately scaled version of the\n            # rate like this:\n\n            # 1 / 4 Time  | 2 / 4 Time            | 1 / 4 Time\n            #         ####|######                 |\n            #       ##    |      ###              |\n            #     ##      |         ##            |\n            # ####        |           #           |        ####\n            #             |            ##         |      ##\n            #             |              ###      |    ##\n            #             |                 ######|####\n\n            # Mirrored looks better in the way the wave is used.\n            t = 1 - t\n\n            # Clamp input\n            if t >= 1 or t <= 0:\n                return 0\n\n            phases = ripples * 2\n            phase = int(t * phases)\n            if phase == 0:\n                # First rising ripple\n                return wave_func(t * phases)\n            elif phase == phases - 1:\n                # last ripple. Rising or falling depending on the number of ripples\n                # The (ripples % 2)-term is used to make this distinction.\n                t -= phase / phases  # Time relative to the phase\n                return (1 - wave_func(t * phases)) * (2 * (ripples % 2) - 1)\n            else:\n                # Longer phases:\n                phase = int((phase - 1) / 2)\n                t -= (2 * phase + 1) / phases\n\n                # Similar to last ripple:\n                return (1 - 2 * wave_func(t * ripples)) * (1 - 2 * ((phase) % 2))\n\n        def homotopy(\n            x: float,\n            y: float,\n            z: float,\n            t: float,\n        ) -> tuple[float, float, float]:\n            upper = interpolate(0, 1 + time_width, t)\n            lower = upper - time_width\n            relative_x = inverse_interpolate(x_min, x_max, x)\n            wave_phase = inverse_interpolate(lower, upper, relative_x)\n            nudge = wave(wave_phase) * vect\n            return_value: tuple[float, float, float] = np.array([x, y, z]) + nudge\n            return return_value\n\n        super().__init__(homotopy, mobject, run_time=run_time, **kwargs)\n\n\nclass Wiggle(Animation):\n    \"\"\"Wiggle a Mobject.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to wiggle.\n    scale_value\n        The factor by which the mobject will be temporarily scaled.\n    rotation_angle\n        The wiggle angle.\n    n_wiggles\n        The number of wiggles.\n    scale_about_point\n        The point about which the mobject gets scaled.\n    rotate_about_point\n        The point around which the mobject gets rotated.\n    run_time\n        The duration of the animation\n\n    Examples\n    --------\n\n    .. manim:: ApplyingWaves\n\n        class ApplyingWaves(Scene):\n            def construct(self):\n                tex = Tex(\"Wiggle\").scale(3)\n                self.play(Wiggle(tex))\n                self.wait()\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        scale_value: float = 1.1,\n        rotation_angle: float = 0.01 * TAU,\n        n_wiggles: int = 6,\n        scale_about_point: Point3DLike | None = None,\n        rotate_about_point: Point3DLike | None = None,\n        run_time: float = 2,\n        **kwargs: Any,\n    ):\n        self.scale_value = scale_value\n        self.rotation_angle = rotation_angle\n        self.n_wiggles = n_wiggles\n        self.scale_about_point = scale_about_point\n        if scale_about_point is not None:\n            self.scale_about_point = np.array(scale_about_point)\n        self.rotate_about_point = rotate_about_point\n        if rotate_about_point is not None:\n            self.rotate_about_point = np.array(rotate_about_point)\n        super().__init__(mobject, run_time=run_time, **kwargs)\n\n    def get_scale_about_point(self) -> Point3D:\n        if self.scale_about_point is None:\n            return self.mobject.get_center()\n        return self.scale_about_point\n\n    def get_rotate_about_point(self) -> Point3D:\n        if self.rotate_about_point is None:\n            return self.mobject.get_center()\n        return self.rotate_about_point\n\n    def interpolate_submobject(\n        self,\n        submobject: Mobject,\n        starting_submobject: Mobject,\n        alpha: float,\n    ) -> Self:\n        submobject.points[:, :] = starting_submobject.points\n        submobject.scale(\n            interpolate(1, self.scale_value, there_and_back(alpha)),\n            about_point=self.get_scale_about_point(),\n        )\n        submobject.rotate(\n            wiggle(alpha, self.n_wiggles) * self.rotation_angle,\n            about_point=self.get_rotate_about_point(),\n        )\n        return self\n\n\nclass Circumscribe(Succession):\n    r\"\"\"Draw a temporary line surrounding the mobject.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to be circumscribed.\n    shape\n        The shape with which to surround the given mobject. Should be either\n        :class:`~.Rectangle` or :class:`~.Circle`\n    fade_in\n        Whether to make the surrounding shape to fade in. It will be drawn otherwise.\n    fade_out\n        Whether to make the surrounding shape to fade out. It will be undrawn otherwise.\n    time_width\n        The time_width of the drawing and undrawing. Gets ignored if either `fade_in` or `fade_out` is `True`.\n    buff\n        The distance between the surrounding shape and the given mobject.\n    color\n        The color of the surrounding shape.\n    run_time\n        The duration of the entire animation.\n    kwargs\n        Additional arguments to be passed to the :class:`~.Succession` constructor\n\n    Examples\n    --------\n\n    .. manim:: UsingCircumscribe\n\n        class UsingCircumscribe(Scene):\n            def construct(self):\n                lbl = Tex(r\"Circum-\\\\scribe\").scale(2)\n                self.add(lbl)\n                self.play(Circumscribe(lbl))\n                self.play(Circumscribe(lbl, Circle))\n                self.play(Circumscribe(lbl, fade_out=True))\n                self.play(Circumscribe(lbl, time_width=2))\n                self.play(Circumscribe(lbl, Circle, True))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        shape: type[Rectangle] | type[Circle] = Rectangle,\n        fade_in: bool = False,\n        fade_out: bool = False,\n        time_width: float = 0.3,\n        buff: float = SMALL_BUFF,\n        color: ParsableManimColor = PURE_YELLOW,\n        run_time: float = 1,\n        stroke_width: float = DEFAULT_STROKE_WIDTH,\n        **kwargs: Any,\n    ):\n        if shape is Rectangle:\n            frame: SurroundingRectangle | Circle = SurroundingRectangle(\n                mobject,\n                color=color,\n                buff=buff,\n                stroke_width=stroke_width,\n            )\n        elif shape is Circle:\n            frame = Circle(color=color, stroke_width=stroke_width).surround(\n                mobject,\n                buffer_factor=1,\n            )\n            radius = frame.width / 2\n            frame.scale((radius + buff) / radius)\n        else:\n            raise ValueError(\"shape should be either Rectangle or Circle.\")\n\n        if fade_in and fade_out:\n            super().__init__(\n                FadeIn(frame, run_time=run_time / 2),\n                FadeOut(frame, run_time=run_time / 2),\n                **kwargs,\n            )\n        elif fade_in:\n            frame.reverse_direction()\n            super().__init__(\n                FadeIn(frame, run_time=run_time / 2),\n                Uncreate(frame, run_time=run_time / 2),\n                **kwargs,\n            )\n        elif fade_out:\n            super().__init__(\n                Create(frame, run_time=run_time / 2),\n                FadeOut(frame, run_time=run_time / 2),\n                **kwargs,\n            )\n        else:\n            super().__init__(\n                ShowPassingFlash(frame, time_width, run_time=run_time), **kwargs\n            )\n\n\nclass Blink(Succession):\n    \"\"\"Blink the mobject.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to be blinked.\n    time_on\n        The duration that the mobject is shown for one blink.\n    time_off\n        The duration that the mobject is hidden for one blink.\n    blinks\n        The number of blinks\n    hide_at_end\n        Whether to hide the mobject at the end of the animation.\n    kwargs\n        Additional arguments to be passed to the :class:`~.Succession` constructor.\n\n    Examples\n    --------\n\n    .. manim:: BlinkingExample\n\n        class BlinkingExample(Scene):\n            def construct(self):\n                text = Text(\"Blinking\").scale(1.5)\n                self.add(text)\n                self.play(Blink(text, blinks=3))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        time_on: float = 0.5,\n        time_off: float = 0.5,\n        blinks: int = 1,\n        hide_at_end: bool = False,\n        **kwargs: Any,\n    ):\n        animations = [\n            UpdateFromFunc(\n                mobject,\n                update_function=lambda mob: mob.set_opacity(1.0),\n                run_time=time_on,\n            ),\n            UpdateFromFunc(\n                mobject,\n                update_function=lambda mob: mob.set_opacity(0.0),\n                run_time=time_off,\n            ),\n        ] * blinks\n\n        if not hide_at_end:\n            animations.append(\n                UpdateFromFunc(\n                    mobject,\n                    update_function=lambda mob: mob.set_opacity(1.0),\n                    run_time=time_on,\n                ),\n            )\n\n        super().__init__(*animations, **kwargs)\n"
  },
  {
    "path": "manim/animation/movement.py",
    "content": "\"\"\"Animations related to movement.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"Homotopy\",\n    \"SmoothedVectorizedHomotopy\",\n    \"ComplexHomotopy\",\n    \"PhaseFlow\",\n    \"MoveAlongPath\",\n]\n\nfrom collections.abc import Callable\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom ..animation.animation import Animation\nfrom ..utils.rate_functions import linear\n\nif TYPE_CHECKING:\n    from typing import Self\n\n    from manim.mobject.types.vectorized_mobject import VMobject\n    from manim.typing import MappingFunction, Point3D\n    from manim.utils.rate_functions import RateFunction\n\n    from ..mobject.mobject import Mobject\n\n\nclass Homotopy(Animation):\n    \"\"\"A Homotopy.\n\n    This is an animation transforming the points of a mobject according\n    to the specified transformation function. With the parameter :math:`t`\n    moving from 0 to 1 throughout the animation and :math:`(x, y, z)`\n    describing the coordinates of the point of a mobject,\n    the function passed to the ``homotopy`` keyword argument should\n    transform the tuple :math:`(x, y, z, t)` to :math:`(x', y', z')`,\n    the coordinates the original point is transformed to at time :math:`t`.\n\n    Parameters\n    ----------\n    homotopy\n        A function mapping :math:`(x, y, z, t)` to :math:`(x', y', z')`.\n    mobject\n        The mobject transformed under the given homotopy.\n    run_time\n        The run time of the animation.\n    apply_function_kwargs\n        Keyword arguments propagated to :meth:`.Mobject.apply_function`.\n    kwargs\n        Further keyword arguments passed to the parent class.\n\n    Examples\n    --------\n\n    .. manim:: HomotopyExample\n\n        class HomotopyExample(Scene):\n            def construct(self):\n                square = Square()\n\n                def homotopy(x, y, z, t):\n                    if t <= 0.25:\n                        progress = t / 0.25\n                        return (x, y + progress * 0.2 * np.sin(x), z)\n                    else:\n                        wave_progress = (t - 0.25) / 0.75\n                        return (x, y + 0.2 * np.sin(x + 10 * wave_progress), z)\n\n                self.play(Homotopy(homotopy, square, rate_func= linear, run_time=2))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        homotopy: Callable[[float, float, float, float], tuple[float, float, float]],\n        mobject: Mobject,\n        run_time: float = 3,\n        apply_function_kwargs: dict[str, Any] | None = None,\n        **kwargs: Any,\n    ):\n        self.homotopy = homotopy\n        self.apply_function_kwargs = (\n            apply_function_kwargs if apply_function_kwargs is not None else {}\n        )\n        super().__init__(mobject, run_time=run_time, **kwargs)\n\n    def function_at_time_t(self, t: float) -> MappingFunction:\n        def mapping_function(p: Point3D) -> Point3D:\n            x, y, z = p\n            return np.array(self.homotopy(x, y, z, t))\n\n        return mapping_function\n\n    def interpolate_submobject(\n        self,\n        submobject: Mobject,\n        starting_submobject: Mobject,\n        alpha: float,\n    ) -> Self:\n        submobject.points = starting_submobject.points\n        submobject.apply_function(\n            self.function_at_time_t(alpha),\n            **self.apply_function_kwargs,\n        )\n        return self\n\n\nclass SmoothedVectorizedHomotopy(Homotopy):\n    def interpolate_submobject(\n        self,\n        submobject: Mobject,\n        starting_submobject: Mobject,\n        alpha: float,\n    ) -> Self:\n        assert isinstance(submobject, VMobject)\n        super().interpolate_submobject(submobject, starting_submobject, alpha)\n        submobject.make_smooth()\n        return self\n\n\nclass ComplexHomotopy(Homotopy):\n    def __init__(\n        self,\n        complex_homotopy: Callable[[complex, float], float],\n        mobject: Mobject,\n        **kwargs: Any,\n    ):\n        \"\"\"Complex Homotopy a function Cx[0, 1] to C\"\"\"\n\n        def homotopy(\n            x: float,\n            y: float,\n            z: float,\n            t: float,\n        ) -> tuple[float, float, float]:\n            c = complex_homotopy(complex(x, y), t)\n            return (c.real, c.imag, z)\n\n        super().__init__(homotopy, mobject, **kwargs)\n\n\nclass PhaseFlow(Animation):\n    def __init__(\n        self,\n        function: Callable[[np.ndarray], np.ndarray],\n        mobject: Mobject,\n        virtual_time: float = 1,\n        suspend_mobject_updating: bool = False,\n        rate_func: RateFunction = linear,\n        **kwargs: Any,\n    ):\n        self.virtual_time = virtual_time\n        self.function = function\n        super().__init__(\n            mobject,\n            suspend_mobject_updating=suspend_mobject_updating,\n            rate_func=rate_func,\n            **kwargs,\n        )\n\n    def interpolate_mobject(self, alpha: float) -> None:\n        if hasattr(self, \"last_alpha\"):\n            dt = self.virtual_time * (\n                self.rate_func(alpha) - self.rate_func(self.last_alpha)\n            )\n            self.mobject.apply_function(lambda p: p + dt * self.function(p))\n        self.last_alpha: float = alpha\n\n\nclass MoveAlongPath(Animation):\n    \"\"\"Make one mobject move along the path of another mobject.\n\n    .. manim:: MoveAlongPathExample\n\n        class MoveAlongPathExample(Scene):\n            def construct(self):\n                d1 = Dot().set_color(ORANGE)\n                l1 = Line(LEFT, RIGHT)\n                l2 = VMobject()\n                self.add(d1, l1, l2)\n                l2.add_updater(lambda x: x.become(Line(LEFT, d1.get_center()).set_color(ORANGE)))\n                self.play(MoveAlongPath(d1, l1), rate_func=linear)\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        path: VMobject,\n        suspend_mobject_updating: bool = False,\n        **kwargs: Any,\n    ):\n        self.path = path\n        super().__init__(\n            mobject, suspend_mobject_updating=suspend_mobject_updating, **kwargs\n        )\n\n    def interpolate_mobject(self, alpha: float) -> None:\n        point = self.path.point_from_proportion(self.rate_func(alpha))\n        self.mobject.move_to(point)\n"
  },
  {
    "path": "manim/animation/numbers.py",
    "content": "\"\"\"Animations for changing numbers.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"ChangingDecimal\", \"ChangeDecimalToValue\"]\n\n\nfrom collections.abc import Callable\nfrom typing import Any\n\nfrom manim.mobject.text.numbers import DecimalNumber\n\nfrom ..animation.animation import Animation\nfrom ..utils.bezier import interpolate\n\n\nclass ChangingDecimal(Animation):\n    \"\"\"Animate a :class:`~.DecimalNumber` to values specified by a user-supplied function.\n\n    Parameters\n    ----------\n    decimal_mob\n        The :class:`~.DecimalNumber` instance to animate.\n    number_update_func\n        A function that returns the number to display at each point in the animation.\n    suspend_mobject_updating\n        If ``True``, the mobject is not updated outside this animation.\n\n    Raises\n    ------\n    TypeError\n        If ``decimal_mob`` is not an instance of :class:`~.DecimalNumber`.\n\n    Examples\n    --------\n\n    .. manim:: ChangingDecimalExample\n\n        class ChangingDecimalExample(Scene):\n            def construct(self):\n                number = DecimalNumber(0)\n                self.add(number)\n                self.play(\n                    ChangingDecimal(\n                        number,\n                        lambda a: 5 * a,\n                        run_time=3\n                    )\n                )\n                self.wait()\n    \"\"\"\n\n    def __init__(\n        self,\n        decimal_mob: DecimalNumber,\n        number_update_func: Callable[[float], float],\n        suspend_mobject_updating: bool = False,\n        **kwargs: Any,\n    ) -> None:\n        self.check_validity_of_input(decimal_mob)\n        self.number_update_func = number_update_func\n        super().__init__(\n            decimal_mob, suspend_mobject_updating=suspend_mobject_updating, **kwargs\n        )\n\n    def check_validity_of_input(self, decimal_mob: DecimalNumber) -> None:\n        if not isinstance(decimal_mob, DecimalNumber):\n            raise TypeError(\"ChangingDecimal can only take in a DecimalNumber\")\n\n    def interpolate_mobject(self, alpha: float) -> None:\n        self.mobject.set_value(self.number_update_func(self.rate_func(alpha)))  # type: ignore[attr-defined]\n\n\nclass ChangeDecimalToValue(ChangingDecimal):\n    \"\"\"Animate a :class:`~.DecimalNumber` to a target value using linear interpolation.\n\n    Parameters\n    ----------\n    decimal_mob\n        The :class:`~.DecimalNumber` instance to animate.\n    target_number\n        The target value to transition to.\n\n    Examples\n    --------\n\n    .. manim:: ChangeDecimalToValueExample\n\n        class ChangeDecimalToValueExample(Scene):\n            def construct(self):\n                number = DecimalNumber(0)\n                self.add(number)\n                self.play(ChangeDecimalToValue(number, 10, run_time=3))\n                self.wait()\n    \"\"\"\n\n    def __init__(\n        self, decimal_mob: DecimalNumber, target_number: int, **kwargs: Any\n    ) -> None:\n        start_number = decimal_mob.number\n        super().__init__(\n            decimal_mob, lambda a: interpolate(start_number, target_number, a), **kwargs\n        )\n"
  },
  {
    "path": "manim/animation/rotation.py",
    "content": "\"\"\"Animations related to rotation.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"Rotating\", \"Rotate\"]\n\nfrom collections.abc import Callable\nfrom typing import TYPE_CHECKING, Any\n\nfrom ..animation.animation import Animation\nfrom ..animation.transform import Transform\nfrom ..constants import OUT, PI, TAU\nfrom ..utils.rate_functions import linear\n\nif TYPE_CHECKING:\n    from ..mobject.mobject import Mobject\n    from ..mobject.opengl.opengl_mobject import OpenGLMobject\n    from ..typing import Point3DLike, Vector3DLike\n\n\nclass Rotating(Animation):\n    \"\"\"Animation that rotates a Mobject.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to be rotated.\n    angle\n        The rotation angle in radians. Predefined constants such as ``DEGREES``\n        can also be used to specify the angle in degrees.\n    axis\n        The rotation axis as a numpy vector.\n    about_point\n        The rotation center.\n    about_edge\n        If ``about_point`` is ``None``, this argument specifies\n        the direction of the bounding box point to be taken as\n        the rotation center.\n    run_time\n        The duration of the animation in seconds.\n    rate_func\n        The function defining the animation progress based on the relative\n        runtime (see :mod:`~.rate_functions`) .\n    **kwargs\n        Additional keyword arguments passed to :class:`~.Animation`.\n\n    Examples\n    --------\n    .. manim:: RotatingDemo\n\n        class RotatingDemo(Scene):\n            def construct(self):\n                circle = Circle(radius=1, color=BLUE)\n                line = Line(start=ORIGIN, end=RIGHT)\n                arrow = Arrow(start=ORIGIN, end=RIGHT, buff=0, color=GOLD)\n                vg = VGroup(circle,line,arrow)\n                self.add(vg)\n                anim_kw = {\"about_point\": arrow.get_start(), \"run_time\": 1}\n                self.play(Rotating(arrow, 180*DEGREES, **anim_kw))\n                self.play(Rotating(arrow, PI, **anim_kw))\n                self.play(Rotating(vg, PI, about_point=RIGHT))\n                self.play(Rotating(vg, PI, axis=UP, about_point=ORIGIN))\n                self.play(Rotating(vg, PI, axis=RIGHT, about_edge=UP))\n                self.play(vg.animate.move_to(ORIGIN))\n\n    .. manim:: RotatingDifferentAxis\n\n        class RotatingDifferentAxis(ThreeDScene):\n            def construct(self):\n                axes = ThreeDAxes()\n                cube = Cube()\n                arrow2d = Arrow(start=[0, -1.2, 1], end=[0, 1.2, 1], color=YELLOW_E)\n                cube_group = VGroup(cube,arrow2d)\n                self.set_camera_orientation(gamma=0, phi=40*DEGREES, theta=40*DEGREES)\n                self.add(axes, cube_group)\n                play_kw = {\"run_time\": 1.5}\n                self.play(Rotating(cube_group, PI), **play_kw)\n                self.play(Rotating(cube_group, PI, axis=UP), **play_kw)\n                self.play(Rotating(cube_group, 180*DEGREES, axis=RIGHT), **play_kw)\n                self.wait(0.5)\n\n    See also\n    --------\n    :class:`~.Rotate`, :meth:`~.Mobject.rotate`\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        angle: float = TAU,\n        axis: Vector3DLike = OUT,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n        run_time: float = 5,\n        rate_func: Callable[[float], float] = linear,\n        **kwargs: Any,\n    ) -> None:\n        self.angle = angle\n        self.axis = axis\n        self.about_point = about_point\n        self.about_edge = about_edge\n        super().__init__(mobject, run_time=run_time, rate_func=rate_func, **kwargs)\n\n    def interpolate_mobject(self, alpha: float) -> None:\n        self.mobject.become(self.starting_mobject)\n        self.mobject.rotate(\n            self.rate_func(alpha) * self.angle,\n            axis=self.axis,\n            about_point=self.about_point,\n            about_edge=self.about_edge,\n        )\n\n\nclass Rotate(Transform):\n    \"\"\"Animation that rotates a Mobject.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to be rotated.\n    angle\n        The rotation angle.\n    axis\n        The rotation axis as a numpy vector.\n    about_point\n        The rotation center.\n    about_edge\n        If ``about_point`` is ``None``, this argument specifies\n        the direction of the bounding box point to be taken as\n        the rotation center.\n\n    Examples\n    --------\n    .. manim:: UsingRotate\n\n        class UsingRotate(Scene):\n            def construct(self):\n                self.play(\n                    Rotate(\n                        Square(side_length=0.5).shift(UP * 2),\n                        angle=2*PI,\n                        about_point=ORIGIN,\n                        rate_func=linear,\n                    ),\n                    Rotate(Square(side_length=0.5), angle=2*PI, rate_func=linear),\n                    )\n\n    See also\n    --------\n    :class:`~.Rotating`, :meth:`~.Mobject.rotate`\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        angle: float = PI,\n        axis: Vector3DLike = OUT,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n        **kwargs: Any,\n    ) -> None:\n        if \"path_arc\" not in kwargs:\n            kwargs[\"path_arc\"] = angle\n        if \"path_arc_axis\" not in kwargs:\n            kwargs[\"path_arc_axis\"] = axis\n        self.angle = angle\n        self.axis = axis\n        self.about_edge = about_edge\n        self.about_point = about_point\n        if self.about_point is None:\n            self.about_point = mobject.get_center()\n        super().__init__(mobject, path_arc_centers=self.about_point, **kwargs)\n\n    def create_target(self) -> Mobject | OpenGLMobject:\n        target = self.mobject.copy()\n        target.rotate(\n            self.angle,\n            axis=self.axis,\n            about_point=self.about_point,\n            about_edge=self.about_edge,\n        )\n        return target\n"
  },
  {
    "path": "manim/animation/specialized.py",
    "content": "from __future__ import annotations\n\n__all__ = [\"Broadcast\"]\n\nfrom collections.abc import Sequence\nfrom typing import Any\n\nfrom manim.animation.transform import Restore\nfrom manim.mobject.mobject import Mobject\n\nfrom ..constants import *\nfrom .composition import LaggedStart\n\n\nclass Broadcast(LaggedStart):\n    \"\"\"Broadcast a mobject starting from an ``initial_width``, up to the actual size of the mobject.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to be broadcast.\n    focal_point\n        The center of the broadcast, by default ORIGIN.\n    n_mobs\n        The number of mobjects that emerge from the focal point, by default 5.\n    initial_opacity\n        The starting stroke opacity of the mobjects emitted from the broadcast, by default 1.\n    final_opacity\n        The final stroke opacity of the mobjects emitted from the broadcast, by default 0.\n    initial_width\n        The initial width of the mobjects, by default 0.0.\n    remover\n        Whether the mobjects should be removed from the scene after the animation, by default True.\n    lag_ratio\n        The time between each iteration of the mobject, by default 0.2.\n    run_time\n        The total duration of the animation, by default 3.\n    kwargs\n        Additional arguments to be passed to :class:`~.LaggedStart`.\n\n    Examples\n    ---------\n\n    .. manim:: BroadcastExample\n\n        class BroadcastExample(Scene):\n            def construct(self):\n                mob = Circle(radius=4, color=TEAL_A)\n                self.play(Broadcast(mob))\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        focal_point: Sequence[float] = ORIGIN,\n        n_mobs: int = 5,\n        initial_opacity: float = 1,\n        final_opacity: float = 0,\n        initial_width: float = 0.0,\n        remover: bool = True,\n        lag_ratio: float = 0.2,\n        run_time: float = 3,\n        **kwargs: Any,\n    ):\n        self.focal_point = focal_point\n        self.n_mobs = n_mobs\n        self.initial_opacity = initial_opacity\n        self.final_opacity = final_opacity\n        self.initial_width = initial_width\n\n        anims = []\n\n        # Works by saving the mob that is passed into the animation, scaling it to 0 (or the initial_width) and then restoring the original mob.\n        fill_o = bool(mobject.fill_opacity)\n\n        for _ in range(self.n_mobs):\n            mob = mobject.copy()\n\n            if fill_o:\n                mob.set_opacity(self.final_opacity)\n            else:\n                mob.set_stroke(opacity=self.final_opacity)\n\n            mob.move_to(self.focal_point)\n            mob.save_state()\n            mob.set(width=self.initial_width)\n\n            if fill_o:\n                mob.set_opacity(self.initial_opacity)\n            else:\n                mob.set_stroke(opacity=self.initial_opacity)\n\n            anims.append(Restore(mob, remover=remover))\n\n        super().__init__(*anims, run_time=run_time, lag_ratio=lag_ratio, **kwargs)\n"
  },
  {
    "path": "manim/animation/speedmodifier.py",
    "content": "\"\"\"Utilities for modifying the speed at which animations are played.\"\"\"\n\nfrom __future__ import annotations\n\nimport inspect\nimport types\nfrom collections.abc import Callable\nfrom typing import TYPE_CHECKING\n\nfrom numpy import piecewise\n\nfrom ..animation.animation import Animation, Wait, prepare_animation\nfrom ..animation.composition import AnimationGroup\nfrom ..mobject.mobject import Mobject, _AnimationBuilder\nfrom ..scene.scene import Scene\n\nif TYPE_CHECKING:\n    from ..mobject.mobject import Updater\n\n__all__ = [\"ChangeSpeed\"]\n\n\nclass ChangeSpeed(Animation):\n    \"\"\"Modifies the speed of passed animation.\n    :class:`AnimationGroup` with different ``lag_ratio`` can also be used\n    which combines multiple animations into one.\n    The ``run_time`` of the passed animation is changed to modify the speed.\n\n    Parameters\n    ----------\n    anim\n        Animation of which the speed is to be modified.\n    speedinfo\n        Contains nodes (percentage of ``run_time``) and its corresponding speed factor.\n    rate_func\n        Overrides ``rate_func`` of passed animation, applied before changing speed.\n\n    Examples\n    --------\n\n    .. manim:: SpeedModifierExample\n\n        class SpeedModifierExample(Scene):\n            def construct(self):\n                a = Dot().shift(LEFT * 4)\n                b = Dot().shift(RIGHT * 4)\n                self.add(a, b)\n                self.play(\n                    ChangeSpeed(\n                        AnimationGroup(\n                            a.animate(run_time=1).shift(RIGHT * 8),\n                            b.animate(run_time=1).shift(LEFT * 8),\n                        ),\n                        speedinfo={0.3: 1, 0.4: 0.1, 0.6: 0.1, 1: 1},\n                        rate_func=linear,\n                    )\n                )\n\n    .. manim:: SpeedModifierUpdaterExample\n\n        class SpeedModifierUpdaterExample(Scene):\n            def construct(self):\n                a = Dot().shift(LEFT * 4)\n                self.add(a)\n\n                ChangeSpeed.add_updater(a, lambda x, dt: x.shift(RIGHT * 4 * dt))\n                self.play(\n                    ChangeSpeed(\n                        Wait(2),\n                        speedinfo={0.4: 1, 0.5: 0.2, 0.8: 0.2, 1: 1},\n                        affects_speed_updaters=True,\n                    )\n                )\n\n    .. manim:: SpeedModifierUpdaterExample2\n\n        class SpeedModifierUpdaterExample2(Scene):\n            def construct(self):\n                a = Dot().shift(LEFT * 4)\n                self.add(a)\n\n                ChangeSpeed.add_updater(a, lambda x, dt: x.shift(RIGHT * 4 * dt))\n                self.wait()\n                self.play(\n                    ChangeSpeed(\n                        Wait(),\n                        speedinfo={1: 0},\n                        affects_speed_updaters=True,\n                    )\n                )\n\n    \"\"\"\n\n    dt = 0\n    is_changing_dt = False\n\n    def __init__(\n        self,\n        anim: Animation | _AnimationBuilder,\n        speedinfo: dict[float, float],\n        rate_func: Callable[[float], float] | None = None,\n        affects_speed_updaters: bool = True,\n        **kwargs,\n    ) -> None:\n        if issubclass(type(anim), AnimationGroup):\n            self.anim = type(anim)(\n                *map(self.setup, anim.animations),\n                group=anim.group,\n                run_time=anim.run_time,\n                rate_func=anim.rate_func,\n                lag_ratio=anim.lag_ratio,\n            )\n        else:\n            self.anim = self.setup(anim)\n\n        if affects_speed_updaters:\n            assert ChangeSpeed.is_changing_dt is False, (\n                \"Only one animation at a time can play that changes speed (dt) for ChangeSpeed updaters\"\n            )\n            ChangeSpeed.is_changing_dt = True\n            self.t = 0\n        self.affects_speed_updaters = affects_speed_updaters\n\n        self.rate_func = self.anim.rate_func if rate_func is None else rate_func\n\n        # A function where, f(0) = 0, f'(0) = initial speed, f'( f-1(1) ) = final speed\n        # Following function obtained when conditions applied to vertical parabola\n        self.speed_modifier = lambda x, init_speed, final_speed: (\n            (final_speed**2 - init_speed**2) * x**2 / 4 + init_speed * x\n        )\n\n        # f-1(1), returns x for which f(x) = 1 in `speed_modifier` function\n        self.f_inv_1 = lambda init_speed, final_speed: 2 / (init_speed + final_speed)\n\n        # if speed factors for the starting node (0) and the final node (1) are\n        # not set, set them to 1 and the penultimate factor, respectively\n        if 0 not in speedinfo:\n            speedinfo[0] = 1\n        if 1 not in speedinfo:\n            speedinfo[1] = sorted(speedinfo.items())[-1][1]\n\n        self.speedinfo = dict(sorted(speedinfo.items()))\n        self.functions = []\n        self.conditions = []\n\n        # Get the time taken by amimation if `run_time` is assumed to be 1\n        scaled_total_time = self.get_scaled_total_time()\n\n        prevnode = 0\n        init_speed = self.speedinfo[0]\n        curr_time = 0\n        for node, final_speed in list(self.speedinfo.items())[1:]:\n            dur = node - prevnode\n\n            def condition(\n                t,\n                curr_time=curr_time,\n                init_speed=init_speed,\n                final_speed=final_speed,\n                dur=dur,\n            ):\n                lower_bound = curr_time / scaled_total_time\n                upper_bound = (\n                    curr_time + self.f_inv_1(init_speed, final_speed) * dur\n                ) / scaled_total_time\n                return lower_bound <= t <= upper_bound\n\n            self.conditions.append(condition)\n\n            def function(\n                t,\n                curr_time=curr_time,\n                init_speed=init_speed,\n                final_speed=final_speed,\n                dur=dur,\n                prevnode=prevnode,\n            ):\n                return (\n                    self.speed_modifier(\n                        (scaled_total_time * t - curr_time) / dur,\n                        init_speed,\n                        final_speed,\n                    )\n                    * dur\n                    + prevnode\n                )\n\n            self.functions.append(function)\n\n            curr_time += self.f_inv_1(init_speed, final_speed) * dur\n            prevnode = node\n            init_speed = final_speed\n\n        def func(t):\n            if t == 1:\n                ChangeSpeed.is_changing_dt = False\n            new_t = piecewise(\n                self.rate_func(t),\n                [condition(self.rate_func(t)) for condition in self.conditions],\n                self.functions,\n            )\n            if self.affects_speed_updaters:\n                ChangeSpeed.dt = (new_t - self.t) * self.anim.run_time\n                self.t = new_t\n            return new_t\n\n        self.anim.set_rate_func(func)\n\n        super().__init__(\n            self.anim.mobject,\n            rate_func=self.rate_func,\n            run_time=scaled_total_time * self.anim.run_time,\n            **kwargs,\n        )\n\n    def setup(self, anim):\n        if type(anim) is Wait:\n            anim.interpolate = types.MethodType(\n                lambda self, alpha: self.rate_func(alpha), anim\n            )\n        return prepare_animation(anim)\n\n    def get_scaled_total_time(self) -> float:\n        \"\"\"The time taken by the animation under the assumption that the ``run_time`` is 1.\"\"\"\n        prevnode = 0\n        init_speed = self.speedinfo[0]\n        total_time = 0\n        for node, final_speed in list(self.speedinfo.items())[1:]:\n            dur = node - prevnode\n            total_time += dur * self.f_inv_1(init_speed, final_speed)\n            prevnode = node\n            init_speed = final_speed\n        return total_time\n\n    @classmethod\n    def add_updater(\n        cls,\n        mobject: Mobject,\n        update_function: Updater,\n        index: int | None = None,\n        call_updater: bool = False,\n    ):\n        \"\"\"This static method can be used to apply speed change to updaters.\n\n        This updater will follow speed and rate function of any :class:`.ChangeSpeed`\n        animation that is playing with ``affects_speed_updaters=True``. By default,\n        updater functions added via the usual :meth:`.Mobject.add_updater` method\n        do not respect the change of animation speed.\n\n        Parameters\n        ----------\n        mobject\n            The mobject to which the updater should be attached.\n        update_function\n            The function that is called whenever a new frame is rendered.\n        index\n            The position in the list of the mobject's updaters at which the\n            function should be inserted.\n        call_updater\n            If ``True``, calls the update function when attaching it to the\n            mobject.\n\n        See also\n        --------\n        :class:`.ChangeSpeed`\n        :meth:`.Mobject.add_updater`\n        \"\"\"\n        if \"dt\" in inspect.signature(update_function).parameters:\n            mobject.add_updater(\n                lambda mob, dt: update_function(\n                    mob, ChangeSpeed.dt if ChangeSpeed.is_changing_dt else dt\n                ),\n                index=index,\n                call_updater=call_updater,\n            )\n        else:\n            mobject.add_updater(update_function, index=index, call_updater=call_updater)\n\n    def interpolate(self, alpha: float) -> None:\n        self.anim.interpolate(alpha)\n\n    def update_mobjects(self, dt: float) -> None:\n        self.anim.update_mobjects(dt)\n\n    def finish(self) -> None:\n        ChangeSpeed.is_changing_dt = False\n        self.anim.finish()\n\n    def begin(self) -> None:\n        self.anim.begin()\n\n    def clean_up_from_scene(self, scene: Scene) -> None:\n        self.anim.clean_up_from_scene(scene)\n\n    def _setup_scene(self, scene) -> None:\n        self.anim._setup_scene(scene)\n"
  },
  {
    "path": "manim/animation/transform.py",
    "content": "\"\"\"Animations transforming one mobject into another.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"Transform\",\n    \"ReplacementTransform\",\n    \"TransformFromCopy\",\n    \"ClockwiseTransform\",\n    \"CounterclockwiseTransform\",\n    \"MoveToTarget\",\n    \"ApplyMethod\",\n    \"ApplyPointwiseFunction\",\n    \"ApplyPointwiseFunctionToCenter\",\n    \"FadeToColor\",\n    \"FadeTransform\",\n    \"FadeTransformPieces\",\n    \"ScaleInPlace\",\n    \"ShrinkToCenter\",\n    \"Restore\",\n    \"ApplyFunction\",\n    \"ApplyMatrix\",\n    \"ApplyComplexFunction\",\n    \"CyclicReplace\",\n    \"Swap\",\n    \"TransformAnimations\",\n]\n\nimport inspect\nimport types\nfrom collections.abc import Callable, Iterable, Sequence\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom manim.data_structures import MethodWithArgs\nfrom manim.mobject.opengl.opengl_mobject import OpenGLGroup, OpenGLMobject\n\nfrom .. import config\nfrom ..animation.animation import Animation\nfrom ..constants import (\n    DEFAULT_POINTWISE_FUNCTION_RUN_TIME,\n    DEGREES,\n    ORIGIN,\n    OUT,\n    RendererType,\n)\nfrom ..mobject.mobject import Group, Mobject\nfrom ..utils.paths import path_along_arc, path_along_circles\nfrom ..utils.rate_functions import smooth, squish_rate_func\n\nif TYPE_CHECKING:\n    from ..scene.scene import Scene\n    from ..typing import Point3DLike, Point3DLike_Array\n\n\nclass Transform(Animation):\n    \"\"\"A Transform transforms a Mobject into a target Mobject.\n\n    Parameters\n    ----------\n    mobject\n        The :class:`.Mobject` to be transformed. It will be mutated to become the ``target_mobject``.\n    target_mobject\n        The target of the transformation.\n    path_func\n        A function defining the path that the points of the ``mobject`` are being moved\n        along until they match the points of the ``target_mobject``, see :mod:`.utils.paths`.\n    path_arc\n        The arc angle (in radians) that the points of ``mobject`` will follow to reach\n        the points of the target if using a circular path arc, see ``path_arc_centers``.\n        See also :func:`manim.utils.paths.path_along_arc`.\n    path_arc_axis\n        The axis to rotate along if using a circular path arc, see ``path_arc_centers``.\n    path_arc_centers\n        The center of the circular arcs along which the points of ``mobject`` are\n        moved by the transformation.\n\n        If this is set and ``path_func`` is not set, then a ``path_along_circles`` path will be generated\n        using the ``path_arc`` parameters and stored in ``path_func``. If ``path_func`` is set, this and the\n        other ``path_arc`` fields are set as attributes, but a ``path_func`` is not generated from it.\n    replace_mobject_with_target_in_scene\n        Controls which mobject is replaced when the transformation is complete.\n\n        If set to True, ``mobject`` will be removed from the scene and ``target_mobject`` will\n        replace it. Otherwise, ``target_mobject`` is never added and ``mobject`` just takes its shape.\n\n    Examples\n    --------\n\n    .. manim :: TransformPathArc\n\n        class TransformPathArc(Scene):\n            def construct(self):\n                def make_arc_path(start, end, arc_angle):\n                    points = []\n                    p_fn = path_along_arc(arc_angle)\n                    # alpha animates between 0.0 and 1.0, where 0.0\n                    # is the beginning of the animation and 1.0 is the end.\n                    for alpha in range(0, 11):\n                        points.append(p_fn(start, end, alpha / 10.0))\n                    path = VMobject(stroke_color=YELLOW)\n                    path.set_points_smoothly(points)\n                    return path\n\n                left = Circle(stroke_color=BLUE_E, fill_opacity=1.0, radius=0.5).move_to(LEFT * 2)\n                colors = [TEAL_A, TEAL_B, TEAL_C, TEAL_D, TEAL_E, GREEN_A]\n                # Positive angles move counter-clockwise, negative angles move clockwise.\n                examples = [-90, 0, 30, 90, 180, 270]\n                anims = []\n                for idx, angle in enumerate(examples):\n                    left_c = left.copy().shift((3 - idx) * UP)\n                    left_c.fill_color = colors[idx]\n                    right_c = left_c.copy().shift(4 * RIGHT)\n                    path_arc = make_arc_path(left_c.get_center(), right_c.get_center(),\n                                             arc_angle=angle * DEGREES)\n                    desc = Text('%d°' % examples[idx]).next_to(left_c, LEFT)\n                    # Make the circles in front of the text in front of the arcs.\n                    self.add(\n                        path_arc.set_z_index(1),\n                        desc.set_z_index(2),\n                        left_c.set_z_index(3),\n                    )\n                    anims.append(Transform(left_c, right_c, path_arc=angle * DEGREES))\n\n                self.play(*anims, run_time=2)\n                self.wait()\n\n    See also\n    --------\n    :class:`~.ReplacementTransform`, :meth:`~.Mobject.interpolate`, :meth:`~.Mobject.align_data`\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject | None,\n        target_mobject: Mobject | None = None,\n        path_func: Callable | None = None,\n        path_arc: float = 0,\n        path_arc_axis: np.ndarray = OUT,\n        path_arc_centers: Point3DLike | Point3DLike_Array | None = None,\n        replace_mobject_with_target_in_scene: bool = False,\n        **kwargs,\n    ) -> None:\n        self.path_arc_axis: np.ndarray = path_arc_axis\n        self.path_arc_centers: Point3DLike | Point3DLike_Array | None = path_arc_centers\n        self.path_arc: float = path_arc\n\n        # path_func is a property a few lines below so it doesn't need to be set in any case\n        if path_func is not None:\n            self.path_func: Callable = path_func\n        elif self.path_arc_centers is not None:\n            self.path_func = path_along_circles(\n                path_arc,\n                self.path_arc_centers,\n                self.path_arc_axis,\n            )\n\n        self.replace_mobject_with_target_in_scene: bool = (\n            replace_mobject_with_target_in_scene\n        )\n        self.target_mobject: Mobject = (\n            target_mobject if target_mobject is not None else Mobject()\n        )\n        super().__init__(mobject, **kwargs)\n\n    @property\n    def path_arc(self) -> float:\n        return self._path_arc\n\n    @path_arc.setter\n    def path_arc(self, path_arc: float) -> None:\n        self._path_arc = path_arc\n        self._path_func = path_along_arc(\n            arc_angle=self._path_arc,\n            axis=self.path_arc_axis,\n        )\n\n    @property\n    def path_func(\n        self,\n    ) -> Callable[\n        [Iterable[np.ndarray], Iterable[np.ndarray], float],\n        Iterable[np.ndarray],\n    ]:\n        return self._path_func\n\n    @path_func.setter\n    def path_func(\n        self,\n        path_func: Callable[\n            [Iterable[np.ndarray], Iterable[np.ndarray], float],\n            Iterable[np.ndarray],\n        ],\n    ) -> None:\n        if path_func is not None:\n            self._path_func = path_func\n\n    def begin(self) -> None:\n        # Use a copy of target_mobject for the align_data\n        # call so that the actual target_mobject stays\n        # preserved.\n        self.target_mobject = self.create_target()\n        self.target_copy = self.target_mobject.copy()\n        # Note, this potentially changes the structure\n        # of both mobject and target_mobject\n        if config.renderer == RendererType.OPENGL:\n            self.mobject.align_data_and_family(self.target_copy)\n        else:\n            self.mobject.align_data(self.target_copy)\n        super().begin()\n\n    def create_target(self) -> Mobject | OpenGLMobject:\n        # Has no meaningful effect here, but may be useful\n        # in subclasses\n        return self.target_mobject\n\n    def clean_up_from_scene(self, scene: Scene) -> None:\n        super().clean_up_from_scene(scene)\n        if self.replace_mobject_with_target_in_scene:\n            scene.replace(self.mobject, self.target_mobject)\n\n    def get_all_mobjects(self) -> Sequence[Mobject]:\n        return [\n            self.mobject,\n            self.starting_mobject,\n            self.target_mobject,\n            self.target_copy,\n        ]\n\n    def get_all_families_zipped(self) -> Iterable[tuple]:  # more precise typing?\n        mobs = [\n            self.mobject,\n            self.starting_mobject,\n            self.target_copy,\n        ]\n        if config.renderer == RendererType.OPENGL:\n            return zip(*(mob.get_family() for mob in mobs), strict=True)\n        return zip(*(mob.family_members_with_points() for mob in mobs), strict=True)\n\n    def interpolate_submobject(\n        self,\n        submobject: Mobject,\n        starting_submobject: Mobject,\n        target_copy: Mobject,\n        alpha: float,\n    ) -> Transform:\n        submobject.interpolate(starting_submobject, target_copy, alpha, self.path_func)\n        return self\n\n\nclass ReplacementTransform(Transform):\n    \"\"\"Replaces and morphs a mobject into a target mobject.\n\n    Parameters\n    ----------\n    mobject\n        The starting :class:`~.Mobject`.\n    target_mobject\n        The target :class:`~.Mobject`.\n    kwargs\n        Further keyword arguments that are passed to :class:`Transform`.\n\n    Examples\n    --------\n\n    .. manim:: ReplacementTransformOrTransform\n        :quality: low\n\n        class ReplacementTransformOrTransform(Scene):\n            def construct(self):\n                # set up the numbers\n                r_transform = VGroup(*[Integer(i) for i in range(1,4)])\n                text_1 = Text(\"ReplacementTransform\", color=RED)\n                r_transform.add(text_1)\n\n                transform = VGroup(*[Integer(i) for i in range(4,7)])\n                text_2 = Text(\"Transform\", color=BLUE)\n                transform.add(text_2)\n\n                ints = VGroup(r_transform, transform)\n                texts = VGroup(text_1, text_2).scale(0.75)\n                r_transform.arrange(direction=UP, buff=1)\n                transform.arrange(direction=UP, buff=1)\n\n                ints.arrange(buff=2)\n                self.add(ints, texts)\n\n                # The mobs replace each other and none are left behind\n                self.play(ReplacementTransform(r_transform[0], r_transform[1]))\n                self.play(ReplacementTransform(r_transform[1], r_transform[2]))\n\n                # The mobs linger after the Transform()\n                self.play(Transform(transform[0], transform[1]))\n                self.play(Transform(transform[1], transform[2]))\n                self.wait()\n\n    \"\"\"\n\n    def __init__(self, mobject: Mobject, target_mobject: Mobject, **kwargs) -> None:\n        super().__init__(\n            mobject, target_mobject, replace_mobject_with_target_in_scene=True, **kwargs\n        )\n\n\nclass TransformFromCopy(Transform):\n    \"\"\"Preserves a copy of the original VMobject and transforms only it's copy to the target VMobject\"\"\"\n\n    def __init__(self, mobject: Mobject, target_mobject: Mobject, **kwargs) -> None:\n        super().__init__(target_mobject, mobject, **kwargs)\n\n    def interpolate(self, alpha: float) -> None:\n        super().interpolate(1 - alpha)\n\n\nclass ClockwiseTransform(Transform):\n    \"\"\"Transforms the points of a mobject along a clockwise oriented arc.\n\n    See also\n    --------\n    :class:`.Transform`, :class:`.CounterclockwiseTransform`\n\n    Examples\n    --------\n\n    .. manim:: ClockwiseExample\n\n        class ClockwiseExample(Scene):\n            def construct(self):\n                dl, dr = Dot(), Dot()\n                sl, sr = Square(), Square()\n\n                VGroup(dl, sl).arrange(DOWN).shift(2*LEFT)\n                VGroup(dr, sr).arrange(DOWN).shift(2*RIGHT)\n\n                self.add(dl, dr)\n                self.wait()\n                self.play(\n                    ClockwiseTransform(dl, sl),\n                    Transform(dr, sr)\n                )\n                self.wait()\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        target_mobject: Mobject,\n        path_arc: float = -np.pi,\n        **kwargs,\n    ) -> None:\n        super().__init__(mobject, target_mobject, path_arc=path_arc, **kwargs)\n\n\nclass CounterclockwiseTransform(Transform):\n    \"\"\"Transforms the points of a mobject along a counterclockwise oriented arc.\n\n    See also\n    --------\n    :class:`.Transform`, :class:`.ClockwiseTransform`\n\n    Examples\n    --------\n\n    .. manim:: CounterclockwiseTransform_vs_Transform\n\n        class CounterclockwiseTransform_vs_Transform(Scene):\n            def construct(self):\n                # set up the numbers\n                c_transform = VGroup(DecimalNumber(number=3.141, num_decimal_places=3), DecimalNumber(number=1.618, num_decimal_places=3))\n                text_1 = Text(\"CounterclockwiseTransform\", color=RED)\n                c_transform.add(text_1)\n\n                transform = VGroup(DecimalNumber(number=1.618, num_decimal_places=3), DecimalNumber(number=3.141, num_decimal_places=3))\n                text_2 = Text(\"Transform\", color=BLUE)\n                transform.add(text_2)\n\n                ints = VGroup(c_transform, transform)\n                texts = VGroup(text_1, text_2).scale(0.75)\n                c_transform.arrange(direction=UP, buff=1)\n                transform.arrange(direction=UP, buff=1)\n\n                ints.arrange(buff=2)\n                self.add(ints, texts)\n\n                # The mobs move in clockwise direction for ClockwiseTransform()\n                self.play(CounterclockwiseTransform(c_transform[0], c_transform[1]))\n\n                # The mobs move straight up for Transform()\n                self.play(Transform(transform[0], transform[1]))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        target_mobject: Mobject,\n        path_arc: float = np.pi,\n        **kwargs,\n    ) -> None:\n        super().__init__(mobject, target_mobject, path_arc=path_arc, **kwargs)\n\n\nclass MoveToTarget(Transform):\n    \"\"\"Transforms a mobject to the mobject stored in its ``target`` attribute.\n\n    After calling the :meth:`~.Mobject.generate_target` method, the :attr:`target`\n    attribute of the mobject is populated with a copy of it. After modifying the attribute,\n    playing the :class:`.MoveToTarget` animation transforms the original mobject\n    into the modified one stored in the :attr:`target` attribute.\n\n    Examples\n    --------\n\n    .. manim:: MoveToTargetExample\n\n        class MoveToTargetExample(Scene):\n            def construct(self):\n                c = Circle()\n\n                c.generate_target()\n                c.target.set_fill(color=GREEN, opacity=0.5)\n                c.target.shift(2*RIGHT + UP).scale(0.5)\n\n                self.add(c)\n                self.play(MoveToTarget(c))\n\n    \"\"\"\n\n    def __init__(self, mobject: Mobject, **kwargs) -> None:\n        self.check_validity_of_input(mobject)\n        super().__init__(mobject, mobject.target, **kwargs)\n\n    def check_validity_of_input(self, mobject: Mobject) -> None:\n        if not hasattr(mobject, \"target\"):\n            raise ValueError(\n                \"MoveToTarget called on mobjectwithout attribute 'target'\",\n            )\n\n\nclass _MethodAnimation(MoveToTarget):\n    def __init__(self, mobject: Mobject, methods: list[MethodWithArgs]) -> None:\n        self.methods = methods\n        super().__init__(mobject)\n\n    def finish(self) -> None:\n        for item in self.methods:\n            item.method.__func__(self.mobject, *item.args, **item.kwargs)\n        super().finish()\n\n\nclass ApplyMethod(Transform):\n    \"\"\"Animates a mobject by applying a method.\n\n    Note that only the method needs to be passed to this animation,\n    it is not required to pass the corresponding mobject. Furthermore,\n    this animation class only works if the method returns the modified\n    mobject.\n\n    Parameters\n    ----------\n    method\n        The method that will be applied in the animation.\n    args\n        Any positional arguments to be passed when applying the method.\n    kwargs\n        Any keyword arguments passed to :class:`~.Transform`.\n\n    \"\"\"\n\n    def __init__(\n        self, method: Callable, *args, **kwargs\n    ) -> None:  # method typing (we want to specify Mobject method)? for args?\n        self.check_validity_of_input(method)\n        self.method = method\n        self.method_args = args\n        super().__init__(method.__self__, **kwargs)\n\n    def check_validity_of_input(self, method: Callable) -> None:\n        if not inspect.ismethod(method):\n            raise ValueError(\n                \"Whoops, looks like you accidentally invoked \"\n                \"the method you want to animate\",\n            )\n        assert isinstance(method.__self__, (Mobject, OpenGLMobject))\n\n    def create_target(self) -> Mobject:\n        method = self.method\n        # Make sure it's a list so that args.pop() works\n        args = list(self.method_args)\n\n        if len(args) > 0 and isinstance(args[-1], dict):\n            method_kwargs = args.pop()\n        else:\n            method_kwargs = {}\n        target = method.__self__.copy()\n        method.__func__(target, *args, **method_kwargs)\n        return target\n\n\nclass ApplyPointwiseFunction(ApplyMethod):\n    \"\"\"Animation that applies a pointwise function to a mobject.\n\n    Examples\n    --------\n\n    .. manim:: WarpSquare\n        :quality: low\n\n        class WarpSquare(Scene):\n            def construct(self):\n                square = Square()\n                self.play(\n                    ApplyPointwiseFunction(\n                        lambda point: complex_to_R3(np.exp(R3_to_complex(point))), square\n                    )\n                )\n                self.wait()\n\n    \"\"\"\n\n    def __init__(\n        self,\n        function: types.MethodType,\n        mobject: Mobject,\n        run_time: float = DEFAULT_POINTWISE_FUNCTION_RUN_TIME,\n        **kwargs,\n    ) -> None:\n        super().__init__(mobject.apply_function, function, run_time=run_time, **kwargs)\n\n\nclass ApplyPointwiseFunctionToCenter(ApplyPointwiseFunction):\n    def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None:\n        self.function = function\n        super().__init__(mobject.move_to, **kwargs)\n\n    def begin(self) -> None:\n        self.method_args = [self.function(self.mobject.get_center())]\n        super().begin()\n\n\nclass FadeToColor(ApplyMethod):\n    \"\"\"Animation that changes color of a mobject.\n\n    Examples\n    --------\n\n    .. manim:: FadeToColorExample\n\n        class FadeToColorExample(Scene):\n            def construct(self):\n                self.play(FadeToColor(Text(\"Hello World!\"), color=RED))\n\n    \"\"\"\n\n    def __init__(self, mobject: Mobject, color: str, **kwargs) -> None:\n        super().__init__(mobject.set_color, color, **kwargs)\n\n\nclass ScaleInPlace(ApplyMethod):\n    \"\"\"Animation that scales a mobject by a certain factor.\n\n    Examples\n    --------\n\n    .. manim:: ScaleInPlaceExample\n\n        class ScaleInPlaceExample(Scene):\n            def construct(self):\n                self.play(ScaleInPlace(Text(\"Hello World!\"), 2))\n\n    \"\"\"\n\n    def __init__(self, mobject: Mobject, scale_factor: float, **kwargs) -> None:\n        super().__init__(mobject.scale, scale_factor, **kwargs)\n\n\nclass ShrinkToCenter(ScaleInPlace):\n    \"\"\"Animation that makes a mobject shrink to center.\n\n    Examples\n    --------\n\n    .. manim:: ShrinkToCenterExample\n\n        class ShrinkToCenterExample(Scene):\n            def construct(self):\n                self.play(ShrinkToCenter(Text(\"Hello World!\")))\n\n    \"\"\"\n\n    def __init__(self, mobject: Mobject, **kwargs) -> None:\n        super().__init__(mobject, 0, **kwargs)\n\n\nclass Restore(ApplyMethod):\n    \"\"\"Transforms a mobject to its last saved state.\n\n    To save the state of a mobject, use the :meth:`~.Mobject.save_state` method.\n\n    Examples\n    --------\n\n    .. manim:: RestoreExample\n\n        class RestoreExample(Scene):\n            def construct(self):\n                s = Square()\n                s.save_state()\n                self.play(FadeIn(s))\n                self.play(s.animate.set_color(PURPLE).set_opacity(0.5).shift(2*LEFT).scale(3))\n                self.play(s.animate.shift(5*DOWN).rotate(PI/4))\n                self.wait()\n                self.play(Restore(s), run_time=2)\n\n    \"\"\"\n\n    def __init__(self, mobject: Mobject, **kwargs) -> None:\n        super().__init__(mobject.restore, **kwargs)\n\n\nclass ApplyFunction(Transform):\n    def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None:\n        self.function = function\n        super().__init__(mobject, **kwargs)\n\n    def create_target(self) -> Any:\n        target = self.function(self.mobject.copy())\n        if not isinstance(target, (Mobject, OpenGLMobject)):\n            raise TypeError(\n                \"Functions passed to ApplyFunction must return object of type Mobject\",\n            )\n        return target\n\n\nclass ApplyMatrix(ApplyPointwiseFunction):\n    \"\"\"Applies a matrix transform to an mobject.\n\n    Parameters\n    ----------\n    matrix\n        The transformation matrix.\n    mobject\n        The :class:`~.Mobject`.\n    about_point\n        The origin point for the transform. Defaults to ``ORIGIN``.\n    kwargs\n        Further keyword arguments that are passed to :class:`ApplyPointwiseFunction`.\n\n    Examples\n    --------\n\n    .. manim:: ApplyMatrixExample\n\n        class ApplyMatrixExample(Scene):\n            def construct(self):\n                matrix = [[1, 1], [0, 2/3]]\n                self.play(ApplyMatrix(matrix, Text(\"Hello World!\")), ApplyMatrix(matrix, NumberPlane()))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        matrix: np.ndarray,\n        mobject: Mobject,\n        about_point: np.ndarray = ORIGIN,\n        **kwargs,\n    ) -> None:\n        matrix = self.initialize_matrix(matrix)\n\n        def func(p):\n            return np.dot(p - about_point, matrix.T) + about_point\n\n        super().__init__(func, mobject, **kwargs)\n\n    def initialize_matrix(self, matrix: np.ndarray) -> np.ndarray:\n        matrix = np.array(matrix)\n        if matrix.shape == (2, 2):\n            new_matrix = np.identity(3)\n            new_matrix[:2, :2] = matrix\n            matrix = new_matrix\n        elif matrix.shape != (3, 3):\n            raise ValueError(\"Matrix has bad dimensions\")\n        return matrix\n\n\nclass ApplyComplexFunction(ApplyMethod):\n    def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None:\n        self.function = function\n        method = mobject.apply_complex_function\n        super().__init__(method, function, **kwargs)\n\n    def _init_path_func(self) -> None:\n        func1 = self.function(complex(1))\n        self.path_arc = np.log(func1).imag\n        super()._init_path_func()\n\n\n###\n\n\nclass CyclicReplace(Transform):\n    \"\"\"An animation moving mobjects cyclically.\n\n    In particular, this means: the first mobject takes the place\n    of the second mobject, the second one takes the place of\n    the third mobject, and so on. The last mobject takes the\n    place of the first one.\n\n    Parameters\n    ----------\n    mobjects\n        List of mobjects to be transformed.\n    path_arc\n        The angle of the arc (in radians) that the mobjects will follow to reach\n        their target.\n    kwargs\n        Further keyword arguments that are passed to :class:`.Transform`.\n\n    Examples\n    --------\n    .. manim :: CyclicReplaceExample\n\n        class CyclicReplaceExample(Scene):\n            def construct(self):\n                group = VGroup(Square(), Circle(), Triangle(), Star())\n                group.arrange(RIGHT)\n                self.add(group)\n\n                for _ in range(4):\n                    self.play(CyclicReplace(*group))\n    \"\"\"\n\n    def __init__(\n        self, *mobjects: Mobject, path_arc: float = 90 * DEGREES, **kwargs\n    ) -> None:\n        self.group = Group(*mobjects)\n        super().__init__(self.group, path_arc=path_arc, **kwargs)\n\n    def create_target(self) -> Group:\n        target = self.group.copy()\n        cycled_targets = [target[-1], *target[:-1]]\n        for m1, m2 in zip(cycled_targets, self.group, strict=True):\n            m1.move_to(m2)\n        return target\n\n\nclass Swap(CyclicReplace):\n    pass  # Renaming, more understandable for two entries\n\n\n# TODO, this may be deprecated...worth reimplementing?\nclass TransformAnimations(Transform):\n    def __init__(\n        self,\n        start_anim: Animation,\n        end_anim: Animation,\n        rate_func: Callable = squish_rate_func(smooth),\n        **kwargs,\n    ) -> None:\n        self.start_anim = start_anim\n        self.end_anim = end_anim\n        if \"run_time\" in kwargs:\n            self.run_time = kwargs.pop(\"run_time\")\n        else:\n            self.run_time = max(start_anim.run_time, end_anim.run_time)\n        for anim in start_anim, end_anim:\n            anim.set_run_time(self.run_time)\n        if (\n            start_anim.starting_mobject is not None\n            and end_anim.starting_mobject is not None\n            and start_anim.starting_mobject.get_num_points()\n            != end_anim.starting_mobject.get_num_points()\n        ):\n            start_anim.starting_mobject.align_data(end_anim.starting_mobject)\n            for anim in start_anim, end_anim:\n                if isinstance(anim, Transform) and anim.starting_mobject is not None:\n                    anim.starting_mobject.align_data(anim.target_mobject)\n\n        super().__init__(\n            start_anim.mobject, end_anim.mobject, rate_func=rate_func, **kwargs\n        )\n        # Rewire starting and ending mobjects\n        start_anim.mobject = self.starting_mobject\n        end_anim.mobject = self.target_mobject\n\n    def interpolate(self, alpha: float) -> None:\n        self.start_anim.interpolate(alpha)\n        self.end_anim.interpolate(alpha)\n        super().interpolate(alpha)\n\n\nclass FadeTransform(Transform):\n    \"\"\"Fades one mobject into another.\n\n    Parameters\n    ----------\n    mobject\n        The starting :class:`~.Mobject`.\n    target_mobject\n        The target :class:`~.Mobject`.\n    stretch\n        Controls whether the target :class:`~.Mobject` is stretched during\n        the animation. Default: ``True``.\n    dim_to_match\n        If the target mobject is not stretched automatically, this allows\n        to adjust the initial scale of the target :class:`~.Mobject` while\n        it is shifted in. Setting this to 0, 1, and 2, respectively,\n        matches the length of the target with the length of the starting\n        :class:`~.Mobject` in x, y, and z direction, respectively.\n    kwargs\n        Further keyword arguments are passed to the parent class.\n\n    Examples\n    --------\n\n    .. manim:: DifferentFadeTransforms\n\n        class DifferentFadeTransforms(Scene):\n            def construct(self):\n                starts = [Rectangle(width=4, height=1) for _ in range(3)]\n                VGroup(*starts).arrange(DOWN, buff=1).shift(3*LEFT)\n                targets = [Circle(fill_opacity=1).scale(0.25) for _ in range(3)]\n                VGroup(*targets).arrange(DOWN, buff=1).shift(3*RIGHT)\n\n                self.play(*[FadeIn(s) for s in starts])\n                self.play(\n                    FadeTransform(starts[0], targets[0], stretch=True),\n                    FadeTransform(starts[1], targets[1], stretch=False, dim_to_match=0),\n                    FadeTransform(starts[2], targets[2], stretch=False, dim_to_match=1)\n                )\n\n                self.play(*[FadeOut(mobj) for mobj in self.mobjects])\n\n    \"\"\"\n\n    def __init__(self, mobject, target_mobject, stretch=True, dim_to_match=1, **kwargs):\n        self.to_add_on_completion = target_mobject\n        self.stretch = stretch\n        self.dim_to_match = dim_to_match\n        mobject.save_state()\n        if config.renderer == RendererType.OPENGL:\n            group = OpenGLGroup(mobject, target_mobject.copy())\n        else:\n            group = Group(mobject, target_mobject.copy())\n        super().__init__(group, **kwargs)\n\n    def begin(self):\n        \"\"\"Initial setup for the animation.\n\n        The mobject to which this animation is bound is a group consisting of\n        both the starting and the ending mobject. At the start, the ending\n        mobject replaces the starting mobject (and is completely faded). In the\n        end, it is set to be the other way around.\n        \"\"\"\n        self.ending_mobject = self.mobject.copy()\n        Animation.begin(self)\n        # Both 'start' and 'end' consists of the source and target mobjects.\n        # At the start, the target should be faded replacing the source,\n        # and at the end it should be the other way around.\n        start, end = self.starting_mobject, self.ending_mobject\n        for m0, m1 in ((start[1], start[0]), (end[0], end[1])):\n            self.ghost_to(m0, m1)\n\n    def ghost_to(self, source, target):\n        \"\"\"Replaces the source by the target and sets the opacity to 0.\n\n        If the provided target has no points, and thus a location of [0, 0, 0]\n        the source will simply fade out where it currently is.\n        \"\"\"\n        # mobject.replace() does not work if the target has no points.\n        if target.get_num_points() or target.submobjects:\n            source.replace(target, stretch=self.stretch, dim_to_match=self.dim_to_match)\n        source.set_opacity(0)\n\n    def get_all_mobjects(self) -> Sequence[Mobject]:\n        return [\n            self.mobject,\n            self.starting_mobject,\n            self.ending_mobject,\n        ]\n\n    def get_all_families_zipped(self):\n        return Animation.get_all_families_zipped(self)\n\n    def clean_up_from_scene(self, scene):\n        Animation.clean_up_from_scene(self, scene)\n        scene.remove(self.mobject)\n        self.mobject[0].restore()\n        scene.add(self.to_add_on_completion)\n\n\nclass FadeTransformPieces(FadeTransform):\n    \"\"\"Fades submobjects of one mobject into submobjects of another one.\n\n    See also\n    --------\n    :class:`~.FadeTransform`\n\n    Examples\n    --------\n    .. manim:: FadeTransformSubmobjects\n\n        class FadeTransformSubmobjects(Scene):\n            def construct(self):\n                src = VGroup(Square(), Circle().shift(LEFT + UP))\n                src.shift(3*LEFT + 2*UP)\n                src_copy = src.copy().shift(4*DOWN)\n\n                target = VGroup(Circle(), Triangle().shift(RIGHT + DOWN))\n                target.shift(3*RIGHT + 2*UP)\n                target_copy = target.copy().shift(4*DOWN)\n\n                self.play(FadeIn(src), FadeIn(src_copy))\n                self.play(\n                    FadeTransform(src, target),\n                    FadeTransformPieces(src_copy, target_copy)\n                )\n                self.play(*[FadeOut(mobj) for mobj in self.mobjects])\n\n    \"\"\"\n\n    def begin(self):\n        self.mobject[0].align_submobjects(self.mobject[1])\n        super().begin()\n\n    def ghost_to(self, source, target):\n        \"\"\"Replaces the source submobjects by the target submobjects and sets\n        the opacity to 0.\n        \"\"\"\n        for sm0, sm1 in zip(source.get_family(), target.get_family(), strict=True):\n            super().ghost_to(sm0, sm1)\n"
  },
  {
    "path": "manim/animation/transform_matching_parts.py",
    "content": "\"\"\"Animations that try to transform Mobjects while keeping track of identical parts.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"TransformMatchingShapes\", \"TransformMatchingTex\"]\n\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\n\nfrom manim.mobject.opengl.opengl_mobject import OpenGLGroup, OpenGLMobject\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVGroup, OpenGLVMobject\n\nfrom .._config import config\nfrom ..constants import RendererType\nfrom ..mobject.mobject import Group, Mobject\nfrom ..mobject.types.vectorized_mobject import VGroup, VMobject\nfrom .composition import AnimationGroup\nfrom .fading import FadeIn, FadeOut\nfrom .transform import FadeTransformPieces, Transform\n\nif TYPE_CHECKING:\n    from ..scene.scene import Scene\n\n\nclass TransformMatchingAbstractBase(AnimationGroup):\n    \"\"\"Abstract base class for transformations that keep track of matching parts.\n\n    Subclasses have to implement the two static methods\n    :meth:`~.TransformMatchingAbstractBase.get_mobject_parts` and\n    :meth:`~.TransformMatchingAbstractBase.get_mobject_key`.\n\n    Basically, this transformation first maps all submobjects returned\n    by the ``get_mobject_parts`` method to certain keys by applying the\n    ``get_mobject_key`` method. Then, submobjects with matching keys\n    are transformed into each other.\n\n    Parameters\n    ----------\n    mobject\n        The starting :class:`~.Mobject`.\n    target_mobject\n        The target :class:`~.Mobject`.\n    transform_mismatches\n        Controls whether submobjects without a matching key are transformed\n        into each other by using :class:`~.Transform`. Default: ``False``.\n    fade_transform_mismatches\n        Controls whether submobjects without a matching key are transformed\n        into each other by using :class:`~.FadeTransform`. Default: ``False``.\n    key_map\n        Optional. A dictionary mapping keys belonging to some of the starting mobject's\n        submobjects (i.e., the return values of the ``get_mobject_key`` method)\n        to some keys belonging to the target mobject's submobjects that should\n        be transformed although the keys don't match.\n    kwargs\n        All further keyword arguments are passed to the submobject transformations.\n\n\n    Note\n    ----\n    If neither ``transform_mismatches`` nor ``fade_transform_mismatches``\n    are set to ``True``, submobjects without matching keys in the starting\n    mobject are faded out in the direction of the unmatched submobjects in\n    the target mobject, and unmatched submobjects in the target mobject\n    are faded in from the direction of the unmatched submobjects in the\n    start mobject.\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        target_mobject: Mobject,\n        transform_mismatches: bool = False,\n        fade_transform_mismatches: bool = False,\n        key_map: dict | None = None,\n        **kwargs,\n    ):\n        if isinstance(mobject, OpenGLVMobject):\n            group_type = OpenGLVGroup\n        elif isinstance(mobject, OpenGLMobject):\n            group_type = OpenGLGroup\n        elif isinstance(mobject, VMobject):\n            group_type = VGroup\n        else:\n            group_type = Group\n\n        source_map = self.get_shape_map(mobject)\n        target_map = self.get_shape_map(target_mobject)\n\n        if key_map is None:\n            key_map = {}\n\n        # Create two mobjects whose submobjects all match each other\n        # according to whatever keys are used for source_map and\n        # target_map\n        transform_source = group_type()\n        transform_target = group_type()\n        for key in set(source_map).intersection(target_map):\n            transform_source.add(source_map[key])\n            transform_target.add(target_map[key])\n        anims = [Transform(transform_source, transform_target, **kwargs)]\n        # User can manually specify when one part should transform\n        # into another despite not matching by using key_map\n        key_mapped_source = group_type()\n        key_mapped_target = group_type()\n        for key1, key2 in key_map.items():\n            if key1 in source_map and key2 in target_map:\n                key_mapped_source.add(source_map[key1])\n                key_mapped_target.add(target_map[key2])\n                source_map.pop(key1, None)\n                target_map.pop(key2, None)\n        if len(key_mapped_source) > 0:\n            anims.append(\n                FadeTransformPieces(key_mapped_source, key_mapped_target, **kwargs),\n            )\n\n        fade_source = group_type()\n        fade_target = group_type()\n        for key in set(source_map).difference(target_map):\n            fade_source.add(source_map[key])\n        for key in set(target_map).difference(source_map):\n            fade_target.add(target_map[key])\n        fade_target_copy = fade_target.copy()\n\n        if transform_mismatches:\n            if \"replace_mobject_with_target_in_scene\" not in kwargs:\n                kwargs[\"replace_mobject_with_target_in_scene\"] = True\n            anims.append(Transform(fade_source, fade_target, **kwargs))\n        elif fade_transform_mismatches:\n            anims.append(FadeTransformPieces(fade_source, fade_target, **kwargs))\n        else:\n            anims.append(FadeOut(fade_source, target_position=fade_target, **kwargs))\n            anims.append(\n                FadeIn(fade_target_copy, target_position=fade_target, **kwargs),\n            )\n\n        super().__init__(*anims)\n\n        self.to_remove = [mobject, fade_target_copy]\n        self.to_add = target_mobject\n\n    def get_shape_map(self, mobject: Mobject) -> dict:\n        shape_map = {}\n        for sm in self.get_mobject_parts(mobject):\n            key = self.get_mobject_key(sm)\n            if key not in shape_map:\n                if config[\"renderer\"] == RendererType.OPENGL:\n                    shape_map[key] = OpenGLVGroup()\n                else:\n                    shape_map[key] = VGroup()\n            shape_map[key].add(sm)\n        return shape_map\n\n    def clean_up_from_scene(self, scene: Scene) -> None:\n        # Interpolate all animations back to 0 to ensure source mobjects remain unchanged.\n        for anim in self.animations:\n            anim.interpolate(0)\n        scene.remove(self.mobject)\n        scene.remove(*self.to_remove)\n        scene.add(self.to_add)\n\n    @staticmethod\n    def get_mobject_parts(mobject: Mobject):\n        raise NotImplementedError(\"To be implemented in subclass.\")\n\n    @staticmethod\n    def get_mobject_key(mobject: Mobject):\n        raise NotImplementedError(\"To be implemented in subclass.\")\n\n\nclass TransformMatchingShapes(TransformMatchingAbstractBase):\n    \"\"\"An animation trying to transform groups by matching the shape\n    of their submobjects.\n\n    Two submobjects match if the hash of their point coordinates after\n    normalization (i.e., after translation to the origin, fixing the submobject\n    height at 1 unit, and rounding the coordinates to three decimal places)\n    matches.\n\n    See also\n    --------\n    :class:`~.TransformMatchingAbstractBase`\n\n    Examples\n    --------\n\n    .. manim:: Anagram\n\n        class Anagram(Scene):\n            def construct(self):\n                src = Text(\"the morse code\")\n                tar = Text(\"here come dots\")\n                self.play(Write(src))\n                self.wait(0.5)\n                self.play(TransformMatchingShapes(src, tar, path_arc=PI/2))\n                self.wait(0.5)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        target_mobject: Mobject,\n        transform_mismatches: bool = False,\n        fade_transform_mismatches: bool = False,\n        key_map: dict | None = None,\n        **kwargs,\n    ):\n        super().__init__(\n            mobject,\n            target_mobject,\n            transform_mismatches=transform_mismatches,\n            fade_transform_mismatches=fade_transform_mismatches,\n            key_map=key_map,\n            **kwargs,\n        )\n\n    @staticmethod\n    def get_mobject_parts(mobject: Mobject) -> list[Mobject]:\n        return mobject.family_members_with_points()\n\n    @staticmethod\n    def get_mobject_key(mobject: Mobject) -> int:\n        mobject.save_state()\n        mobject.center()\n        mobject.set(height=1)\n        rounded_points = np.round(mobject.points, 3) + 0.0\n        result = hash(rounded_points.tobytes())\n        mobject.restore()\n        return result\n\n\nclass TransformMatchingTex(TransformMatchingAbstractBase):\n    \"\"\"A transformation trying to transform rendered LaTeX strings.\n\n    Two submobjects match if their ``tex_string`` matches.\n\n    See also\n    --------\n    :class:`~.TransformMatchingAbstractBase`\n\n    Examples\n    --------\n\n    .. manim:: MatchingEquationParts\n\n        class MatchingEquationParts(Scene):\n            def construct(self):\n                variables = VGroup(MathTex(\"a\"), MathTex(\"b\"), MathTex(\"c\")).arrange_submobjects().shift(UP)\n\n                eq1 = MathTex(\"{{x}}^2\", \"+\", \"{{y}}^2\", \"=\", \"{{z}}^2\")\n                eq2 = MathTex(\"{{a}}^2\", \"+\", \"{{b}}^2\", \"=\", \"{{c}}^2\")\n                eq3 = MathTex(\"{{a}}^2\", \"=\", \"{{c}}^2\", \"-\", \"{{b}}^2\")\n\n                self.add(eq1)\n                self.wait(0.5)\n                self.play(TransformMatchingTex(Group(eq1, variables), eq2))\n                self.wait(0.5)\n                self.play(TransformMatchingTex(eq2, eq3))\n                self.wait(0.5)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        target_mobject: Mobject,\n        transform_mismatches: bool = False,\n        fade_transform_mismatches: bool = False,\n        key_map: dict | None = None,\n        **kwargs,\n    ):\n        super().__init__(\n            mobject,\n            target_mobject,\n            transform_mismatches=transform_mismatches,\n            fade_transform_mismatches=fade_transform_mismatches,\n            key_map=key_map,\n            **kwargs,\n        )\n\n    @staticmethod\n    def get_mobject_parts(mobject: Mobject) -> list[Mobject]:\n        if isinstance(mobject, (Group, VGroup, OpenGLGroup, OpenGLVGroup)):\n            return [\n                p\n                for s in mobject.submobjects\n                for p in TransformMatchingTex.get_mobject_parts(s)\n            ]\n        else:\n            assert hasattr(mobject, \"tex_string\")\n            return mobject.submobjects\n\n    @staticmethod\n    def get_mobject_key(mobject: Mobject) -> str:\n        return mobject.tex_string\n"
  },
  {
    "path": "manim/animation/updaters/__init__.py",
    "content": "\"\"\"Animations and utility mobjects related to update functions.\n\nModules\n=======\n\n.. autosummary::\n    :toctree: ../reference\n\n    ~mobject_update_utils\n    ~update\n\"\"\"\n"
  },
  {
    "path": "manim/animation/updaters/mobject_update_utils.py",
    "content": "\"\"\"Utility functions for continuous animation of mobjects.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"assert_is_mobject_method\",\n    \"always\",\n    \"f_always\",\n    \"always_redraw\",\n    \"always_shift\",\n    \"always_rotate\",\n    \"turn_animation_into_updater\",\n    \"cycle_animation\",\n]\n\n\nimport inspect\nfrom collections.abc import Callable\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\n\nfrom manim.constants import DEGREES, RIGHT\nfrom manim.mobject.mobject import Mobject\nfrom manim.opengl import OpenGLMobject\nfrom manim.utils.space_ops import normalize\n\nif TYPE_CHECKING:\n    from manim.animation.animation import Animation\n\n\ndef assert_is_mobject_method(method: Callable) -> None:\n    assert inspect.ismethod(method)\n    mobject = method.__self__\n    assert isinstance(mobject, (Mobject, OpenGLMobject))\n\n\ndef always(method: Callable, *args, **kwargs) -> Mobject:\n    assert_is_mobject_method(method)\n    mobject = method.__self__\n    func = method.__func__\n    mobject.add_updater(lambda m: func(m, *args, **kwargs))\n    return mobject\n\n\ndef f_always(method: Callable[[Mobject], None], *arg_generators, **kwargs) -> Mobject:\n    \"\"\"\n    More functional version of always, where instead\n    of taking in args, it takes in functions which output\n    the relevant arguments.\n    \"\"\"\n    assert_is_mobject_method(method)\n    mobject = method.__self__\n    func = method.__func__\n\n    def updater(mob):\n        args = [arg_generator() for arg_generator in arg_generators]\n        func(mob, *args, **kwargs)\n\n    mobject.add_updater(updater)\n    return mobject\n\n\ndef always_redraw(func: Callable[[], Mobject]) -> Mobject:\n    \"\"\"Redraw the mobject constructed by a function every frame.\n\n    This function returns a mobject with an attached updater that\n    continuously regenerates the mobject according to the\n    specified function.\n\n    Parameters\n    ----------\n    func\n        A function without (required) input arguments that returns\n        a mobject.\n\n    Examples\n    --------\n\n    .. manim:: TangentAnimation\n\n        class TangentAnimation(Scene):\n            def construct(self):\n                ax = Axes()\n                sine = ax.plot(np.sin, color=RED)\n                alpha = ValueTracker(0)\n                point = always_redraw(\n                    lambda: Dot(\n                        sine.point_from_proportion(alpha.get_value()),\n                        color=BLUE\n                    )\n                )\n                tangent = always_redraw(\n                    lambda: TangentLine(\n                        sine,\n                        alpha=alpha.get_value(),\n                        color=YELLOW,\n                        length=4\n                    )\n                )\n                self.add(ax, sine, point, tangent)\n                self.play(alpha.animate.set_value(1), rate_func=linear, run_time=2)\n    \"\"\"\n    mob = func()\n    mob.add_updater(lambda _: mob.become(func()))\n    return mob\n\n\ndef always_shift(\n    mobject: Mobject, direction: np.ndarray[np.float64] = RIGHT, rate: float = 0.1\n) -> Mobject:\n    \"\"\"A mobject which is continuously shifted along some direction\n    at a certain rate.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to shift.\n    direction\n        The direction to shift. The vector is normalized, the specified magnitude\n        is not relevant.\n    rate\n        Length in Manim units which the mobject travels in one\n        second along the specified direction.\n\n    Examples\n    --------\n\n    .. manim:: ShiftingSquare\n\n        class ShiftingSquare(Scene):\n            def construct(self):\n                sq = Square().set_fill(opacity=1)\n                tri = Triangle()\n                VGroup(sq, tri).arrange(LEFT)\n\n                # construct a square which is continuously\n                # shifted to the right\n                always_shift(sq, RIGHT, rate=5)\n\n                self.add(sq)\n                self.play(tri.animate.set_fill(opacity=1))\n    \"\"\"\n    mobject.add_updater(lambda m, dt: m.shift(dt * rate * normalize(direction)))\n    return mobject\n\n\ndef always_rotate(mobject: Mobject, rate: float = 20 * DEGREES, **kwargs) -> Mobject:\n    \"\"\"A mobject which is continuously rotated at a certain rate.\n\n    Parameters\n    ----------\n    mobject\n        The mobject to be rotated.\n    rate\n        The angle which the mobject is rotated by\n        over one second.\n    kwags\n        Further arguments to be passed to :meth:`.Mobject.rotate`.\n\n    Examples\n    --------\n\n    .. manim:: SpinningTriangle\n\n        class SpinningTriangle(Scene):\n            def construct(self):\n                tri = Triangle().set_fill(opacity=1).set_z_index(2)\n                sq = Square().to_edge(LEFT)\n\n                # will keep spinning while there is an animation going on\n                always_rotate(tri, rate=2*PI, about_point=ORIGIN)\n\n                self.add(tri, sq)\n                self.play(sq.animate.to_edge(RIGHT), rate_func=linear, run_time=1)\n    \"\"\"\n    mobject.add_updater(lambda m, dt: m.rotate(dt * rate, **kwargs))\n    return mobject\n\n\ndef turn_animation_into_updater(\n    animation: Animation, cycle: bool = False, delay: float = 0, **kwargs\n) -> Mobject:\n    \"\"\"\n    Add an updater to the animation's mobject which applies\n    the interpolation and update functions of the animation\n\n    If cycle is True, this repeats over and over.  Otherwise,\n    the updater will be popped upon completion\n\n    The ``delay`` parameter is the delay (in seconds) before the animation starts..\n\n    Examples\n    --------\n\n    .. manim:: WelcomeToManim\n\n        class WelcomeToManim(Scene):\n            def construct(self):\n                words = Text(\"Welcome to\")\n                banner = ManimBanner().scale(0.5)\n                VGroup(words, banner).arrange(DOWN)\n\n                turn_animation_into_updater(Write(words, run_time=0.9))\n                self.add(words)\n                self.wait(0.5)\n                self.play(banner.expand(), run_time=0.5)\n    \"\"\"\n    mobject = animation.mobject\n    animation.suspend_mobject_updating = False\n    animation.begin()\n    animation.total_time = -delay\n\n    def update(m: Mobject, dt: float):\n        if animation.total_time >= 0:\n            run_time = animation.get_run_time()\n\n            # handle zero/negative runtime safely\n            if run_time <= 0:\n                # instantly snap to final state once, then remove updater\n                animation.interpolate(1)\n                animation.update_mobjects(dt)\n                animation.finish()\n                m.remove_updater(update)\n                return\n\n            time_ratio = animation.total_time / run_time\n            if cycle:\n                alpha = time_ratio % 1\n            else:\n                alpha = np.clip(time_ratio, 0, 1)\n                if alpha >= 1:\n                    animation.finish()\n                    m.remove_updater(update)\n                    return\n            animation.interpolate(alpha)\n            animation.update_mobjects(dt)\n        animation.total_time += dt\n\n    mobject.add_updater(update)\n    return mobject\n\n\ndef cycle_animation(animation: Animation, **kwargs) -> Mobject:\n    return turn_animation_into_updater(animation, cycle=True, **kwargs)\n"
  },
  {
    "path": "manim/animation/updaters/update.py",
    "content": "\"\"\"Animations that update mobjects.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"UpdateFromFunc\", \"UpdateFromAlphaFunc\", \"MaintainPositionRelativeTo\"]\n\n\nimport operator as op\nfrom collections.abc import Callable\nfrom typing import TYPE_CHECKING, Any\n\nfrom manim.animation.animation import Animation\n\nif TYPE_CHECKING:\n    from manim.mobject.mobject import Mobject\n\n\nclass UpdateFromFunc(Animation):\n    \"\"\"\n    update_function of the form func(mobject), presumably\n    to be used when the state of one mobject is dependent\n    on another simultaneously animated mobject\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        update_function: Callable[[Mobject], Any],\n        suspend_mobject_updating: bool = False,\n        **kwargs: Any,\n    ) -> None:\n        self.update_function = update_function\n        super().__init__(\n            mobject, suspend_mobject_updating=suspend_mobject_updating, **kwargs\n        )\n\n    def interpolate_mobject(self, alpha: float) -> None:\n        self.update_function(self.mobject)  # type: ignore[arg-type]\n\n\nclass UpdateFromAlphaFunc(UpdateFromFunc):\n    def interpolate_mobject(self, alpha: float) -> None:\n        self.update_function(self.mobject, self.rate_func(alpha))  # type: ignore[call-arg, arg-type]\n\n\nclass MaintainPositionRelativeTo(Animation):\n    def __init__(\n        self, mobject: Mobject, tracked_mobject: Mobject, **kwargs: Any\n    ) -> None:\n        self.tracked_mobject = tracked_mobject\n        self.diff = op.sub(\n            mobject.get_center(),\n            tracked_mobject.get_center(),\n        )\n        super().__init__(mobject, **kwargs)\n\n    def interpolate_mobject(self, alpha: float) -> None:\n        target = self.tracked_mobject.get_center()\n        location = self.mobject.get_center()\n        self.mobject.shift(target - location + self.diff)\n"
  },
  {
    "path": "manim/camera/__init__.py",
    "content": ""
  },
  {
    "path": "manim/camera/camera.py",
    "content": "\"\"\"A camera converts the mobjects contained in a Scene into an array of pixels.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"Camera\", \"BackgroundColoredVMobjectDisplayer\"]\n\nimport copy\nimport itertools as it\nimport operator as op\nimport pathlib\nfrom collections.abc import Callable, Iterable\nfrom functools import reduce\nfrom typing import TYPE_CHECKING, Any, Self\n\nimport cairo\nimport numpy as np\nfrom PIL import Image\n\nfrom manim._config import config, logger\nfrom manim.constants import *\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.types.point_cloud_mobject import PMobject\nfrom manim.mobject.types.vectorized_mobject import VMobject\nfrom manim.utils.color import ManimColor, ParsableManimColor, color_to_int_rgba\nfrom manim.utils.family import extract_mobject_family_members\nfrom manim.utils.images import get_full_raster_image_path\nfrom manim.utils.iterables import list_difference_update\nfrom manim.utils.space_ops import cross2d\n\nif TYPE_CHECKING:\n    import numpy.typing as npt\n\n    from manim.mobject.types.image_mobject import AbstractImageMobject\n    from manim.typing import (\n        FloatRGBA_Array,\n        FloatRGBALike_Array,\n        ManimFloat,\n        ManimInt,\n        PixelArray,\n        Point3D,\n        Point3D_Array,\n    )\n\n\nLINE_JOIN_MAP = {\n    LineJointType.AUTO: None,  # TODO: this could be improved\n    LineJointType.ROUND: cairo.LineJoin.ROUND,\n    LineJointType.BEVEL: cairo.LineJoin.BEVEL,\n    LineJointType.MITER: cairo.LineJoin.MITER,\n}\n\n\nCAP_STYLE_MAP = {\n    CapStyleType.AUTO: None,  # TODO: this could be improved\n    CapStyleType.ROUND: cairo.LineCap.ROUND,\n    CapStyleType.BUTT: cairo.LineCap.BUTT,\n    CapStyleType.SQUARE: cairo.LineCap.SQUARE,\n}\n\n\nclass Camera:\n    \"\"\"Base camera class.\n\n    This is the object which takes care of what exactly is displayed\n    on screen at any given moment.\n\n    Parameters\n    ----------\n    background_image\n        The path to an image that should be the background image.\n        If not set, the background is filled with :attr:`self.background_color`\n    background\n        What :attr:`background` is set to. By default, ``None``.\n    pixel_height\n        The height of the scene in pixels.\n    pixel_width\n        The width of the scene in pixels.\n    kwargs\n        Additional arguments (``background_color``, ``background_opacity``)\n        to be set.\n    \"\"\"\n\n    def __init__(\n        self,\n        background_image: str | None = None,\n        frame_center: Point3D = ORIGIN,\n        image_mode: str = \"RGBA\",\n        n_channels: int = 4,\n        pixel_array_dtype: str = \"uint8\",\n        cairo_line_width_multiple: float = 0.01,\n        use_z_index: bool = True,\n        background: PixelArray | None = None,\n        pixel_height: int | None = None,\n        pixel_width: int | None = None,\n        frame_height: float | None = None,\n        frame_width: float | None = None,\n        frame_rate: float | None = None,\n        background_color: ParsableManimColor | None = None,\n        background_opacity: float | None = None,\n        **kwargs: Any,\n    ) -> None:\n        self.background_image = background_image\n        self.frame_center = frame_center\n        self.image_mode = image_mode\n        self.n_channels = n_channels\n        self.pixel_array_dtype = pixel_array_dtype\n        self.cairo_line_width_multiple = cairo_line_width_multiple\n        self.use_z_index = use_z_index\n        self.background = background\n        self.background_colored_vmobject_displayer: (\n            BackgroundColoredVMobjectDisplayer | None\n        ) = None\n\n        if pixel_height is None:\n            pixel_height = config[\"pixel_height\"]\n        self.pixel_height = pixel_height\n\n        if pixel_width is None:\n            pixel_width = config[\"pixel_width\"]\n        self.pixel_width = pixel_width\n\n        if frame_height is None:\n            frame_height = config[\"frame_height\"]\n        self.frame_height = frame_height\n\n        if frame_width is None:\n            frame_width = config[\"frame_width\"]\n        self.frame_width = frame_width\n\n        if frame_rate is None:\n            frame_rate = config[\"frame_rate\"]\n        self.frame_rate = frame_rate\n\n        if background_color is None:\n            self._background_color: ManimColor = ManimColor.parse(\n                config[\"background_color\"]\n            )\n        else:\n            self._background_color = ManimColor.parse(background_color)\n        if background_opacity is None:\n            self._background_opacity: float = config[\"background_opacity\"]\n        else:\n            self._background_opacity = background_opacity\n\n        # This one is in the same boat as the above, but it doesn't have the\n        # same name as the corresponding key so it has to be handled on its own\n        self.max_allowable_norm = config[\"frame_width\"]\n\n        self.rgb_max_val = np.iinfo(self.pixel_array_dtype).max\n        self.pixel_array_to_cairo_context: dict[int, cairo.Context] = {}\n\n        # Contains the correct method to process a list of Mobjects of the\n        # corresponding class.  If a Mobject is not an instance of a class in\n        # this dict (or an instance of a class that inherits from a class in\n        # this dict), then it cannot be rendered.\n\n        self.init_background()\n        self.resize_frame_shape()\n        self.reset()\n\n    def __deepcopy__(self, memo: Any) -> Camera:\n        # This is to address a strange bug where deepcopying\n        # will result in a segfault, which is somehow related\n        # to the aggdraw library\n        self.canvas = None\n        return copy.copy(self)\n\n    @property\n    def background_color(self) -> ManimColor:\n        return self._background_color\n\n    @background_color.setter\n    def background_color(self, color: ManimColor) -> None:\n        self._background_color = color\n        self.init_background()\n\n    @property\n    def background_opacity(self) -> float:\n        return self._background_opacity\n\n    @background_opacity.setter\n    def background_opacity(self, alpha: float) -> None:\n        self._background_opacity = alpha\n        self.init_background()\n\n    def type_or_raise(\n        self, mobject: Mobject\n    ) -> type[VMobject] | type[PMobject] | type[AbstractImageMobject] | type[Mobject]:\n        \"\"\"Return the type of mobject, if it is a type that can be rendered.\n\n        If `mobject` is an instance of a class that inherits from a class that\n        can be rendered, return the super class.  For example, an instance of a\n        Square is also an instance of VMobject, and these can be rendered.\n        Therefore, `type_or_raise(Square())` returns True.\n\n        Parameters\n        ----------\n        mobject\n            The object to take the type of.\n\n        Notes\n        -----\n        For a list of classes that can currently be rendered, see :meth:`display_funcs`.\n\n        Returns\n        -------\n        Type[:class:`~.Mobject`]\n            The type of mobjects, if it can be rendered.\n\n        Raises\n        ------\n        :exc:`TypeError`\n            When mobject is not an instance of a class that can be rendered.\n        \"\"\"\n        from ..mobject.types.image_mobject import AbstractImageMobject\n\n        self.display_funcs: dict[\n            type[Mobject], Callable[[list[Mobject], PixelArray], Any]\n        ] = {\n            VMobject: self.display_multiple_vectorized_mobjects,  # type: ignore[dict-item]\n            PMobject: self.display_multiple_point_cloud_mobjects,  # type: ignore[dict-item]\n            AbstractImageMobject: self.display_multiple_image_mobjects,  # type: ignore[dict-item]\n            Mobject: lambda batch, pa: batch,  # Do nothing\n        }\n        # We have to check each type in turn because we are dealing with\n        # super classes.  For example, if square = Square(), then\n        # type(square) != VMobject, but isinstance(square, VMobject) == True.\n        for _type in self.display_funcs:\n            if isinstance(mobject, _type):\n                return _type\n        raise TypeError(f\"Displaying an object of class {_type} is not supported\")\n\n    def reset_pixel_shape(self, new_height: float, new_width: float) -> None:\n        \"\"\"This method resets the height and width\n        of a single pixel to the passed new_height and new_width.\n\n        Parameters\n        ----------\n        new_height\n            The new height of the entire scene in pixels\n        new_width\n            The new width of the entire scene in pixels\n        \"\"\"\n        self.pixel_width = new_width\n        self.pixel_height = new_height\n        self.init_background()\n        self.resize_frame_shape()\n        self.reset()\n\n    def resize_frame_shape(self, fixed_dimension: int = 0) -> None:\n        \"\"\"\n        Changes frame_shape to match the aspect ratio\n        of the pixels, where fixed_dimension determines\n        whether frame_height or frame_width\n        remains fixed while the other changes accordingly.\n\n        Parameters\n        ----------\n        fixed_dimension\n            If 0, height is scaled with respect to width\n            else, width is scaled with respect to height.\n        \"\"\"\n        pixel_height = self.pixel_height\n        pixel_width = self.pixel_width\n        frame_height = self.frame_height\n        frame_width = self.frame_width\n        aspect_ratio = pixel_width / pixel_height\n        if fixed_dimension == 0:\n            frame_height = frame_width / aspect_ratio\n        else:\n            frame_width = aspect_ratio * frame_height\n        self.frame_height = frame_height\n        self.frame_width = frame_width\n\n    def init_background(self) -> None:\n        \"\"\"Initialize the background.\n        If self.background_image is the path of an image\n        the image is set as background; else, the default\n        background color fills the background.\n        \"\"\"\n        height = self.pixel_height\n        width = self.pixel_width\n        if self.background_image is not None:\n            path = get_full_raster_image_path(self.background_image)\n            image = Image.open(path).convert(self.image_mode)\n            # TODO, how to gracefully handle backgrounds\n            # with different sizes?\n            self.background = np.array(image)[:height, :width]\n            self.background = self.background.astype(self.pixel_array_dtype)\n        else:\n            background_rgba = color_to_int_rgba(\n                self.background_color,\n                self.background_opacity,\n            )\n            self.background = np.zeros(\n                (height, width, self.n_channels),\n                dtype=self.pixel_array_dtype,\n            )\n            self.background[:, :] = background_rgba\n\n    def get_image(\n        self, pixel_array: PixelArray | list | tuple | None = None\n    ) -> Image.Image:\n        \"\"\"Returns an image from the passed\n        pixel array, or from the current frame\n        if the passed pixel array is none.\n\n        Parameters\n        ----------\n        pixel_array\n            The pixel array from which to get an image, by default None\n\n        Returns\n        -------\n        PIL.Image.Image\n            The PIL image of the array.\n        \"\"\"\n        if pixel_array is None:\n            pixel_array = self.pixel_array\n        return Image.fromarray(pixel_array, mode=self.image_mode)\n\n    def convert_pixel_array(\n        self, pixel_array: PixelArray | list | tuple, convert_from_floats: bool = False\n    ) -> PixelArray:\n        \"\"\"Converts a pixel array from values that have floats in then\n        to proper RGB values.\n\n        Parameters\n        ----------\n        pixel_array\n            Pixel array to convert.\n        convert_from_floats\n            Whether or not to convert float values to ints, by default False\n\n        Returns\n        -------\n        np.array\n            The new, converted pixel array.\n        \"\"\"\n        retval = np.array(pixel_array)\n        if convert_from_floats:\n            retval = np.apply_along_axis(\n                lambda f: (f * self.rgb_max_val).astype(self.pixel_array_dtype),\n                2,\n                retval,\n            )\n        return retval\n\n    def set_pixel_array(\n        self, pixel_array: PixelArray | list | tuple, convert_from_floats: bool = False\n    ) -> None:\n        \"\"\"Sets the pixel array of the camera to the passed pixel array.\n\n        Parameters\n        ----------\n        pixel_array\n            The pixel array to convert and then set as the camera's pixel array.\n        convert_from_floats\n            Whether or not to convert float values to proper RGB values, by default False\n        \"\"\"\n        converted_array: PixelArray = self.convert_pixel_array(\n            pixel_array, convert_from_floats\n        )\n        if not (\n            hasattr(self, \"pixel_array\")\n            and self.pixel_array.shape == converted_array.shape\n        ):\n            self.pixel_array: PixelArray = converted_array\n        else:\n            # Set in place\n            self.pixel_array[:, :, :] = converted_array[:, :, :]\n\n    def set_background(\n        self, pixel_array: PixelArray | list | tuple, convert_from_floats: bool = False\n    ) -> None:\n        \"\"\"Sets the background to the passed pixel_array after converting\n        to valid RGB values.\n\n        Parameters\n        ----------\n        pixel_array\n            The pixel array to set the background to.\n        convert_from_floats\n            Whether or not to convert floats values to proper RGB valid ones, by default False\n        \"\"\"\n        self.background = self.convert_pixel_array(pixel_array, convert_from_floats)\n\n    # TODO, this should live in utils, not as a method of Camera\n    def make_background_from_func(\n        self, coords_to_colors_func: Callable[[np.ndarray], np.ndarray]\n    ) -> PixelArray:\n        \"\"\"\n        Makes a pixel array for the background by using coords_to_colors_func to determine each pixel's color. Each input\n        pixel's color. Each input to coords_to_colors_func is an (x, y) pair in space (in ordinary space coordinates; not\n        pixel coordinates), and each output is expected to be an RGBA array of 4 floats.\n\n        Parameters\n        ----------\n        coords_to_colors_func\n            The function whose input is an (x,y) pair of coordinates and\n            whose return values must be the colors for that point\n\n        Returns\n        -------\n        np.array\n            The pixel array which can then be passed to set_background.\n        \"\"\"\n        logger.info(\"Starting set_background\")\n        coords = self.get_coords_of_all_pixels()\n        new_background = np.apply_along_axis(coords_to_colors_func, 2, coords)\n        logger.info(\"Ending set_background\")\n\n        return self.convert_pixel_array(new_background, convert_from_floats=True)\n\n    def set_background_from_func(\n        self, coords_to_colors_func: Callable[[np.ndarray], np.ndarray]\n    ) -> None:\n        \"\"\"\n        Sets the background to a pixel array using coords_to_colors_func to determine each pixel's color. Each input\n        pixel's color. Each input to coords_to_colors_func is an (x, y) pair in space (in ordinary space coordinates; not\n        pixel coordinates), and each output is expected to be an RGBA array of 4 floats.\n\n        Parameters\n        ----------\n        coords_to_colors_func\n            The function whose input is an (x,y) pair of coordinates and\n            whose return values must be the colors for that point\n        \"\"\"\n        self.set_background(self.make_background_from_func(coords_to_colors_func))\n\n    def reset(self) -> Self:\n        \"\"\"Resets the camera's pixel array\n        to that of the background\n\n        Returns\n        -------\n        Camera\n            The camera object after setting the pixel array.\n        \"\"\"\n        self.set_pixel_array(self.background)\n        return self\n\n    def set_frame_to_background(self, background: PixelArray) -> None:\n        self.set_pixel_array(background)\n\n    ####\n\n    def get_mobjects_to_display(\n        self,\n        mobjects: Iterable[Mobject],\n        include_submobjects: bool = True,\n        excluded_mobjects: list | None = None,\n    ) -> list[Mobject]:\n        \"\"\"Used to get the list of mobjects to display\n        with the camera.\n\n        Parameters\n        ----------\n        mobjects\n            The Mobjects\n        include_submobjects\n            Whether or not to include the submobjects of mobjects, by default True\n        excluded_mobjects\n            Any mobjects to exclude, by default None\n\n        Returns\n        -------\n        list\n            list of mobjects\n        \"\"\"\n        if include_submobjects:\n            mobjects = extract_mobject_family_members(\n                mobjects,\n                use_z_index=self.use_z_index,\n                only_those_with_points=True,\n            )\n            if excluded_mobjects:\n                all_excluded = extract_mobject_family_members(\n                    excluded_mobjects,\n                    use_z_index=self.use_z_index,\n                )\n                mobjects = list_difference_update(mobjects, all_excluded)\n        return list(mobjects)\n\n    def is_in_frame(self, mobject: Mobject) -> bool:\n        \"\"\"Checks whether the passed mobject is in\n        frame or not.\n\n        Parameters\n        ----------\n        mobject\n            The mobject for which the checking needs to be done.\n\n        Returns\n        -------\n        bool\n            True if in frame, False otherwise.\n        \"\"\"\n        fc = self.frame_center\n        fh = self.frame_height\n        fw = self.frame_width\n        return not reduce(\n            op.or_,\n            [\n                mobject.get_right()[0] < fc[0] - fw / 2,\n                mobject.get_bottom()[1] > fc[1] + fh / 2,\n                mobject.get_left()[0] > fc[0] + fw / 2,\n                mobject.get_top()[1] < fc[1] - fh / 2,\n            ],\n        )\n\n    def capture_mobject(self, mobject: Mobject, **kwargs: Any) -> None:\n        \"\"\"Capture mobjects by storing it in :attr:`pixel_array`.\n\n        This is a single-mobject version of :meth:`capture_mobjects`.\n\n        Parameters\n        ----------\n        mobject\n            Mobject to capture.\n\n        kwargs\n            Keyword arguments to be passed to :meth:`get_mobjects_to_display`.\n\n        \"\"\"\n        return self.capture_mobjects([mobject], **kwargs)\n\n    def capture_mobjects(self, mobjects: Iterable[Mobject], **kwargs: Any) -> None:\n        \"\"\"Capture mobjects by printing them on :attr:`pixel_array`.\n\n        This is the essential function that converts the contents of a Scene\n        into an array, which is then converted to an image or video.\n\n        Parameters\n        ----------\n        mobjects\n            Mobjects to capture.\n\n        kwargs\n            Keyword arguments to be passed to :meth:`get_mobjects_to_display`.\n\n        Notes\n        -----\n        For a list of classes that can currently be rendered, see :meth:`display_funcs`.\n\n        \"\"\"\n        # The mobjects will be processed in batches (or runs) of mobjects of\n        # the same type.  That is, if the list mobjects contains objects of\n        # types [VMobject, VMobject, VMobject, PMobject, PMobject, VMobject],\n        # then they will be captured in three batches: [VMobject, VMobject,\n        # VMobject], [PMobject, PMobject], and [VMobject].  This must be done\n        # without altering their order.  it.groupby computes exactly this\n        # partition while at the same time preserving order.\n        mobjects = self.get_mobjects_to_display(mobjects, **kwargs)\n        for group_type, group in it.groupby(mobjects, self.type_or_raise):\n            self.display_funcs[group_type](list(group), self.pixel_array)\n\n    # Methods associated with svg rendering\n\n    # NOTE: None of the methods below have been mentioned outside of their definitions. Their DocStrings are not as\n    # detailed as possible.\n\n    def get_cached_cairo_context(self, pixel_array: PixelArray) -> cairo.Context | None:\n        \"\"\"Returns the cached cairo context of the passed\n        pixel array if it exists, and None if it doesn't.\n\n        Parameters\n        ----------\n        pixel_array\n            The pixel array to check.\n\n        Returns\n        -------\n        cairo.Context\n            The cached cairo context.\n        \"\"\"\n        return self.pixel_array_to_cairo_context.get(id(pixel_array), None)\n\n    def cache_cairo_context(self, pixel_array: PixelArray, ctx: cairo.Context) -> None:\n        \"\"\"Caches the passed Pixel array into a Cairo Context\n\n        Parameters\n        ----------\n        pixel_array\n            The pixel array to cache\n        ctx\n            The context to cache it into.\n        \"\"\"\n        self.pixel_array_to_cairo_context[id(pixel_array)] = ctx\n\n    def get_cairo_context(self, pixel_array: PixelArray) -> cairo.Context:\n        \"\"\"Returns the cairo context for a pixel array after\n        caching it to self.pixel_array_to_cairo_context\n        If that array has already been cached, it returns the\n        cached version instead.\n\n        Parameters\n        ----------\n        pixel_array\n            The Pixel array to get the cairo context of.\n\n        Returns\n        -------\n        cairo.Context\n            The cairo context of the pixel array.\n        \"\"\"\n        cached_ctx = self.get_cached_cairo_context(pixel_array)\n        if cached_ctx:\n            return cached_ctx\n        pw = self.pixel_width\n        ph = self.pixel_height\n        fw = self.frame_width\n        fh = self.frame_height\n        fc = self.frame_center\n        surface = cairo.ImageSurface.create_for_data(\n            pixel_array.data,\n            cairo.FORMAT_ARGB32,\n            pw,\n            ph,\n        )\n        ctx = cairo.Context(surface)\n        ctx.scale(pw, ph)\n        ctx.set_matrix(\n            cairo.Matrix(\n                (pw / fw),\n                0,\n                0,\n                -(ph / fh),\n                (pw / 2) - fc[0] * (pw / fw),\n                (ph / 2) + fc[1] * (ph / fh),\n            ),\n        )\n        self.cache_cairo_context(pixel_array, ctx)\n        return ctx\n\n    def display_multiple_vectorized_mobjects(\n        self, vmobjects: list[VMobject], pixel_array: PixelArray\n    ) -> None:\n        \"\"\"Displays multiple VMobjects in the pixel_array\n\n        Parameters\n        ----------\n        vmobjects\n            list of VMobjects to display\n        pixel_array\n            The pixel array\n        \"\"\"\n        if len(vmobjects) == 0:\n            return\n        batch_image_pairs = it.groupby(vmobjects, lambda vm: vm.get_background_image())\n        for image, batch in batch_image_pairs:\n            if image:\n                self.display_multiple_background_colored_vmobjects(batch, pixel_array)\n            else:\n                self.display_multiple_non_background_colored_vmobjects(\n                    batch,\n                    pixel_array,\n                )\n\n    def display_multiple_non_background_colored_vmobjects(\n        self, vmobjects: Iterable[VMobject], pixel_array: PixelArray\n    ) -> None:\n        \"\"\"Displays multiple VMobjects in the cairo context, as long as they don't have\n        background colors.\n\n        Parameters\n        ----------\n        vmobjects\n            list of the VMobjects\n        pixel_array\n            The Pixel array to add the VMobjects to.\n        \"\"\"\n        ctx = self.get_cairo_context(pixel_array)\n        for vmobject in vmobjects:\n            self.display_vectorized(vmobject, ctx)\n\n    def display_vectorized(self, vmobject: VMobject, ctx: cairo.Context) -> Self:\n        \"\"\"Displays a VMobject in the cairo context\n\n        Parameters\n        ----------\n        vmobject\n            The Vectorized Mobject to display\n        ctx\n            The cairo context to use.\n\n        Returns\n        -------\n        Camera\n            The camera object\n        \"\"\"\n        self.set_cairo_context_path(ctx, vmobject)\n        self.apply_stroke(ctx, vmobject, background=True)\n        self.apply_fill(ctx, vmobject)\n        self.apply_stroke(ctx, vmobject)\n        return self\n\n    def set_cairo_context_path(self, ctx: cairo.Context, vmobject: VMobject) -> Self:\n        \"\"\"Sets a path for the cairo context with the vmobject passed\n\n        Parameters\n        ----------\n        ctx\n            The cairo context\n        vmobject\n            The VMobject\n\n        Returns\n        -------\n        Camera\n            Camera object after setting cairo_context_path\n        \"\"\"\n        points = self.transform_points_pre_display(vmobject, vmobject.points)\n        # TODO, shouldn't this be handled in transform_points_pre_display?\n        # points = points - self.get_frame_center()\n        if len(points) == 0:\n            return self\n\n        ctx.new_path()\n        subpaths = vmobject.gen_subpaths_from_points_2d(points)\n        for subpath in subpaths:\n            quads = vmobject.gen_cubic_bezier_tuples_from_points(subpath)\n            ctx.new_sub_path()\n            start = subpath[0]\n            ctx.move_to(*start[:2])\n            for _p0, p1, p2, p3 in quads:\n                ctx.curve_to(*p1[:2], *p2[:2], *p3[:2])\n            if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]):\n                ctx.close_path()\n        return self\n\n    def set_cairo_context_color(\n        self, ctx: cairo.Context, rgbas: FloatRGBALike_Array, vmobject: VMobject\n    ) -> Self:\n        \"\"\"Sets the color of the cairo context\n\n        Parameters\n        ----------\n        ctx\n            The cairo context\n        rgbas\n            The RGBA array with which to color the context.\n        vmobject\n            The VMobject with which to set the color.\n\n        Returns\n        -------\n        Camera\n            The camera object\n        \"\"\"\n        if len(rgbas) == 1:\n            # Use reversed rgb because cairo surface is\n            # encodes it in reverse order\n            ctx.set_source_rgba(*rgbas[0][2::-1], rgbas[0][3])\n        else:\n            points = vmobject.get_gradient_start_and_end_points()\n            points = self.transform_points_pre_display(vmobject, points)\n            pat = cairo.LinearGradient(*it.chain(*(point[:2] for point in points)))\n            offsets = np.linspace(0, 1, len(rgbas))\n            for rgba, offset in zip(rgbas, offsets, strict=True):\n                pat.add_color_stop_rgba(offset, *rgba[2::-1], rgba[3])\n            ctx.set_source(pat)\n        return self\n\n    def apply_fill(self, ctx: cairo.Context, vmobject: VMobject) -> Self:\n        \"\"\"Fills the cairo context\n\n        Parameters\n        ----------\n        ctx\n            The cairo context\n        vmobject\n            The VMobject\n\n        Returns\n        -------\n        Camera\n            The camera object.\n        \"\"\"\n        self.set_cairo_context_color(ctx, self.get_fill_rgbas(vmobject), vmobject)\n        ctx.fill_preserve()\n        return self\n\n    def apply_stroke(\n        self, ctx: cairo.Context, vmobject: VMobject, background: bool = False\n    ) -> Self:\n        \"\"\"Applies a stroke to the VMobject in the cairo context.\n\n        Parameters\n        ----------\n        ctx\n            The cairo context\n        vmobject\n            The VMobject\n        background\n            Whether or not to consider the background when applying this\n            stroke width, by default False\n\n        Returns\n        -------\n        Camera\n            The camera object with the stroke applied.\n        \"\"\"\n        width = vmobject.get_stroke_width(background)\n        if width == 0:\n            return self\n        self.set_cairo_context_color(\n            ctx,\n            self.get_stroke_rgbas(vmobject, background=background),\n            vmobject,\n        )\n        ctx.set_line_width(\n            width\n            * self.cairo_line_width_multiple\n            * (self.frame_width / self.frame_width),\n            # This ensures lines have constant width as you zoom in on them.\n        )\n        if vmobject.joint_type != LineJointType.AUTO:\n            ctx.set_line_join(LINE_JOIN_MAP[vmobject.joint_type])\n        if vmobject.cap_style != CapStyleType.AUTO:\n            ctx.set_line_cap(CAP_STYLE_MAP[vmobject.cap_style])\n        ctx.stroke_preserve()\n        return self\n\n    def get_stroke_rgbas(\n        self, vmobject: VMobject, background: bool = False\n    ) -> FloatRGBA_Array:\n        \"\"\"Gets the RGBA array for the stroke of the passed\n        VMobject.\n\n        Parameters\n        ----------\n        vmobject\n            The VMobject\n        background\n            Whether or not to consider the background when getting the stroke\n            RGBAs, by default False\n\n        Returns\n        -------\n        np.ndarray\n            The RGBA array of the stroke.\n        \"\"\"\n        return vmobject.get_stroke_rgbas(background)\n\n    def get_fill_rgbas(self, vmobject: VMobject) -> FloatRGBA_Array:\n        \"\"\"Returns the RGBA array of the fill of the passed VMobject\n\n        Parameters\n        ----------\n        vmobject\n            The VMobject\n\n        Returns\n        -------\n        np.array\n            The RGBA Array of the fill of the VMobject\n        \"\"\"\n        return vmobject.get_fill_rgbas()\n\n    def get_background_colored_vmobject_displayer(\n        self,\n    ) -> BackgroundColoredVMobjectDisplayer:\n        \"\"\"Returns the background_colored_vmobject_displayer\n        if it exists or makes one and returns it if not.\n\n        Returns\n        -------\n        BackgroundColoredVMobjectDisplayer\n            Object that displays VMobjects that have the same color\n            as the background.\n        \"\"\"\n        if self.background_colored_vmobject_displayer is None:\n            self.background_colored_vmobject_displayer = (\n                BackgroundColoredVMobjectDisplayer(self)\n            )\n        return self.background_colored_vmobject_displayer\n\n    def display_multiple_background_colored_vmobjects(\n        self, cvmobjects: Iterable[VMobject], pixel_array: PixelArray\n    ) -> Self:\n        \"\"\"Displays multiple vmobjects that have the same color as the background.\n\n        Parameters\n        ----------\n        cvmobjects\n            List of Colored VMobjects\n        pixel_array\n            The pixel array.\n\n        Returns\n        -------\n        Camera\n            The camera object.\n        \"\"\"\n        displayer = self.get_background_colored_vmobject_displayer()\n        cvmobject_pixel_array = displayer.display(*cvmobjects)\n        self.overlay_rgba_array(pixel_array, cvmobject_pixel_array)\n        return self\n\n    # Methods for other rendering\n\n    # NOTE: Out of the following methods, only `transform_points_pre_display` and `points_to_pixel_coords` have been mentioned outside of their definitions.\n    # As a result, the other methods do not have as detailed docstrings as would be preferred.\n\n    def display_multiple_point_cloud_mobjects(\n        self, pmobjects: Iterable[PMobject], pixel_array: PixelArray\n    ) -> None:\n        \"\"\"Displays multiple PMobjects by modifying the passed pixel array.\n\n        Parameters\n        ----------\n        pmobjects\n            List of PMobjects\n        pixel_array\n            The pixel array to modify.\n        \"\"\"\n        for pmobject in pmobjects:\n            self.display_point_cloud(\n                pmobject,\n                pmobject.points,\n                pmobject.rgbas,\n                self.adjusted_thickness(pmobject.stroke_width),\n                pixel_array,\n            )\n\n    def display_point_cloud(\n        self,\n        pmobject: PMobject,\n        points: Point3D_Array,\n        rgbas: FloatRGBA_Array,\n        thickness: float,\n        pixel_array: PixelArray,\n    ) -> None:\n        \"\"\"Displays a PMobject by modifying the pixel array suitably.\n\n        TODO: Write a description for the rgbas argument.\n\n        Parameters\n        ----------\n        pmobject\n            Point Cloud Mobject\n        points\n            The points to display in the point cloud mobject\n        rgbas\n\n        thickness\n            The thickness of each point of the PMobject\n        pixel_array\n            The pixel array to modify.\n\n        \"\"\"\n        if len(points) == 0:\n            return\n        pixel_coords = self.points_to_pixel_coords(pmobject, points)\n        pixel_coords = self.thickened_coordinates(pixel_coords, thickness)\n        rgba_len = pixel_array.shape[2]\n\n        rgbas = (self.rgb_max_val * rgbas).astype(self.pixel_array_dtype)\n        target_len = len(pixel_coords)\n        factor = target_len // len(rgbas)\n        rgbas = np.array([rgbas] * factor).reshape((target_len, rgba_len))\n\n        on_screen_indices = self.on_screen_pixels(pixel_coords)\n        pixel_coords = pixel_coords[on_screen_indices]\n        rgbas = rgbas[on_screen_indices]\n\n        ph = self.pixel_height\n        pw = self.pixel_width\n\n        flattener = np.array([1, pw], dtype=\"int\")\n        flattener = flattener.reshape((2, 1))\n        indices = np.dot(pixel_coords, flattener)[:, 0]\n        indices = indices.astype(\"int\")\n\n        new_pa = pixel_array.reshape((ph * pw, rgba_len))\n        new_pa[indices] = rgbas\n        pixel_array[:, :] = new_pa.reshape((ph, pw, rgba_len))\n\n    def display_multiple_image_mobjects(\n        self,\n        image_mobjects: Iterable[AbstractImageMobject],\n        pixel_array: PixelArray,\n    ) -> None:\n        \"\"\"Displays multiple image mobjects by modifying the passed pixel_array.\n\n        Parameters\n        ----------\n        image_mobjects\n            list of ImageMobjects\n        pixel_array\n            The pixel array to modify.\n        \"\"\"\n        for image_mobject in image_mobjects:\n            self.display_image_mobject(image_mobject, pixel_array)\n\n    def display_image_mobject(\n        self, image_mobject: AbstractImageMobject, pixel_array: np.ndarray\n    ) -> None:\n        \"\"\"Display an :class:`~.ImageMobject` by changing the ``pixel_array`` suitably.\n\n        Parameters\n        ----------\n        image_mobject\n            The :class:`~.ImageMobject` to display.\n        pixel_array\n            The pixel array to put the :class:`~.ImageMobject` in.\n        \"\"\"\n        sub_image = Image.fromarray(image_mobject.get_pixel_array(), mode=\"RGBA\")\n        original_coords = np.array(\n            [\n                [0, 0],\n                [sub_image.width, 0],\n                [0, sub_image.height],\n                [sub_image.width, sub_image.height],\n            ]\n        )\n        target_coords = self.points_to_subpixel_coords(\n            image_mobject, image_mobject.points\n        )\n        int_target_coords = target_coords.astype(np.int64)\n\n        # Temporarily translate target coords to upper left corner to calculate the\n        # smallest possible size for the target image.\n        shift_vector = np.array(\n            [\n                min(*[x for x, y in int_target_coords]),\n                min(*[y for x, y in int_target_coords]),\n            ]\n        )\n        target_coords -= shift_vector\n        int_target_coords -= shift_vector\n        target_size = (\n            max(*[x for x, y in int_target_coords]),\n            max(*[y for x, y in int_target_coords]),\n        )\n\n        # Check that the quadrilateral of the transformed image can actually contain any\n        # pixels by checking that its height from the longest side is longer than 0.5 pixels.\n        # If it's not, do not render the image. Otherwise, the perspective transform\n        # coefficients below might have broken values due to the extreme distortion (for\n        # example, when the image is perpendicular to the camera).\n        ordered_vertices = [target_coords[i] for i in (0, 1, 3, 2)]\n        sides = [ordered_vertices[(i + 1) % 4] - ordered_vertices[i] for i in range(4)]\n        side_lengths_in_pixels = np.linalg.norm(sides, axis=1)\n\n        longest_side_index = np.argmax(side_lengths_in_pixels)\n        longest_side = sides[longest_side_index]\n        longest_side_length_in_pixels = side_lengths_in_pixels[longest_side_index]\n        if longest_side_length_in_pixels == 0:\n            return\n\n        previous_side = sides[(longest_side_index - 1) % 4]\n        next_side = sides[(longest_side_index - 1) % 4]\n\n        # height = area / base\n        h1 = abs(cross2d(longest_side, previous_side)) / longest_side_length_in_pixels\n        h2 = abs(cross2d(longest_side, next_side)) / longest_side_length_in_pixels\n        height_from_longest_side_in_pixels = max(h1, h2)\n\n        if height_from_longest_side_in_pixels < 0.5:\n            return\n\n        # Use PIL.Image.Image.transform() to apply a perspective transform to the image.\n        # The transform coefficients must be calculated. The following is adapted from:\n        # https://pc-pillow.readthedocs.io/en/latest/Image_class/Image_transform.html#transform-perspective-coefficients\n        # https://stackoverflow.com/questions/14177744/how-does-perspective-transformation-work-in-pil\n        # The derivation can be found here:\n        # https://web.archive.org/web/20150222120106/xenia.media.mit.edu/~cwren/interpolator/\n        homography_matrix = []\n        for (x, y), (X, Y) in zip(target_coords, original_coords, strict=True):\n            homography_matrix.append([x, y, 1, 0, 0, 0, -X * x, -X * y])\n            homography_matrix.append([0, 0, 0, x, y, 1, -Y * x, -Y * y])\n\n        A = np.array(homography_matrix, dtype=np.float64)\n        b = original_coords.reshape(8).astype(np.float64)\n\n        try:\n            transform_coefficients = np.linalg.solve(A, b)\n        except np.linalg.LinAlgError:\n            # The matrix A might be singular if three points are collinear.\n            # In this case, do nothing and return.\n            return\n\n        sub_image = sub_image.transform(\n            size=target_size,  # Use the smallest possible size for speed.\n            method=Image.Transform.PERSPECTIVE,\n            data=transform_coefficients,\n            resample=image_mobject.resampling_algorithm,\n        )\n\n        # Paste into an image as large as the camera's pixel array.\n        full_image = Image.fromarray(\n            np.zeros((self.pixel_height, self.pixel_width)),\n            mode=\"RGBA\",\n        )\n        full_image.paste(\n            sub_image,\n            box=(\n                shift_vector[0],\n                shift_vector[1],\n                shift_vector[0] + target_size[0],\n                shift_vector[1] + target_size[1],\n            ),\n        )\n        # Paint on top of existing pixel array.\n        self.overlay_PIL_image(pixel_array, full_image)\n\n    def overlay_rgba_array(\n        self, pixel_array: np.ndarray, new_array: np.ndarray\n    ) -> None:\n        \"\"\"Overlays an RGBA array on top of the given Pixel array.\n\n        Parameters\n        ----------\n        pixel_array\n            The original pixel array to modify.\n        new_array\n            The new pixel array to overlay.\n        \"\"\"\n        self.overlay_PIL_image(pixel_array, self.get_image(new_array))\n\n    def overlay_PIL_image(self, pixel_array: np.ndarray, image: Image) -> None:\n        \"\"\"Overlays a PIL image on the passed pixel array.\n\n        Parameters\n        ----------\n        pixel_array\n            The Pixel array\n        image\n            The Image to overlay.\n        \"\"\"\n        pixel_array[:, :] = np.array(\n            Image.alpha_composite(self.get_image(pixel_array), image),\n            dtype=\"uint8\",\n        )\n\n    def adjust_out_of_range_points(self, points: np.ndarray) -> np.ndarray:\n        \"\"\"If any of the points in the passed array are out of\n        the viable range, they are adjusted suitably.\n\n        Parameters\n        ----------\n        points\n            The points to adjust\n\n        Returns\n        -------\n        np.array\n            The adjusted points.\n        \"\"\"\n        if not np.any(points > self.max_allowable_norm):\n            return points\n        norms = np.apply_along_axis(np.linalg.norm, 1, points)\n        violator_indices = norms > self.max_allowable_norm\n        violators = points[violator_indices, :]\n        violator_norms = norms[violator_indices]\n        reshaped_norms = np.repeat(\n            violator_norms.reshape((len(violator_norms), 1)),\n            points.shape[1],\n            1,\n        )\n        rescaled = self.max_allowable_norm * violators / reshaped_norms\n        points[violator_indices] = rescaled\n        return points\n\n    def transform_points_pre_display(\n        self,\n        mobject: Mobject,\n        points: Point3D_Array,\n    ) -> Point3D_Array:  # TODO: Write more detailed docstrings for this method.\n        # NOTE: There seems to be an unused argument `mobject`.\n\n        # Subclasses (like ThreeDCamera) may want to\n        # adjust points further before they're shown\n        if not np.all(np.isfinite(points)):\n            # TODO, print some kind of warning about\n            # mobject having invalid points?\n            points = np.zeros((1, 3))\n        return points\n\n    def points_to_subpixel_coords(\n        self,\n        mobject: Mobject,\n        points: Point3D_Array,\n    ) -> npt.NDArray[\n        ManimFloat\n    ]:  # TODO: Write more detailed docstrings for this method.\n        points = self.transform_points_pre_display(mobject, points)\n        shifted_points = points - self.frame_center\n\n        result = np.zeros((len(points), 2))\n        pixel_height = self.pixel_height\n        pixel_width = self.pixel_width\n        frame_height = self.frame_height\n        frame_width = self.frame_width\n        width_mult = pixel_width / frame_width\n        width_add = pixel_width / 2\n        height_mult = pixel_height / frame_height\n        height_add = pixel_height / 2\n        # Flip on y-axis as you go\n        height_mult *= -1\n\n        result[:, 0] = shifted_points[:, 0] * width_mult + width_add\n        result[:, 1] = shifted_points[:, 1] * height_mult + height_add\n        return result\n\n    def points_to_pixel_coords(\n        self,\n        mobject: Mobject,\n        points: Point3D_Array,\n    ) -> npt.NDArray[ManimInt]:  # TODO: Write more detailed docstrings for this method.\n        return self.points_to_subpixel_coords(mobject, points).astype(np.int64)\n\n    def on_screen_pixels(self, pixel_coords: np.ndarray) -> PixelArray:\n        \"\"\"Returns array of pixels that are on the screen from a given\n        array of pixel_coordinates\n\n        Parameters\n        ----------\n        pixel_coords\n            The pixel coords to check.\n\n        Returns\n        -------\n        np.array\n            The pixel coords on screen.\n        \"\"\"\n        return reduce(\n            op.and_,\n            [\n                pixel_coords[:, 0] >= 0,\n                pixel_coords[:, 0] < self.pixel_width,\n                pixel_coords[:, 1] >= 0,\n                pixel_coords[:, 1] < self.pixel_height,\n            ],\n        )\n\n    def adjusted_thickness(self, thickness: float) -> float:\n        \"\"\"Computes the adjusted stroke width for a zoomed camera.\n\n        Parameters\n        ----------\n        thickness\n            The stroke width of a mobject.\n\n        Returns\n        -------\n        float\n            The adjusted stroke width that reflects zooming in with\n            the camera.\n        \"\"\"\n        # TODO: This seems...unsystematic\n        big_sum: float = op.add(config[\"pixel_height\"], config[\"pixel_width\"])\n        this_sum: float = op.add(self.pixel_height, self.pixel_width)\n        factor = big_sum / this_sum\n        return 1 + (thickness - 1) * factor\n\n    def get_thickening_nudges(self, thickness: float) -> PixelArray:\n        \"\"\"Determine a list of vectors used to nudge\n        two-dimensional pixel coordinates.\n\n        Parameters\n        ----------\n        thickness\n\n        Returns\n        -------\n        np.array\n\n        \"\"\"\n        thickness = int(thickness)\n        _range = list(range(-thickness // 2 + 1, thickness // 2 + 1))\n        return np.array(list(it.product(_range, _range)))\n\n    def thickened_coordinates(\n        self, pixel_coords: np.ndarray, thickness: float\n    ) -> PixelArray:\n        \"\"\"Returns thickened coordinates for a passed array of pixel coords and\n        a thickness to thicken by.\n\n        Parameters\n        ----------\n        pixel_coords\n            Pixel coordinates\n        thickness\n            Thickness\n\n        Returns\n        -------\n        np.array\n            Array of thickened pixel coords.\n        \"\"\"\n        nudges = self.get_thickening_nudges(thickness)\n        pixel_coords = np.array([pixel_coords + nudge for nudge in nudges])\n        size = pixel_coords.size\n        return pixel_coords.reshape((size // 2, 2))\n\n    # TODO, reimplement using cairo matrix\n    def get_coords_of_all_pixels(self) -> PixelArray:\n        \"\"\"Returns the cartesian coordinates of each pixel.\n\n        Returns\n        -------\n        np.ndarray\n            The array of cartesian coordinates.\n        \"\"\"\n        # These are in x, y order, to help me keep things straight\n        full_space_dims = np.array([self.frame_width, self.frame_height])\n        full_pixel_dims = np.array([self.pixel_width, self.pixel_height])\n\n        # These are addressed in the same y, x order as in pixel_array, but the values in them\n        # are listed in x, y order\n        uncentered_pixel_coords = np.indices([self.pixel_height, self.pixel_width])[\n            ::-1\n        ].transpose(1, 2, 0)\n        uncentered_space_coords = (\n            uncentered_pixel_coords * full_space_dims\n        ) / full_pixel_dims\n        # Could structure above line's computation slightly differently, but figured (without much\n        # thought) multiplying by frame_shape first, THEN dividing by pixel_shape, is probably\n        # better than the other order, for avoiding underflow quantization in the division (whereas\n        # overflow is unlikely to be a problem)\n\n        centered_space_coords = uncentered_space_coords - (full_space_dims / 2)\n\n        # Have to also flip the y coordinates to account for pixel array being listed in\n        # top-to-bottom order, opposite of screen coordinate convention\n        centered_space_coords = centered_space_coords * (1, -1)\n\n        return centered_space_coords\n\n\n# NOTE: The methods of the following class have not been mentioned outside of their definitions.\n# Their DocStrings are not as detailed as preferred.\nclass BackgroundColoredVMobjectDisplayer:\n    \"\"\"Auxiliary class that handles displaying vectorized mobjects with\n    a set background image.\n\n    Parameters\n    ----------\n    camera\n        Camera object to use.\n    \"\"\"\n\n    def __init__(self, camera: Camera):\n        self.camera = camera\n        self.file_name_to_pixel_array_map: dict[str, PixelArray] = {}\n        self.pixel_array = np.array(camera.pixel_array)\n        self.reset_pixel_array()\n\n    def reset_pixel_array(self) -> None:\n        self.pixel_array[:, :] = 0\n\n    def resize_background_array(\n        self,\n        background_array: PixelArray,\n        new_width: float,\n        new_height: float,\n        mode: str = \"RGBA\",\n    ) -> PixelArray:\n        \"\"\"Resizes the pixel array representing the background.\n\n        Parameters\n        ----------\n        background_array\n            The pixel\n        new_width\n            The new width of the background\n        new_height\n            The new height of the background\n        mode\n            The PIL image mode, by default \"RGBA\"\n\n        Returns\n        -------\n        np.array\n            The numpy pixel array of the resized background.\n        \"\"\"\n        image = Image.fromarray(background_array)\n        image = image.convert(mode)\n        resized_image = image.resize((new_width, new_height))\n        return np.array(resized_image)\n\n    def resize_background_array_to_match(\n        self, background_array: PixelArray, pixel_array: PixelArray\n    ) -> PixelArray:\n        \"\"\"Resizes the background array to match the passed pixel array.\n\n        Parameters\n        ----------\n        background_array\n            The prospective pixel array.\n        pixel_array\n            The pixel array whose width and height should be matched.\n\n        Returns\n        -------\n        np.array\n            The resized background array.\n        \"\"\"\n        height, width = pixel_array.shape[:2]\n        mode = \"RGBA\" if pixel_array.shape[2] == 4 else \"RGB\"\n        return self.resize_background_array(background_array, width, height, mode)\n\n    def get_background_array(\n        self, image: Image.Image | pathlib.Path | str\n    ) -> PixelArray:\n        \"\"\"Gets the background array that has the passed file_name.\n\n        Parameters\n        ----------\n        image\n            The background image or its file name.\n\n        Returns\n        -------\n        np.ndarray\n            The pixel array of the image.\n        \"\"\"\n        image_key = str(image)\n\n        if image_key in self.file_name_to_pixel_array_map:\n            return self.file_name_to_pixel_array_map[image_key]\n        if isinstance(image, str):\n            full_path = get_full_raster_image_path(image)\n            image = Image.open(full_path)\n        back_array = np.array(image)\n\n        pixel_array = self.pixel_array\n        if not np.all(pixel_array.shape == back_array.shape):\n            back_array = self.resize_background_array_to_match(back_array, pixel_array)\n\n        self.file_name_to_pixel_array_map[image_key] = back_array\n        return back_array\n\n    def display(self, *cvmobjects: VMobject) -> PixelArray | None:\n        \"\"\"Displays the colored VMobjects.\n\n        Parameters\n        ----------\n        *cvmobjects\n            The VMobjects\n\n        Returns\n        -------\n        np.array\n            The pixel array with the `cvmobjects` displayed.\n        \"\"\"\n        batch_image_pairs = it.groupby(cvmobjects, lambda cv: cv.get_background_image())\n        curr_array = None\n        for image, batch in batch_image_pairs:\n            background_array = self.get_background_array(image)\n            pixel_array = self.pixel_array\n            self.camera.display_multiple_non_background_colored_vmobjects(\n                batch,\n                pixel_array,\n            )\n            new_array = np.array(\n                (background_array * pixel_array.astype(\"float\") / 255),\n                dtype=self.camera.pixel_array_dtype,\n            )\n            if curr_array is None:\n                curr_array = new_array\n            else:\n                curr_array = np.maximum(curr_array, new_array)\n            self.reset_pixel_array()\n        return curr_array\n"
  },
  {
    "path": "manim/camera/mapping_camera.py",
    "content": "\"\"\"A camera module that supports spatial mapping between objects for distortion effects.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"MappingCamera\", \"OldMultiCamera\", \"SplitScreenCamera\"]\n\nimport math\n\nimport numpy as np\n\nfrom ..camera.camera import Camera\nfrom ..mobject.types.vectorized_mobject import VMobject\nfrom ..utils.config_ops import DictAsObject\n\n# TODO: Add an attribute to mobjects under which they can specify that they should just\n# map their centers but remain otherwise undistorted (useful for labels, etc.)\n\n\nclass MappingCamera(Camera):\n    \"\"\"Parameters\n    ----------\n    mapping_func : callable\n        Function to map 3D points to new 3D points (identity by default).\n    min_num_curves : int\n        Minimum number of curves for VMobjects to avoid visual glitches.\n    allow_object_intrusion : bool\n        If True, modifies original mobjects; else works on copies.\n    kwargs : dict\n        Additional arguments passed to Camera base class.\n    \"\"\"\n\n    def __init__(\n        self,\n        mapping_func=lambda p: p,\n        min_num_curves=50,\n        allow_object_intrusion=False,\n        **kwargs,\n    ):\n        self.mapping_func = mapping_func\n        self.min_num_curves = min_num_curves\n        self.allow_object_intrusion = allow_object_intrusion\n        super().__init__(**kwargs)\n\n    def points_to_pixel_coords(self, mobject, points):\n        # Map points with custom function before converting to pixels\n        return super().points_to_pixel_coords(\n            mobject,\n            np.apply_along_axis(self.mapping_func, 1, points),\n        )\n\n    def capture_mobjects(self, mobjects, **kwargs):\n        \"\"\"Capture mobjects for rendering after applying the spatial mapping.\n\n        Copies mobjects unless intrusion is allowed, and ensures\n        vector objects have enough curves for smooth distortion.\n        \"\"\"\n        mobjects = self.get_mobjects_to_display(mobjects, **kwargs)\n        if self.allow_object_intrusion:\n            mobject_copies = mobjects\n        else:\n            mobject_copies = [mobject.copy() for mobject in mobjects]\n        for mobject in mobject_copies:\n            if (\n                isinstance(mobject, VMobject)\n                and 0 < mobject.get_num_curves() < self.min_num_curves\n            ):\n                mobject.insert_n_curves(self.min_num_curves)\n        super().capture_mobjects(\n            mobject_copies,\n            include_submobjects=False,\n            excluded_mobjects=None,\n        )\n\n\n# Note: This allows layering of multiple cameras onto the same portion of the pixel array,\n# the later cameras overwriting the former\n#\n# TODO: Add optional separator borders between cameras (or perhaps peel this off into a\n# CameraPlusOverlay class)\n\n\n# TODO, the classes below should likely be deleted\nclass OldMultiCamera(Camera):\n    \"\"\"Parameters\n    ----------\n    cameras_with_start_positions : tuple\n        Tuples of (Camera, (start_y, start_x)) indicating camera and\n        its pixel offset on the final frame.\n    \"\"\"\n\n    def __init__(self, *cameras_with_start_positions, **kwargs):\n        self.shifted_cameras = [\n            DictAsObject(\n                {\n                    \"camera\": camera_with_start_positions[0],\n                    \"start_x\": camera_with_start_positions[1][1],\n                    \"start_y\": camera_with_start_positions[1][0],\n                    \"end_x\": camera_with_start_positions[1][1]\n                    + camera_with_start_positions[0].pixel_width,\n                    \"end_y\": camera_with_start_positions[1][0]\n                    + camera_with_start_positions[0].pixel_height,\n                },\n            )\n            for camera_with_start_positions in cameras_with_start_positions\n        ]\n        super().__init__(**kwargs)\n\n    def capture_mobjects(self, mobjects, **kwargs):\n        for shifted_camera in self.shifted_cameras:\n            shifted_camera.camera.capture_mobjects(mobjects, **kwargs)\n\n            self.pixel_array[\n                shifted_camera.start_y : shifted_camera.end_y,\n                shifted_camera.start_x : shifted_camera.end_x,\n            ] = shifted_camera.camera.pixel_array\n\n    def set_background(self, pixel_array, **kwargs):\n        for shifted_camera in self.shifted_cameras:\n            shifted_camera.camera.set_background(\n                pixel_array[\n                    shifted_camera.start_y : shifted_camera.end_y,\n                    shifted_camera.start_x : shifted_camera.end_x,\n                ],\n                **kwargs,\n            )\n\n    def set_pixel_array(self, pixel_array, **kwargs):\n        super().set_pixel_array(pixel_array, **kwargs)\n        for shifted_camera in self.shifted_cameras:\n            shifted_camera.camera.set_pixel_array(\n                pixel_array[\n                    shifted_camera.start_y : shifted_camera.end_y,\n                    shifted_camera.start_x : shifted_camera.end_x,\n                ],\n                **kwargs,\n            )\n\n    def init_background(self):\n        super().init_background()\n        for shifted_camera in self.shifted_cameras:\n            shifted_camera.camera.init_background()\n\n\n# A OldMultiCamera which, when called with two full-size cameras, initializes itself\n# as a split screen, also taking care to resize each individual camera within it\n\n\nclass SplitScreenCamera(OldMultiCamera):\n    \"\"\"Initializes a split screen camera setup with two side-by-side cameras.\n\n    Parameters\n    ----------\n    left_camera : Camera\n    right_camera : Camera\n    kwargs : dict\n    \"\"\"\n\n    def __init__(self, left_camera, right_camera, **kwargs):\n        Camera.__init__(self, **kwargs)  # to set attributes such as pixel_width\n        self.left_camera = left_camera\n        self.right_camera = right_camera\n\n        half_width = math.ceil(self.pixel_width / 2)\n        for camera in [self.left_camera, self.right_camera]:\n            camera.reset_pixel_shape(camera.pixel_height, half_width)\n\n        super().__init__(\n            (left_camera, (0, 0)),\n            (right_camera, (0, half_width)),\n        )\n"
  },
  {
    "path": "manim/camera/moving_camera.py",
    "content": "\"\"\"Defines the MovingCamera class, a camera that can pan and zoom through a scene.\n\n.. SEEALSO::\n\n    :mod:`.moving_camera_scene`\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"MovingCamera\"]\n\nfrom collections.abc import Iterable\nfrom typing import Any, Literal, overload\n\nfrom cairo import Context\n\nfrom manim.typing import PixelArray, Point3D, Point3DLike\n\nfrom .. import config\nfrom ..camera.camera import Camera\nfrom ..constants import DOWN, LEFT, RIGHT, UP\nfrom ..mobject.frame import ScreenRectangle\nfrom ..mobject.mobject import Mobject, _AnimationBuilder\nfrom ..utils.color import WHITE, ManimColor\n\n\nclass MovingCamera(Camera):\n    \"\"\"A camera that follows and matches the size and position of its 'frame', a Rectangle (or similar Mobject).\n\n    The frame defines the region of space the camera displays and can move or resize dynamically.\n\n    .. SEEALSO::\n\n        :class:`.MovingCameraScene`\n    \"\"\"\n\n    def __init__(\n        self,\n        frame: Mobject | None = None,\n        fixed_dimension: int = 0,  # width\n        default_frame_stroke_color: ManimColor = WHITE,\n        default_frame_stroke_width: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"Frame is a Mobject, (should almost certainly be a rectangle)\n        determining which region of space the camera displays\n        \"\"\"\n        self.fixed_dimension = fixed_dimension\n        self.default_frame_stroke_color = default_frame_stroke_color\n        self.default_frame_stroke_width = default_frame_stroke_width\n        if frame is None:\n            frame = ScreenRectangle(height=config[\"frame_height\"])\n            frame.set_stroke(\n                self.default_frame_stroke_color,\n                self.default_frame_stroke_width,\n            )\n        self.frame = frame\n        super().__init__(**kwargs)\n\n    # TODO, make these work for a rotated frame\n    @property\n    def frame_height(self) -> float:\n        \"\"\"Returns the height of the frame.\n\n        Returns\n        -------\n        float\n            The height of the frame.\n        \"\"\"\n        return self.frame.height\n\n    @frame_height.setter\n    def frame_height(self, frame_height: float) -> None:\n        \"\"\"Sets the height of the frame in MUnits.\n\n        Parameters\n        ----------\n        frame_height\n            The new frame_height.\n        \"\"\"\n        self.frame.stretch_to_fit_height(frame_height)\n\n    @property\n    def frame_width(self) -> float:\n        \"\"\"Returns the width of the frame\n\n        Returns\n        -------\n        float\n            The width of the frame.\n        \"\"\"\n        return self.frame.width\n\n    @frame_width.setter\n    def frame_width(self, frame_width: float) -> None:\n        \"\"\"Sets the width of the frame in MUnits.\n\n        Parameters\n        ----------\n        frame_width\n            The new frame_width.\n        \"\"\"\n        self.frame.stretch_to_fit_width(frame_width)\n\n    @property\n    def frame_center(self) -> Point3D:\n        \"\"\"Returns the centerpoint of the frame in cartesian coordinates.\n\n        Returns\n        -------\n        np.array\n            The cartesian coordinates of the center of the frame.\n        \"\"\"\n        return self.frame.get_center()\n\n    @frame_center.setter\n    def frame_center(self, frame_center: Point3DLike | Mobject) -> None:\n        \"\"\"Sets the centerpoint of the frame.\n\n        Parameters\n        ----------\n        frame_center\n            The point to which the frame must be moved.\n            If is of type mobject, the frame will be moved to\n            the center of that mobject.\n        \"\"\"\n        self.frame.move_to(frame_center)\n\n    def capture_mobjects(self, mobjects: Iterable[Mobject], **kwargs: Any) -> None:\n        # self.reset_frame_center()\n        # self.realign_frame_shape()\n        super().capture_mobjects(mobjects, **kwargs)\n\n    def get_cached_cairo_context(self, pixel_array: PixelArray) -> None:\n        \"\"\"Since the frame can be moving around, the cairo\n        context used for updating should be regenerated\n        at each frame.  So no caching.\n        \"\"\"\n        return None\n\n    def cache_cairo_context(self, pixel_array: PixelArray, ctx: Context) -> None:\n        \"\"\"Since the frame can be moving around, the cairo\n        context used for updating should be regenerated\n        at each frame.  So no caching.\n        \"\"\"\n        pass\n\n    # def reset_frame_center(self):\n    #     self.frame_center = self.frame.get_center()\n\n    # def realign_frame_shape(self):\n    #     height, width = self.frame_shape\n    #     if self.fixed_dimension == 0:\n    #         self.frame_shape = (height, self.frame.width\n    #     else:\n    #         self.frame_shape = (self.frame.height, width)\n    #     self.resize_frame_shape(fixed_dimension=self.fixed_dimension)\n\n    def get_mobjects_indicating_movement(self) -> list[Mobject]:\n        \"\"\"Returns all mobjects whose movement implies that the camera\n        should think of all other mobjects on the screen as moving\n\n        Returns\n        -------\n        list[Mobject]\n        \"\"\"\n        return [self.frame]\n\n    @overload\n    def auto_zoom(\n        self,\n        mobjects: Iterable[Mobject],\n        margin: float,\n        only_mobjects_in_frame: bool,\n        animate: Literal[False],\n    ) -> Mobject: ...\n\n    @overload\n    def auto_zoom(\n        self,\n        mobjects: Iterable[Mobject],\n        margin: float,\n        only_mobjects_in_frame: bool,\n        animate: Literal[True],\n    ) -> _AnimationBuilder: ...\n\n    def auto_zoom(\n        self,\n        mobjects: Iterable[Mobject],\n        margin: float = 0,\n        only_mobjects_in_frame: bool = False,\n        animate: bool = True,\n    ) -> _AnimationBuilder | Mobject:\n        \"\"\"Zooms on to a given array of mobjects (or a singular mobject)\n        and automatically resizes to frame all the mobjects.\n\n        .. NOTE::\n\n            This method only works when 2D-objects in the XY-plane are considered, it\n            will not work correctly when the camera has been rotated.\n\n        Parameters\n        ----------\n        mobjects\n            The mobject or array of mobjects that the camera will focus on.\n\n        margin\n            The width of the margin that is added to the frame (optional, 0 by default).\n\n        only_mobjects_in_frame\n            If set to ``True``, only allows focusing on mobjects that are already in frame.\n\n        animate\n            If set to ``False``, applies the changes instead of returning the corresponding animation\n\n        Returns\n        -------\n        Union[_AnimationBuilder, ScreenRectangle]\n            _AnimationBuilder that zooms the camera view to a given list of mobjects\n            or ScreenRectangle with position and size updated to zoomed position.\n\n        \"\"\"\n        (\n            scene_critical_x_left,\n            scene_critical_x_right,\n            scene_critical_y_up,\n            scene_critical_y_down,\n        ) = self._get_bounding_box(mobjects, only_mobjects_in_frame)\n\n        # calculate center x and y\n        x = (scene_critical_x_left + scene_critical_x_right) / 2\n        y = (scene_critical_y_up + scene_critical_y_down) / 2\n\n        # calculate proposed width and height of zoomed scene\n        new_width = abs(scene_critical_x_left - scene_critical_x_right)\n        new_height = abs(scene_critical_y_up - scene_critical_y_down)\n\n        m_target = self.frame.animate if animate else self.frame\n        # zoom to fit all mobjects along the side that has the largest size\n        if new_width / self.frame.width > new_height / self.frame.height:\n            return m_target.set_x(x).set_y(y).set(width=new_width + margin)\n        else:\n            return m_target.set_x(x).set_y(y).set(height=new_height + margin)\n\n    def _get_bounding_box(\n        self, mobjects: Iterable[Mobject], only_mobjects_in_frame: bool\n    ) -> tuple[float, float, float, float]:\n        bounding_box_located = False\n        scene_critical_x_left: float = 0\n        scene_critical_x_right: float = 1\n        scene_critical_y_up: float = 1\n        scene_critical_y_down: float = 0\n\n        for m in mobjects:\n            if (m == self.frame) or (\n                only_mobjects_in_frame and not self.is_in_frame(m)\n            ):\n                # detected camera frame, should not be used to calculate final position of camera\n                continue\n\n            # initialize scene critical points with first mobjects critical points\n            if not bounding_box_located:\n                scene_critical_x_left = m.get_critical_point(LEFT)[0]\n                scene_critical_x_right = m.get_critical_point(RIGHT)[0]\n                scene_critical_y_up = m.get_critical_point(UP)[1]\n                scene_critical_y_down = m.get_critical_point(DOWN)[1]\n                bounding_box_located = True\n\n            else:\n                if m.get_critical_point(LEFT)[0] < scene_critical_x_left:\n                    scene_critical_x_left = m.get_critical_point(LEFT)[0]\n\n                if m.get_critical_point(RIGHT)[0] > scene_critical_x_right:\n                    scene_critical_x_right = m.get_critical_point(RIGHT)[0]\n\n                if m.get_critical_point(UP)[1] > scene_critical_y_up:\n                    scene_critical_y_up = m.get_critical_point(UP)[1]\n\n                if m.get_critical_point(DOWN)[1] < scene_critical_y_down:\n                    scene_critical_y_down = m.get_critical_point(DOWN)[1]\n\n        if not bounding_box_located:\n            raise Exception(\n                \"Could not determine bounding box of the mobjects given to 'auto_zoom'.\"\n            )\n\n        return (\n            scene_critical_x_left,\n            scene_critical_x_right,\n            scene_critical_y_up,\n            scene_critical_y_down,\n        )\n"
  },
  {
    "path": "manim/camera/multi_camera.py",
    "content": "\"\"\"A camera supporting multiple perspectives.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"MultiCamera\"]\n\n\nfrom collections.abc import Iterable\nfrom typing import Any, Self\n\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.types.image_mobject import ImageMobjectFromCamera\n\nfrom ..camera.moving_camera import MovingCamera\nfrom ..utils.iterables import list_difference_update\n\n\nclass MultiCamera(MovingCamera):\n    \"\"\"Camera Object that allows for multiple perspectives.\"\"\"\n\n    def __init__(\n        self,\n        image_mobjects_from_cameras: Iterable[ImageMobjectFromCamera] | None = None,\n        allow_cameras_to_capture_their_own_display: bool = False,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"Initialises the MultiCamera\n\n        Parameters\n        ----------\n        image_mobjects_from_cameras\n\n        kwargs\n            Any valid keyword arguments of MovingCamera.\n        \"\"\"\n        self.image_mobjects_from_cameras: list[ImageMobjectFromCamera] = []\n        if image_mobjects_from_cameras is not None:\n            for imfc in image_mobjects_from_cameras:\n                self.add_image_mobject_from_camera(imfc)\n        self.allow_cameras_to_capture_their_own_display = (\n            allow_cameras_to_capture_their_own_display\n        )\n        super().__init__(**kwargs)\n\n    def add_image_mobject_from_camera(\n        self, image_mobject_from_camera: ImageMobjectFromCamera\n    ) -> None:\n        \"\"\"Adds an ImageMobject that's been obtained from the camera\n        into the list ``self.image_mobject_from_cameras``\n\n        Parameters\n        ----------\n        image_mobject_from_camera\n            The ImageMobject to add to self.image_mobject_from_cameras\n        \"\"\"\n        # A silly method to have right now, but maybe there are things\n        # we want to guarantee about any imfc's added later.\n        imfc = image_mobject_from_camera\n        assert isinstance(imfc.camera, MovingCamera)\n        self.image_mobjects_from_cameras.append(imfc)\n\n    def update_sub_cameras(self) -> None:\n        \"\"\"Reshape sub_camera pixel_arrays\"\"\"\n        for imfc in self.image_mobjects_from_cameras:\n            pixel_height, pixel_width = self.pixel_array.shape[:2]\n            # imfc.camera.frame_shape = (\n            #     imfc.camera.frame.height,\n            #     imfc.camera.frame.width,\n            # )\n            imfc.camera.reset_pixel_shape(\n                int(pixel_height * imfc.height / self.frame_height),\n                int(pixel_width * imfc.width / self.frame_width),\n            )\n\n    def reset(self) -> Self:\n        \"\"\"Resets the MultiCamera.\n\n        Returns\n        -------\n        MultiCamera\n            The reset MultiCamera\n        \"\"\"\n        for imfc in self.image_mobjects_from_cameras:\n            imfc.camera.reset()\n        super().reset()\n        return self\n\n    def capture_mobjects(self, mobjects: Iterable[Mobject], **kwargs: Any) -> None:\n        self.update_sub_cameras()\n        for imfc in self.image_mobjects_from_cameras:\n            to_add = list(mobjects)\n            if not self.allow_cameras_to_capture_their_own_display:\n                to_add = list_difference_update(to_add, imfc.get_family())\n            imfc.camera.capture_mobjects(to_add, **kwargs)\n        super().capture_mobjects(mobjects, **kwargs)\n\n    def get_mobjects_indicating_movement(self) -> list[Mobject]:\n        \"\"\"Returns all mobjects whose movement implies that the camera\n        should think of all other mobjects on the screen as moving\n\n        Returns\n        -------\n        list\n        \"\"\"\n        return [self.frame] + [\n            imfc.camera.frame for imfc in self.image_mobjects_from_cameras\n        ]\n"
  },
  {
    "path": "manim/camera/three_d_camera.py",
    "content": "\"\"\"A camera that can be positioned and oriented in three-dimensional space.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"ThreeDCamera\"]\n\n\nfrom collections.abc import Callable, Iterable\nfrom typing import Any\n\nimport numpy as np\n\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.three_d.three_d_utils import (\n    get_3d_vmob_end_corner,\n    get_3d_vmob_end_corner_unit_normal,\n    get_3d_vmob_start_corner,\n    get_3d_vmob_start_corner_unit_normal,\n)\nfrom manim.mobject.types.vectorized_mobject import VMobject\nfrom manim.mobject.value_tracker import ValueTracker\nfrom manim.typing import (\n    FloatRGBA_Array,\n    MatrixMN,\n    Point3D,\n    Point3D_Array,\n    Point3DLike,\n)\n\nfrom .. import config\nfrom ..camera.camera import Camera\nfrom ..constants import *\nfrom ..mobject.types.point_cloud_mobject import Point\nfrom ..utils.color import get_shaded_rgb\nfrom ..utils.family import extract_mobject_family_members\nfrom ..utils.space_ops import rotation_about_z, rotation_matrix\n\n\nclass ThreeDCamera(Camera):\n    def __init__(\n        self,\n        focal_distance: float = 20.0,\n        shading_factor: float = 0.2,\n        default_distance: float = 5.0,\n        light_source_start_point: Point3DLike = 9 * DOWN + 7 * LEFT + 10 * OUT,\n        should_apply_shading: bool = True,\n        exponential_projection: bool = False,\n        phi: float = 0,\n        theta: float = -90 * DEGREES,\n        gamma: float = 0,\n        zoom: float = 1,\n        **kwargs: Any,\n    ):\n        \"\"\"Initializes the ThreeDCamera\n\n        Parameters\n        ----------\n        *kwargs\n            Any keyword argument of Camera.\n        \"\"\"\n        self._frame_center = Point(kwargs.get(\"frame_center\", ORIGIN), stroke_width=0)\n        super().__init__(**kwargs)\n        self.focal_distance = focal_distance\n        self.phi = phi\n        self.theta = theta\n        self.gamma = gamma\n        self.zoom = zoom\n        self.shading_factor = shading_factor\n        self.default_distance = default_distance\n        self.light_source_start_point = light_source_start_point\n        self.light_source = Point(self.light_source_start_point)\n        self.should_apply_shading = should_apply_shading\n        self.exponential_projection = exponential_projection\n        self.max_allowable_norm = 3 * config[\"frame_width\"]\n        self.phi_tracker = ValueTracker(self.phi)\n        self.theta_tracker = ValueTracker(self.theta)\n        self.focal_distance_tracker = ValueTracker(self.focal_distance)\n        self.gamma_tracker = ValueTracker(self.gamma)\n        self.zoom_tracker = ValueTracker(self.zoom)\n        self.fixed_orientation_mobjects: dict[Mobject, Callable[[], Point3D]] = {}\n        self.fixed_in_frame_mobjects: set[Mobject] = set()\n        self.reset_rotation_matrix()\n\n    @property\n    def frame_center(self) -> Point3D:\n        return self._frame_center.points[0]\n\n    @frame_center.setter\n    def frame_center(self, point: Point3DLike) -> None:\n        self._frame_center.move_to(point)\n\n    def capture_mobjects(self, mobjects: Iterable[Mobject], **kwargs: Any) -> None:\n        self.reset_rotation_matrix()\n        super().capture_mobjects(mobjects, **kwargs)\n\n    def get_value_trackers(self) -> list[ValueTracker]:\n        \"\"\"A list of :class:`ValueTrackers <.ValueTracker>` of phi, theta, focal_distance,\n        gamma and zoom.\n\n        Returns\n        -------\n        list\n            list of ValueTracker objects\n        \"\"\"\n        return [\n            self.phi_tracker,\n            self.theta_tracker,\n            self.focal_distance_tracker,\n            self.gamma_tracker,\n            self.zoom_tracker,\n        ]\n\n    def modified_rgbas(\n        self, vmobject: VMobject, rgbas: FloatRGBA_Array\n    ) -> FloatRGBA_Array:\n        if not self.should_apply_shading:\n            return rgbas\n        if vmobject.shade_in_3d and (vmobject.get_num_points() > 0):\n            light_source_point = self.light_source.points[0]\n            if len(rgbas) < 2:\n                shaded_rgbas = rgbas.repeat(2, axis=0)\n            else:\n                shaded_rgbas = np.array(rgbas[:2])\n            shaded_rgbas[0, :3] = get_shaded_rgb(\n                shaded_rgbas[0, :3],\n                get_3d_vmob_start_corner(vmobject),\n                get_3d_vmob_start_corner_unit_normal(vmobject),\n                light_source_point,\n            )\n            shaded_rgbas[1, :3] = get_shaded_rgb(\n                shaded_rgbas[1, :3],\n                get_3d_vmob_end_corner(vmobject),\n                get_3d_vmob_end_corner_unit_normal(vmobject),\n                light_source_point,\n            )\n            return shaded_rgbas\n        return rgbas\n\n    def get_stroke_rgbas(\n        self,\n        vmobject: VMobject,\n        background: bool = False,\n    ) -> FloatRGBA_Array:  # NOTE : DocStrings From parent\n        return self.modified_rgbas(vmobject, vmobject.get_stroke_rgbas(background))\n\n    def get_fill_rgbas(\n        self, vmobject: VMobject\n    ) -> FloatRGBA_Array:  # NOTE : DocStrings From parent\n        return self.modified_rgbas(vmobject, vmobject.get_fill_rgbas())\n\n    def get_mobjects_to_display(\n        self, *args: Any, **kwargs: Any\n    ) -> list[Mobject]:  # NOTE : DocStrings From parent\n        mobjects = super().get_mobjects_to_display(*args, **kwargs)\n        rot_matrix = self.get_rotation_matrix()\n\n        def z_key(mob: Mobject) -> float:\n            if not (hasattr(mob, \"shade_in_3d\") and mob.shade_in_3d):\n                return np.inf  # type: ignore[no-any-return]\n            # Assign a number to a three dimensional mobjects\n            # based on how close it is to the camera\n            distance: float = np.dot(mob.get_z_index_reference_point(), rot_matrix.T)[2]\n            return distance\n\n        return sorted(mobjects, key=z_key)\n\n    def get_phi(self) -> float:\n        \"\"\"Returns the Polar angle (the angle off Z_AXIS) phi.\n\n        Returns\n        -------\n        float\n            The Polar angle in radians.\n        \"\"\"\n        return self.phi_tracker.get_value()\n\n    def get_theta(self) -> float:\n        \"\"\"Returns the Azimuthal i.e the angle that spins the camera around the Z_AXIS.\n\n        Returns\n        -------\n        float\n            The Azimuthal angle in radians.\n        \"\"\"\n        return self.theta_tracker.get_value()\n\n    def get_focal_distance(self) -> float:\n        \"\"\"Returns focal_distance of the Camera.\n\n        Returns\n        -------\n        float\n            The focal_distance of the Camera in MUnits.\n        \"\"\"\n        return self.focal_distance_tracker.get_value()\n\n    def get_gamma(self) -> float:\n        \"\"\"Returns the rotation of the camera about the vector from the ORIGIN to the Camera.\n\n        Returns\n        -------\n        float\n            The angle of rotation of the camera about the vector\n            from the ORIGIN to the Camera in radians\n        \"\"\"\n        return self.gamma_tracker.get_value()\n\n    def get_zoom(self) -> float:\n        \"\"\"Returns the zoom amount of the camera.\n\n        Returns\n        -------\n        float\n            The zoom amount of the camera.\n        \"\"\"\n        return self.zoom_tracker.get_value()\n\n    def set_phi(self, value: float) -> None:\n        \"\"\"Sets the polar angle i.e the angle between Z_AXIS and Camera through ORIGIN in radians.\n\n        Parameters\n        ----------\n        value\n            The new value of the polar angle in radians.\n        \"\"\"\n        self.phi_tracker.set_value(value)\n\n    def set_theta(self, value: float) -> None:\n        \"\"\"Sets the azimuthal angle i.e the angle that spins the camera around Z_AXIS in radians.\n\n        Parameters\n        ----------\n        value\n            The new value of the azimuthal angle in radians.\n        \"\"\"\n        self.theta_tracker.set_value(value)\n\n    def set_focal_distance(self, value: float) -> None:\n        \"\"\"Sets the focal_distance of the Camera.\n\n        Parameters\n        ----------\n        value\n            The focal_distance of the Camera.\n        \"\"\"\n        self.focal_distance_tracker.set_value(value)\n\n    def set_gamma(self, value: float) -> None:\n        \"\"\"Sets the angle of rotation of the camera about the vector from the ORIGIN to the Camera.\n\n        Parameters\n        ----------\n        value\n            The new angle of rotation of the camera.\n        \"\"\"\n        self.gamma_tracker.set_value(value)\n\n    def set_zoom(self, value: float) -> None:\n        \"\"\"Sets the zoom amount of the camera.\n\n        Parameters\n        ----------\n        value\n            The zoom amount of the camera.\n        \"\"\"\n        self.zoom_tracker.set_value(value)\n\n    def reset_rotation_matrix(self) -> None:\n        \"\"\"Sets the value of self.rotation_matrix to\n        the matrix corresponding to the current position of the camera\n        \"\"\"\n        self.rotation_matrix = self.generate_rotation_matrix()\n\n    def get_rotation_matrix(self) -> MatrixMN:\n        \"\"\"Returns the matrix corresponding to the current position of the camera.\n\n        Returns\n        -------\n        np.array\n            The matrix corresponding to the current position of the camera.\n        \"\"\"\n        return self.rotation_matrix\n\n    def generate_rotation_matrix(self) -> MatrixMN:\n        \"\"\"Generates a rotation matrix based off the current position of the camera.\n\n        Returns\n        -------\n        np.array\n            The matrix corresponding to the current position of the camera.\n        \"\"\"\n        phi = self.get_phi()\n        theta = self.get_theta()\n        gamma = self.get_gamma()\n        matrices = [\n            rotation_about_z(-theta - 90 * DEGREES),\n            rotation_matrix(-phi, RIGHT),\n            rotation_about_z(gamma),\n        ]\n        result = np.identity(3)\n        for matrix in matrices:\n            result = np.dot(matrix, result)\n        return result\n\n    def project_points(self, points: Point3D_Array) -> Point3D_Array:\n        \"\"\"Applies the current rotation_matrix as a projection\n        matrix to the passed array of points.\n\n        Parameters\n        ----------\n        points\n            The list of points to project.\n\n        Returns\n        -------\n        np.array\n            The points after projecting.\n        \"\"\"\n        frame_center = self.frame_center\n        focal_distance = self.get_focal_distance()\n        zoom = self.get_zoom()\n        rot_matrix = self.get_rotation_matrix()\n\n        points = points - frame_center\n        points = np.dot(points, rot_matrix.T)\n        zs = points[:, 2]\n        for i in 0, 1:\n            if self.exponential_projection:\n                # Proper projection would involve multiplying\n                # x and y by d / (d-z).  But for points with high\n                # z value that causes weird artifacts, and applying\n                # the exponential helps smooth it out.\n                factor = np.exp(zs / focal_distance)\n                lt0 = zs < 0\n                factor[lt0] = focal_distance / (focal_distance - zs[lt0])\n            else:\n                factor = focal_distance / (focal_distance - zs)\n                factor[(focal_distance - zs) < 0] = 10**6\n            points[:, i] *= factor * zoom\n        return points\n\n    def project_point(self, point: Point3D) -> Point3D:\n        \"\"\"Applies the current rotation_matrix as a projection\n        matrix to the passed point.\n\n        Parameters\n        ----------\n        point\n            The point to project.\n\n        Returns\n        -------\n        np.array\n            The point after projection.\n        \"\"\"\n        return self.project_points(point.reshape((1, 3)))[0, :]\n\n    def transform_points_pre_display(\n        self,\n        mobject: Mobject,\n        points: Point3D_Array,\n    ) -> Point3D_Array:  # TODO: Write Docstrings for this Method.\n        points = super().transform_points_pre_display(mobject, points)\n        fixed_orientation = mobject in self.fixed_orientation_mobjects\n        fixed_in_frame = mobject in self.fixed_in_frame_mobjects\n\n        if fixed_in_frame:\n            return points\n        if fixed_orientation:\n            center_func = self.fixed_orientation_mobjects[mobject]\n            center = center_func()\n            new_center = self.project_point(center)\n            return points + (new_center - center)\n        else:\n            return self.project_points(points)\n\n    def add_fixed_orientation_mobjects(\n        self,\n        *mobjects: Mobject,\n        use_static_center_func: bool = False,\n        center_func: Callable[[], Point3D] | None = None,\n    ) -> None:\n        \"\"\"This method allows the mobject to have a fixed orientation,\n        even when the camera moves around.\n        E.G If it was passed through this method, facing the camera, it\n        will continue to face the camera even as the camera moves.\n        Highly useful when adding labels to graphs and the like.\n\n        Parameters\n        ----------\n        *mobjects\n            The mobject whose orientation must be fixed.\n        use_static_center_func\n            Whether or not to use the function that takes the mobject's\n            center as centerpoint, by default False\n        center_func\n            The function which returns the centerpoint\n            with respect to which the mobject will be oriented, by default None\n        \"\"\"\n\n        # This prevents the computation of mobject.get_center\n        # every single time a projection happens\n        def get_static_center_func(mobject: Mobject) -> Callable[[], Point3D]:\n            point = mobject.get_center()\n            return lambda: point\n\n        for mobject in mobjects:\n            if center_func:\n                func = center_func\n            elif use_static_center_func:\n                func = get_static_center_func(mobject)\n            else:\n                func = mobject.get_center\n            for submob in mobject.get_family():\n                self.fixed_orientation_mobjects[submob] = func\n\n    def add_fixed_in_frame_mobjects(self, *mobjects: Mobject) -> None:\n        \"\"\"This method allows the mobject to have a fixed position,\n        even when the camera moves around.\n        E.G If it was passed through this method, at the top of the frame, it\n        will continue to be displayed at the top of the frame.\n\n        Highly useful when displaying Titles or formulae or the like.\n\n        Parameters\n        ----------\n        **mobjects\n            The mobject to fix in frame.\n        \"\"\"\n        for mobject in extract_mobject_family_members(mobjects):\n            self.fixed_in_frame_mobjects.add(mobject)\n\n    def remove_fixed_orientation_mobjects(self, *mobjects: Mobject) -> None:\n        \"\"\"If a mobject was fixed in its orientation by passing it through\n        :meth:`.add_fixed_orientation_mobjects`, then this undoes that fixing.\n        The Mobject will no longer have a fixed orientation.\n\n        Parameters\n        ----------\n        mobjects\n            The mobjects whose orientation need not be fixed any longer.\n        \"\"\"\n        for mobject in extract_mobject_family_members(mobjects):\n            if mobject in self.fixed_orientation_mobjects:\n                del self.fixed_orientation_mobjects[mobject]\n\n    def remove_fixed_in_frame_mobjects(self, *mobjects: Mobject) -> None:\n        \"\"\"If a mobject was fixed in frame by passing it through\n        :meth:`.add_fixed_in_frame_mobjects`, then this undoes that fixing.\n        The Mobject will no longer be fixed in frame.\n\n        Parameters\n        ----------\n        mobjects\n            The mobjects which need not be fixed in frame any longer.\n        \"\"\"\n        for mobject in extract_mobject_family_members(mobjects):\n            if mobject in self.fixed_in_frame_mobjects:\n                self.fixed_in_frame_mobjects.remove(mobject)\n"
  },
  {
    "path": "manim/cli/__init__.py",
    "content": "\"\"\"The Manim CLI, and the available commands for ``manim``.\n\nThis page is a work in progress. Please run ``manim`` or ``manim --help`` in\nyour terminal to find more information on the following commands.\n\nAvailable commands\n------------------\n\n.. autosummary::\n   :toctree: ../reference\n\n   cfg\n   checkhealth\n   init\n   plugins\n   render\n\"\"\"\n"
  },
  {
    "path": "manim/cli/cfg/__init__.py",
    "content": ""
  },
  {
    "path": "manim/cli/cfg/group.py",
    "content": "\"\"\"Manim's cfg subcommand.\n\nManim's cfg subcommand is accessed in the command-line interface via ``manim\ncfg``. Here you can specify options, subcommands, and subgroups for the cfg\ngroup.\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport contextlib\nfrom ast import literal_eval\nfrom pathlib import Path\nfrom typing import Any, cast\n\nimport cloup\nfrom rich.errors import StyleSyntaxError\nfrom rich.style import Style\n\nfrom manim._config import cli_ctx_settings, console\nfrom manim._config.utils import config_file_paths, make_config_parser\nfrom manim.constants import EPILOG\nfrom manim.utils.file_ops import guarantee_existence, open_file\n\nRICH_COLOUR_INSTRUCTIONS: str = \"\"\"\n[red]The default colour is used by the input statement.\nIf left empty, the default colour will be used.[/red]\n[magenta] For a full list of styles, visit[/magenta] [green]https://rich.readthedocs.io/en/latest/style.html[/green]\n\"\"\"\nRICH_NON_STYLE_ENTRIES: list[str] = [\"log.width\", \"log.height\", \"log.timestamps\"]\n\n__all__ = [\n    \"value_from_string\",\n    \"value_from_string\",\n    \"is_valid_style\",\n    \"replace_keys\",\n    \"cfg\",\n    \"write\",\n    \"show\",\n    \"export\",\n]\n\n\ndef value_from_string(value: str) -> str | int | bool:\n    \"\"\"Extract the literal of proper datatype from a ``value`` string.\n\n    Parameters\n    ----------\n    value\n        The value to check get the literal from.\n\n    Returns\n    -------\n    :class:`str` | :class:`int` | :class:`bool`\n        The literal of appropriate datatype.\n    \"\"\"\n    with contextlib.suppress(SyntaxError, ValueError):\n        value = literal_eval(value)\n    return value\n\n\ndef _is_expected_datatype(\n    value: str, expected: str, validate_style: bool = False\n) -> bool:\n    \"\"\"Check whether the literal from ``value`` is the same datatype as the\n    literal from ``expected``. If ``validate_style`` is ``True``, also check if\n    the style given by ``value`` is valid, according to ``rich``.\n\n    Parameters\n    ----------\n    value\n        The string of the value to check, obtained from reading the user input.\n    expected\n        The string of the literal datatype which must be matched by ``value``.\n        This is obtained from reading the ``cfg`` file.\n    validate_style\n        Whether or not to confirm if ``value`` is a valid style, according to\n        ``rich``. Default is ``False``.\n\n    Returns\n    -------\n    :class:`bool`\n        Whether or not the literal from ``value`` matches the datatype of the\n        literal from ``expected``.\n    \"\"\"\n    value_literal = value_from_string(value)\n    ExpectedLiteralType = type(value_from_string(expected))\n\n    return isinstance(value_literal, ExpectedLiteralType) and (\n        (isinstance(value_literal, str) and is_valid_style(value_literal))\n        if validate_style\n        else True\n    )\n\n\ndef is_valid_style(style: str) -> bool:\n    \"\"\"Checks whether the entered color style is valid, according to ``rich``.\n\n    Parameters\n    ----------\n    style\n        The style to check whether it is valid.\n\n    Returns\n    -------\n    :class:`bool`\n        Whether the color style is valid or not, according to ``rich``.\n    \"\"\"\n    try:\n        Style.parse(style)\n        return True\n    except StyleSyntaxError:\n        return False\n\n\ndef replace_keys(default: dict[str, Any]) -> dict[str, Any]:\n    \"\"\"Replace ``_`` with ``.`` and vice versa in a dictionary's keys for\n    ``rich``.\n\n    Parameters\n    ----------\n    default\n        The dictionary whose keys will be checked and replaced.\n\n    Returns\n    -------\n    :class:`dict`\n        The dictionary whose keys are modified by replacing ``_`` with ``.``\n        and vice versa.\n    \"\"\"\n    for key in default:\n        if \"_\" in key:\n            temp = default[key]\n            del default[key]\n            key = key.replace(\"_\", \".\")\n            default[key] = temp\n        else:\n            temp = default[key]\n            del default[key]\n            key = key.replace(\".\", \"_\")\n            default[key] = temp\n    return default\n\n\n@cloup.group(\n    context_settings=cli_ctx_settings,\n    invoke_without_command=True,\n    no_args_is_help=True,\n    epilog=EPILOG,\n    help=\"Manages Manim configuration files.\",\n)\n@cloup.pass_context\ndef cfg(ctx: cloup.Context) -> None:\n    \"\"\"Responsible for the cfg subcommand.\"\"\"\n    pass\n\n\n@cfg.command(context_settings=cli_ctx_settings, no_args_is_help=True)\n@cloup.option(\n    \"-l\",\n    \"--level\",\n    type=cloup.Choice([\"user\", \"cwd\"], case_sensitive=False),\n    default=\"cwd\",\n    help=\"Specify if this config is for user or the working directory.\",\n)\n@cloup.option(\"-o\", \"--open\", \"openfile\", is_flag=True)\ndef write(level: str | None = None, openfile: bool = False) -> None:\n    config_paths = config_file_paths()\n    console.print(\n        \"[yellow bold]Manim Configuration File Writer[/yellow bold]\",\n        justify=\"center\",\n    )\n\n    USER_CONFIG_MSG = f\"\"\"A configuration file at [yellow]{config_paths[1]}[/yellow] has been created with your required changes.\nThis will be used when running the manim command. If you want to override this config,\nyou will have to create a manim.cfg in the local directory, where you want those changes to be overridden.\"\"\"\n\n    CWD_CONFIG_MSG = f\"\"\"A configuration file at [yellow]{config_paths[2]}[/yellow] has been created.\nTo save your config please save that file and place it in your current working directory, from where you run the manim command.\"\"\"\n\n    parser = make_config_parser()\n    if not openfile:\n        action = \"save this as\"\n        for category in parser:\n            console.print(f\"{category}\", style=\"bold green underline\")\n            default = cast(dict[str, Any], parser[category])\n            if category == \"logger\":\n                console.print(RICH_COLOUR_INSTRUCTIONS)\n                default = replace_keys(default)\n\n            for key in default:\n                # All the cfg entries for logger need to be validated as styles,\n                # as long as they aren't setting the log width or height etc\n                if category == \"logger\" and key not in RICH_NON_STYLE_ENTRIES:\n                    desc = \"style\"\n                    style = default[key]\n                else:\n                    desc = \"value\"\n                    style = None\n\n                console.print(f\"Enter the {desc} for {key} \", style=style, end=\"\")\n                if category != \"logger\" or key in RICH_NON_STYLE_ENTRIES:\n                    defaultval = (\n                        repr(default[key])\n                        if isinstance(value_from_string(default[key]), str)\n                        else default[key]\n                    )\n                    console.print(f\"(defaults to {defaultval}) :\", end=\"\")\n                try:\n                    temp = input()\n                except EOFError:\n                    raise Exception(\n                        \"\"\"Not enough values in input.\nYou may have added a new entry to default.cfg, in which case you will have to\nmodify write_cfg_subcmd_input to account for it.\"\"\",\n                    ) from None\n                if temp:\n                    while temp and not _is_expected_datatype(\n                        temp,\n                        default[key],\n                        bool(style),\n                    ):\n                        console.print(\n                            f\"[red bold]Invalid {desc}. Try again.[/red bold]\",\n                        )\n                        console.print(\n                            f\"Enter the {desc} for {key}:\",\n                            style=style,\n                            end=\"\",\n                        )\n                        temp = input()\n\n                    default[key] = temp.replace(\"%\", \"%%\")\n\n            default = replace_keys(default) if category == \"logger\" else default\n\n            parser[category] = {\n                i: v.replace(\"%\", \"%%\") for i, v in dict(default).items()\n            }\n\n    else:\n        action = \"open\"\n\n    if level is None:\n        console.print(\n            f\"Do you want to {action} the default config for this User?(y/n)[[n]]\",\n            style=\"dim purple\",\n            end=\"\",\n        )\n        action_to_userpath = input()\n    else:\n        action_to_userpath = \"\"\n\n    if action_to_userpath.lower() == \"y\" or level == \"user\":\n        cfg_file_path = config_paths[1]\n        guarantee_existence(config_paths[1].parents[0])\n        console.print(USER_CONFIG_MSG)\n    else:\n        cfg_file_path = config_paths[2]\n        guarantee_existence(config_paths[2].parents[0])\n        console.print(CWD_CONFIG_MSG)\n    with cfg_file_path.open(\"w\") as fp:\n        parser.write(fp)\n    if openfile:\n        open_file(cfg_file_path)\n\n\n@cfg.command(context_settings=cli_ctx_settings)\ndef show() -> None:\n    console.print(\"CONFIG FILES READ\", style=\"bold green underline\")\n    for path in config_file_paths():\n        if path.exists():\n            console.print(f\"{path}\")\n    console.print()\n\n    parser = make_config_parser()\n    rich_non_style_entries = [a.replace(\".\", \"_\") for a in RICH_NON_STYLE_ENTRIES]\n    for category in parser:\n        console.print(f\"{category}\", style=\"bold green underline\")\n        for entry in parser[category]:\n            if category == \"logger\" and entry not in rich_non_style_entries:\n                console.print(f\"{entry} :\", end=\"\")\n                console.print(\n                    f\" {parser[category][entry]}\",\n                    style=parser[category][entry],\n                )\n            else:\n                console.print(f\"{entry} : {parser[category][entry]}\")\n        console.print(\"\\n\")\n\n\n@cfg.command(context_settings=cli_ctx_settings)\n@cloup.option(\"-d\", \"--directory\", default=Path.cwd())\n@cloup.pass_context\ndef export(ctx: cloup.Context, directory: str) -> None:\n    directory_path = Path(directory)\n    if directory_path.absolute == Path.cwd().absolute:\n        console.print(\n            \"\"\"You are reading the config from the same directory you are exporting to.\nThis means that the exported config will overwrite the config for this directory.\nAre you sure you want to continue? (y/n)\"\"\",\n            style=\"red bold\",\n            end=\"\",\n        )\n        proceed = input().lower() == \"y\"\n    else:\n        proceed = True\n    if proceed:\n        if not directory_path.is_dir():\n            console.print(f\"Creating folder: {directory}.\", style=\"red bold\")\n            directory_path.mkdir(parents=True, exist_ok=True)\n\n        ctx.invoke(write)\n        from_path = Path.cwd() / \"manim.cfg\"\n        to_path = directory_path / \"manim.cfg\"\n\n        console.print(f\"Exported final Config at {from_path} to {to_path}.\")\n    else:\n        console.print(\"Aborted...\", style=\"red bold\")\n"
  },
  {
    "path": "manim/cli/checkhealth/__init__.py",
    "content": ""
  },
  {
    "path": "manim/cli/checkhealth/checks.py",
    "content": "\"\"\"Auxiliary module for the checkhealth subcommand, contains\nthe actual check implementations.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport os\nimport shutil\nfrom collections.abc import Callable\nfrom typing import Protocol, cast\n\n__all__ = [\"HEALTH_CHECKS\"]\n\n\nclass HealthCheckFunction(Protocol):\n    description: str\n    recommendation: str\n    skip_on_failed: list[str]\n    post_fail_fix_hook: Callable[..., object] | None\n    __name__: str\n\n    def __call__(self) -> bool: ...\n\n\nHEALTH_CHECKS: list[HealthCheckFunction] = []\n\n\ndef healthcheck(\n    description: str,\n    recommendation: str,\n    skip_on_failed: list[HealthCheckFunction | str] | None = None,\n    post_fail_fix_hook: Callable[..., object] | None = None,\n) -> Callable[[Callable[[], bool]], HealthCheckFunction]:\n    \"\"\"Decorator used for declaring health checks.\n\n    This decorator attaches some data to a function, which is then added to a\n    a list containing all checks.\n\n    Parameters\n    ----------\n    description\n        A brief description of this check, displayed when the ``checkhealth``\n        subcommand is run.\n    recommendation\n        Help text which is displayed in case the check fails.\n    skip_on_failed\n        A list of check functions which, if they fail, cause the current check\n        to be skipped.\n    post_fail_fix_hook\n        A function that is meant to (interactively) help to fix the detected\n        problem, if possible. This is only called upon explicit confirmation of\n        the user.\n\n    Returns\n    -------\n    Callable[Callable[[], bool], :class:`HealthCheckFunction`]\n        A decorator which converts a function into a health check function, as\n        required by the ``checkhealth`` subcommand.\n    \"\"\"\n    new_skip_on_failed: list[str]\n    if skip_on_failed is None:\n        new_skip_on_failed = []\n    else:\n        new_skip_on_failed = [\n            skip.__name__ if callable(skip) else skip for skip in skip_on_failed\n        ]\n\n    def wrapper(func: Callable[[], bool]) -> HealthCheckFunction:\n        health_func = cast(HealthCheckFunction, func)\n        health_func.description = description\n        health_func.recommendation = recommendation\n        health_func.skip_on_failed = new_skip_on_failed\n        health_func.post_fail_fix_hook = post_fail_fix_hook\n        HEALTH_CHECKS.append(health_func)\n        return health_func\n\n    return wrapper\n\n\n@healthcheck(\n    description=\"Checking whether manim is on your PATH\",\n    recommendation=(\n        \"The command <manim> is currently not on your system's PATH.\\n\\n\"\n        \"You can work around this by calling the manim module directly \"\n        \"via <python -m manim> instead of just <manim>.\\n\\n\"\n        \"To fix the PATH issue properly: \"\n        \"Usually, the Python package installer pip issues a warning \"\n        \"during the installation which contains more information. \"\n        \"Consider reinstalling manim via <pip uninstall manim> \"\n        \"followed by <pip install manim> to see the warning again, \"\n        \"then consult the internet on how to modify your system's \"\n        \"PATH variable.\"\n    ),\n)\ndef is_manim_on_path() -> bool:\n    \"\"\"Check whether ``manim`` is in ``PATH``.\n\n    Returns\n    -------\n    :class:`bool`\n        Whether ``manim`` is in ``PATH`` or not.\n    \"\"\"\n    path_to_manim = shutil.which(\"manim\")\n    return path_to_manim is not None\n\n\n@healthcheck(\n    description=\"Checking whether the executable belongs to manim\",\n    recommendation=(\n        \"The command <manim> does not belong to your installed version \"\n        \"of this library, it likely belongs to manimgl / manimlib.\\n\\n\"\n        \"Run manim via <python -m manim> or via <manimce>, or uninstall \"\n        \"and reinstall manim via <pip install --upgrade \"\n        \"--force-reinstall manim> to fix this.\"\n    ),\n    skip_on_failed=[is_manim_on_path],\n)\ndef is_manim_executable_associated_to_this_library() -> bool:\n    \"\"\"Check whether the ``manim`` executable in ``PATH`` is associated to this\n    library. To verify this, the executable should look like this:\n\n    .. code-block:: python\n\n        #!<MANIM_PATH>/.../python\n        import sys\n        from manim.__main__ import main\n\n        if __name__ == \"__main__\":\n            sys.exit(main())\n\n\n    Returns\n    -------\n    :class:`bool`\n        Whether the ``manim`` executable in ``PATH`` is associated to this\n        library or not.\n    \"\"\"\n    path_to_manim = shutil.which(\"manim\")\n    assert path_to_manim is not None\n    with open(path_to_manim, \"rb\") as manim_binary:\n        manim_exec = manim_binary.read()\n\n    # first condition below corresponds to the executable being\n    # some sort of python script. second condition happens when\n    # the executable is actually a Windows batch file.\n    return b\"manim.__main__\" in manim_exec or b'\"%~dp0\\\\manim\"' in manim_exec\n\n\n@healthcheck(\n    description=\"Checking whether latex is available\",\n    recommendation=(\n        \"Manim cannot find <latex> on your system's PATH. \"\n        \"You will not be able to use Tex and MathTex mobjects \"\n        \"in your scenes.\\n\\n\"\n        \"Consult our installation instructions \"\n        \"at https://docs.manim.community/en/stable/installation.html \"\n        \"or search the web for instructions on how to install a \"\n        \"LaTeX distribution on your operating system.\"\n    ),\n)\ndef is_latex_available() -> bool:\n    \"\"\"Check whether ``latex`` is in ``PATH`` and can be executed.\n\n    Returns\n    -------\n    :class:`bool`\n        Whether ``latex`` is in ``PATH`` and can be executed or not.\n    \"\"\"\n    path_to_latex = shutil.which(\"latex\")\n    return path_to_latex is not None and os.access(path_to_latex, os.X_OK)\n\n\n@healthcheck(\n    description=\"Checking whether dvisvgm is available\",\n    recommendation=(\n        \"Manim could find <latex>, but not <dvisvgm> on your system's \"\n        \"PATH. Make sure your installed LaTeX distribution comes with \"\n        \"dvisvgm and consider installing a larger distribution if it \"\n        \"does not.\"\n    ),\n    skip_on_failed=[is_latex_available],\n)\ndef is_dvisvgm_available() -> bool:\n    \"\"\"Check whether ``dvisvgm`` is in ``PATH`` and can be executed.\n\n    Returns\n    -------\n    :class:`bool`\n        Whether ``dvisvgm`` is in ``PATH`` and can be executed or not.\n    \"\"\"\n    path_to_dvisvgm = shutil.which(\"dvisvgm\")\n    return path_to_dvisvgm is not None and os.access(path_to_dvisvgm, os.X_OK)\n"
  },
  {
    "path": "manim/cli/checkhealth/commands.py",
    "content": "\"\"\"A CLI utility helping to diagnose problems with\nyour Manim installation.\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport sys\nimport timeit\n\nimport click\nimport cloup\n\nfrom manim.cli.checkhealth.checks import HEALTH_CHECKS, HealthCheckFunction\n\n__all__ = [\"checkhealth\"]\n\n\n@cloup.command(\n    context_settings=None,\n)\ndef checkhealth() -> None:\n    \"\"\"This subcommand checks whether Manim is installed correctly\n    and has access to its required (and optional) system dependencies.\n    \"\"\"\n    click.echo(f\"Python executable: {sys.executable}\\n\")\n    click.echo(\"Checking whether your installation of Manim Community is healthy...\")\n    failed_checks: list[HealthCheckFunction] = []\n\n    for check in HEALTH_CHECKS:\n        click.echo(f\"- {check.description} ... \", nl=False)\n        if any(\n            failed_check.__name__ in check.skip_on_failed\n            for failed_check in failed_checks\n        ):\n            click.secho(\"SKIPPED\", fg=\"blue\")\n            continue\n        check_result = check()\n        if check_result:\n            click.secho(\"PASSED\", fg=\"green\")\n        else:\n            click.secho(\"FAILED\", fg=\"red\")\n            failed_checks.append(check)\n\n    click.echo()\n\n    if failed_checks:\n        click.echo(\n            \"There are problems with your installation, \"\n            \"here are some recommendations to fix them:\"\n        )\n        for ind, failed_check in enumerate(failed_checks):\n            click.echo(failed_check.recommendation)\n            if ind + 1 < len(failed_checks):\n                click.confirm(\"Continue with next recommendation?\")\n\n    else:  # no problems detected!\n        click.echo(\"No problems detected, your installation seems healthy!\")\n        render_test_scene = click.confirm(\n            \"Would you like to render and preview a test scene?\"\n        )\n        if render_test_scene:\n            import manim as mn\n\n            class CheckHealthDemo(mn.Scene):\n                def _inner_construct(self) -> None:\n                    banner = mn.ManimBanner().shift(mn.UP * 0.5)\n                    self.play(banner.create())\n                    self.wait(0.5)\n                    self.play(banner.expand())\n                    self.wait(0.5)\n                    text_left = mn.Text(\"All systems operational!\")\n                    formula_right = mn.MathTex(r\"\\oint_{\\gamma} f(z)~dz = 0\")\n                    text_tex_group = mn.VGroup(text_left, formula_right)\n                    text_tex_group.arrange(mn.RIGHT, buff=1).next_to(banner, mn.DOWN)\n                    self.play(mn.Write(text_tex_group))\n                    self.wait(0.5)\n                    self.play(\n                        mn.FadeOut(banner, shift=mn.UP),\n                        mn.FadeOut(text_tex_group, shift=mn.DOWN),\n                    )\n\n                def construct(self) -> None:\n                    self.execution_time = timeit.timeit(self._inner_construct, number=1)\n\n            with mn.tempconfig({\"preview\": True, \"disable_caching\": True}):\n                scene = CheckHealthDemo()\n                scene.render()\n\n                click.echo(f\"Scene rendered in {scene.execution_time:.2f} seconds.\")\n"
  },
  {
    "path": "manim/cli/default_group.py",
    "content": "\"\"\"``DefaultGroup`` allows a subcommand to act as the main command.\n\nIn particular, this class is what allows ``manim`` to act as ``manim render``.\n\n.. note::\n    This is a vendored version of https://github.com/click-contrib/click-default-group/\n    under the BSD 3-Clause \"New\" or \"Revised\" License.\n\n    This library isn't used as a dependency, as we need to inherit from\n    :class:`cloup.Group` instead of :class:`click.Group`.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport warnings\nfrom collections.abc import Callable\nfrom typing import TYPE_CHECKING, Any\n\nimport cloup\n\nfrom manim.utils.deprecation import deprecated\n\n__all__ = [\"DefaultGroup\"]\n\nif TYPE_CHECKING:\n    from click import Command, Context\n\n\nclass DefaultGroup(cloup.Group):\n    \"\"\"Invokes a subcommand marked with ``default=True`` if any subcommand is not\n    chosen.\n\n    Parameters\n    ----------\n    *args\n        Positional arguments to forward to :class:`cloup.Group`.\n    **kwargs\n        Keyword arguments to forward to :class:`cloup.Group`. The keyword\n        ``ignore_unknown_options`` must be set to ``False``.\n\n    Attributes\n    ----------\n    default_cmd_name : str | None\n        The name of the default command, if specified through the ``default``\n        keyword argument. Otherwise, this is set to ``None``.\n    default_if_no_args : bool\n        Whether to include or not the default command, if no command arguments\n        are supplied. This can be specified through the ``default_if_no_args``\n        keyword argument. Default is ``False``.\n    \"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any):\n        # To resolve as the default command.\n        if not kwargs.get(\"ignore_unknown_options\", True):\n            raise ValueError(\"Default group accepts unknown options\")\n        self.ignore_unknown_options = True\n        self.default_cmd_name: str | None = kwargs.pop(\"default\", None)\n        self.default_if_no_args: bool = kwargs.pop(\"default_if_no_args\", False)\n        super().__init__(*args, **kwargs)\n\n    def set_default_command(self, command: Command) -> None:\n        \"\"\"Sets a command function as the default command.\n\n        Parameters\n        ----------\n        command\n            The command to set as default.\n        \"\"\"\n        cmd_name = command.name\n        self.add_command(command)\n        self.default_cmd_name = cmd_name\n\n    def parse_args(self, ctx: Context, args: list[str]) -> list[str]:\n        \"\"\"Parses the list of ``args`` by forwarding it to\n        :meth:`cloup.Group.parse_args`. Before doing so, if\n        :attr:`default_if_no_args` is set to ``True`` and ``args`` is empty,\n        this function appends to it the name of the default command specified\n        by :attr:`default_cmd_name`.\n\n        Parameters\n        ----------\n        ctx\n            The Click context.\n        args\n            A list of arguments. If it's empty and :attr:`default_if_no_args`\n            is ``True``, append the name of the default command to it.\n\n        Returns\n        -------\n        list[str]\n            The parsed arguments.\n        \"\"\"\n        if not args and self.default_if_no_args and self.default_cmd_name:\n            args.insert(0, self.default_cmd_name)\n        parsed_args: list[str] = super().parse_args(ctx, args)\n        return parsed_args\n\n    def get_command(self, ctx: Context, cmd_name: str) -> Command | None:\n        \"\"\"Get a command function by its name, by forwarding the arguments to\n        :meth:`cloup.Group.get_command`. If ``cmd_name`` does not match any of\n        the command names in :attr:`commands`, attempt to get the default command\n        instead.\n\n        Parameters\n        ----------\n        ctx\n            The Click context.\n        cmd_name\n            The name of the command to get.\n\n        Returns\n        -------\n        :class:`click.Command` | None\n            The command, if found. Otherwise, ``None``.\n        \"\"\"\n        if cmd_name not in self.commands and self.default_cmd_name:\n            # No command name matched.\n            ctx.meta[\"arg0\"] = cmd_name\n            cmd_name = self.default_cmd_name\n        return super().get_command(ctx, cmd_name)\n\n    def resolve_command(\n        self, ctx: Context, args: list[str]\n    ) -> tuple[str | None, Command | None, list[str]]:\n        \"\"\"Given a list of ``args`` given by a CLI, find a command which\n        matches the first element, and return its name (``cmd_name``), the\n        command function itself (``cmd``) and the rest of the arguments which\n        shall be passed to the function (``cmd_args``). If not found, return\n        ``None``, ``None`` and the rest of the arguments.\n\n        After resolving the command, if the Click context given by ``ctx``\n        contains an ``arg0`` attribute in its :attr:`click.Context.meta`\n        dictionary, insert it as the first element of the returned\n        ``cmd_args``.\n\n        Parameters\n        ----------\n        ctx\n            The Click context.\n        cmd_name\n            The name of the command to get.\n\n        Returns\n        -------\n        cmd_name : str | None\n            The command name, if found. Otherwise, ``None``.\n        cmd : :class:`click.Command` | None\n            The command, if found. Otherwise, ``None``.\n        cmd_args : list[str]\n            The rest of the arguments to be passed to ``cmd``.\n        \"\"\"\n        cmd_name, cmd, args = super().resolve_command(ctx, args)\n        if \"arg0\" in ctx.meta:\n            args.insert(0, ctx.meta[\"arg0\"])\n            if cmd is not None:\n                cmd_name = cmd.name\n        return cmd_name, cmd, args\n\n    @deprecated\n    def command(\n        self, *args: Any, **kwargs: Any\n    ) -> Callable[[Callable[..., object]], Command]:\n        \"\"\"Return a decorator which converts any function into the default\n        subcommand for this :class:`DefaultGroup`.\n\n        .. warning::\n            This method is deprecated. Use the ``default`` parameter of\n            :class:`DefaultGroup` or :meth:`set_default_command` instead.\n\n        Parameters\n        ----------\n        *args\n            Positional arguments to pass to :meth:`cloup.Group.command`.\n        **kwargs\n            Keyword arguments to pass to :meth:`cloup.Group.command`.\n\n        Returns\n        -------\n        Callable[[Callable[..., object]], click.Command]\n            A decorator which transforms its input into this\n            :class:`DefaultGroup`'s default subcommand.\n        \"\"\"\n        default = kwargs.pop(\"default\", False)\n        decorator: Callable[[Callable[..., object]], Command] = super().command(\n            *args, **kwargs\n        )\n        if not default:\n            return decorator\n        warnings.warn(\n            \"Use default param of DefaultGroup or set_default_command() instead\",\n            DeprecationWarning,\n            stacklevel=1,\n        )\n\n        def _decorator(f: Callable) -> Command:\n            cmd = decorator(f)\n            self.set_default_command(cmd)\n            return cmd\n\n        return _decorator\n"
  },
  {
    "path": "manim/cli/init/__init__.py",
    "content": ""
  },
  {
    "path": "manim/cli/init/commands.py",
    "content": "\"\"\"Manim's init subcommand.\n\nManim's init subcommand is accessed in the command-line interface via ``manim\ninit``. Here you can specify options, subcommands, and subgroups for the init\ngroup.\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport configparser\nfrom pathlib import Path\nfrom typing import Any\n\nimport click\nimport cloup\n\nfrom manim._config import console\nfrom manim.constants import CONTEXT_SETTINGS, EPILOG, QUALITIES\nfrom manim.utils.file_ops import (\n    add_import_statement,\n    copy_template_files,\n    get_template_names,\n    get_template_path,\n)\n\nCFG_DEFAULTS = {\n    \"frame_rate\": 30,\n    \"background_color\": \"BLACK\",\n    \"background_opacity\": 1,\n    \"scene_names\": \"Default\",\n    \"resolution\": (1920, 1080),\n}\n\n__all__ = [\"select_resolution\", \"update_cfg\", \"project\", \"scene\"]\n\n\ndef select_resolution() -> tuple[int, int]:\n    \"\"\"Prompts input of type click.Choice from user. Presents options from QUALITIES constant.\n\n    Returns\n    -------\n    tuple[int, int]\n        Tuple containing height and width.\n    \"\"\"\n    resolution_options: list[tuple[int, int]] = [\n        (quality[1][\"pixel_height\"], quality[1][\"pixel_width\"])\n        for quality in QUALITIES.items()\n    ]\n    resolution_options.pop()\n    choice = click.prompt(\n        \"\\nSelect resolution:\\n\",\n        type=cloup.Choice([f\"{i[0]}p\" for i in resolution_options]),\n        show_default=False,\n        default=\"480p\",\n    )\n    matches = [res for res in resolution_options if f\"{res[0]}p\" == choice]\n    return matches[0]\n\n\ndef update_cfg(cfg_dict: dict[str, Any], project_cfg_path: Path) -> None:\n    \"\"\"Update the ``manim.cfg`` file after reading it from the specified\n    ``project_cfg_path``.\n\n    Parameters\n    ----------\n    cfg_dict\n        Values used to update ``manim.cfg`` which is found in\n        ``project_cfg_path``.\n    project_cfg_path\n        Path of the ``manim.cfg`` file.\n    \"\"\"\n    config = configparser.ConfigParser()\n    config.read(project_cfg_path)\n    cli_config = config[\"CLI\"]\n    for key, value in cfg_dict.items():\n        if key == \"resolution\":\n            cli_config[\"pixel_height\"] = str(value[0])\n            cli_config[\"pixel_width\"] = str(value[1])\n        else:\n            cli_config[key] = str(value)\n\n    with project_cfg_path.open(\"w\") as conf:\n        config.write(conf)\n\n\n@cloup.command(\n    context_settings=CONTEXT_SETTINGS,\n    epilog=EPILOG,\n)\n@cloup.argument(\"project_name\", type=cloup.Path(path_type=Path), required=False)\n@cloup.option(\n    \"-d\",\n    \"--default\",\n    \"default_settings\",\n    is_flag=True,\n    help=\"Default settings for project creation.\",\n    nargs=1,\n)\ndef project(default_settings: bool, **kwargs: Any) -> None:\n    \"\"\"Creates a new project.\n\n    PROJECT_NAME is the name of the folder in which the new project will be initialized.\n    \"\"\"\n    project_name: Path\n    if kwargs[\"project_name\"]:\n        project_name = kwargs[\"project_name\"]\n    else:\n        project_name = click.prompt(\"Project Name\", type=Path)\n\n    # in the future when implementing a full template system. Choices are going to be saved in some sort of config file for templates\n    template_name = click.prompt(\n        \"Template\",\n        type=click.Choice(get_template_names(), False),\n        default=\"Default\",\n    )\n\n    if project_name.is_dir():\n        console.print(\n            f\"\\nFolder [red]{project_name}[/red] exists. Please type another name\\n\",\n        )\n    else:\n        project_name.mkdir()\n        new_cfg: dict[str, Any] = {}\n        new_cfg_path = Path.resolve(project_name / \"manim.cfg\")\n\n        if not default_settings:\n            for key, value in CFG_DEFAULTS.items():\n                if key == \"scene_names\":\n                    new_cfg[key] = template_name + \"Template\"\n                elif key == \"resolution\":\n                    new_cfg[key] = select_resolution()\n                else:\n                    new_cfg[key] = click.prompt(f\"\\n{key}\", default=value)\n\n            console.print(\"\\n\", new_cfg)\n            if click.confirm(\"Do you want to continue?\", default=True, abort=True):\n                copy_template_files(project_name, template_name)\n                update_cfg(new_cfg, new_cfg_path)\n        else:\n            copy_template_files(project_name, template_name)\n            update_cfg(CFG_DEFAULTS, new_cfg_path)\n\n\n@cloup.command(\n    context_settings=CONTEXT_SETTINGS,\n    no_args_is_help=True,\n    epilog=EPILOG,\n)\n@cloup.argument(\"scene_name\", type=str, required=True)\n@cloup.argument(\"file_name\", type=str, required=False)\ndef scene(**kwargs: Any) -> None:\n    \"\"\"Inserts a SCENE to an existing FILE or creates a new FILE.\n\n    SCENE is the name of the scene that will be inserted.\n\n    FILE is the name of file in which the SCENE will be inserted.\n    \"\"\"\n    template_name: str = click.prompt(\n        \"template\",\n        type=click.Choice(get_template_names(), False),\n        default=\"Default\",\n    )\n    scene = (get_template_path() / f\"{template_name}.mtp\").resolve().read_text()\n    scene = scene.replace(template_name + \"Template\", kwargs[\"scene_name\"], 1)\n\n    if kwargs[\"file_name\"]:\n        file_name = Path(kwargs[\"file_name\"])\n\n        if file_name.suffix != \".py\":\n            file_name = file_name.with_suffix(file_name.suffix + \".py\")\n\n        if file_name.is_file():\n            # file exists so we are going to append new scene to that file\n            with file_name.open(\"a\") as f:\n                f.write(\"\\n\\n\\n\" + scene)\n        else:\n            # file does not exist so we create a new file, append the scene and prepend the import statement\n            file_name.write_text(\"\\n\\n\\n\" + scene)\n\n            add_import_statement(file_name)\n    else:\n        # file name is not provided so we assume it is main.py\n        # if main.py does not exist we do not continue\n        with Path(\"main.py\").open(\"a\") as f:\n            f.write(\"\\n\\n\\n\" + scene)\n\n\n@cloup.group(\n    context_settings=CONTEXT_SETTINGS,\n    invoke_without_command=True,\n    no_args_is_help=True,\n    epilog=EPILOG,\n    help=\"Create a new project or insert a new scene.\",\n)\n@cloup.pass_context\ndef init(ctx: cloup.Context) -> None:\n    pass\n\n\ninit.add_command(project)\ninit.add_command(scene)\n"
  },
  {
    "path": "manim/cli/plugins/__init__.py",
    "content": ""
  },
  {
    "path": "manim/cli/plugins/commands.py",
    "content": "\"\"\"Manim's plugin subcommand.\n\nManim's plugin subcommand is accessed in the command-line interface via ``manim\nplugin``. Here you can specify options, subcommands, and subgroups for the plugin\ngroup.\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport cloup\n\nfrom manim.constants import CONTEXT_SETTINGS, EPILOG\nfrom manim.plugins.plugins_flags import list_plugins\n\n__all__ = [\"plugins\"]\n\n\n@cloup.command(\n    context_settings=CONTEXT_SETTINGS,\n    no_args_is_help=True,\n    epilog=EPILOG,\n    help=\"Manages Manim plugins.\",\n)\n@cloup.option(\n    \"-l\",\n    \"--list\",\n    \"list_available\",\n    is_flag=True,\n    help=\"List available plugins.\",\n)\ndef plugins(list_available: bool) -> None:\n    \"\"\"Print a list of all available plugins when calling ``manim plugins -l``\n    or ``manim plugins --list``.\n\n    Parameters\n    ----------\n    list_available\n        If the ``-l`` or ``-list`` option is passed to ``manim plugins``, this\n        parameter will be set to ``True``, which will print a list of all\n        available plugins.\n    \"\"\"\n    if list_available:\n        list_plugins()\n"
  },
  {
    "path": "manim/cli/render/__init__.py",
    "content": ""
  },
  {
    "path": "manim/cli/render/commands.py",
    "content": "\"\"\"Manim's default subcommand, render.\n\nManim's render subcommand is accessed in the command-line interface via\n``manim``, but can be more explicitly accessed with ``manim render``. Here you\ncan specify options, and arguments for the render command.\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport http.client\nimport json\nimport sys\nimport urllib.error\nimport urllib.request\nfrom argparse import Namespace\nfrom pathlib import Path\nfrom typing import Any, cast\n\nimport cloup\n\nfrom manim import __version__\nfrom manim._config import (\n    config,\n    console,\n    error_console,\n    logger,\n    tempconfig,\n)\nfrom manim.cli.render.ease_of_access_options import ease_of_access_options\nfrom manim.cli.render.global_options import global_options\nfrom manim.cli.render.output_options import output_options\nfrom manim.cli.render.render_options import render_options\nfrom manim.constants import EPILOG, RendererType\nfrom manim.utils.module_ops import scene_classes_from_file\n\n__all__ = [\"render\"]\n\n\nclass ClickArgs(Namespace):\n    def __init__(self, args: dict[str, Any]) -> None:\n        for name in args:\n            setattr(self, name, args[name])\n\n    def _get_kwargs(self) -> list[tuple[str, Any]]:\n        return list(self.__dict__.items())\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, ClickArgs):\n            return NotImplemented\n        return vars(self) == vars(other)\n\n    def __contains__(self, key: str) -> bool:\n        return key in self.__dict__\n\n    def __repr__(self) -> str:\n        return str(self.__dict__)\n\n\n@cloup.command(\n    context_settings=None,\n    no_args_is_help=True,\n    epilog=EPILOG,\n)\n@cloup.argument(\"file\", type=cloup.Path(path_type=Path), required=True)\n@cloup.argument(\"scene_names\", required=False, nargs=-1)\n@global_options\n@output_options\n@render_options\n@ease_of_access_options\ndef render(**kwargs: Any) -> ClickArgs | dict[str, Any]:\n    \"\"\"Render SCENE(S) from the input FILE.\n\n    FILE is the file path of the script or a config file.\n\n    SCENES is an optional list of scenes in the file.\n    \"\"\"\n    if kwargs[\"save_as_gif\"]:\n        logger.warning(\"--save_as_gif is deprecated, please use --format=gif instead!\")\n        kwargs[\"format\"] = \"gif\"\n\n    if kwargs[\"save_pngs\"]:\n        logger.warning(\"--save_pngs is deprecated, please use --format=png instead!\")\n        kwargs[\"format\"] = \"png\"\n\n    if kwargs[\"show_in_file_browser\"]:\n        logger.warning(\n            \"The short form of show_in_file_browser is deprecated and will be moved to support --format.\",\n        )\n\n    click_args = ClickArgs(kwargs)\n    if kwargs[\"jupyter\"]:\n        return click_args\n\n    config.digest_args(click_args)\n    file = Path(config.input_file)\n    if config.renderer == RendererType.OPENGL:\n        from manim.renderer.opengl_renderer import OpenGLRenderer\n\n        try:\n            renderer = OpenGLRenderer()\n            keep_running = True\n            while keep_running:\n                for SceneClass in scene_classes_from_file(file):\n                    with tempconfig({}):\n                        scene = SceneClass(renderer)\n                        rerun = scene.render()\n                    if rerun or config[\"write_all\"]:\n                        renderer.num_plays = 0\n                        continue\n                    else:\n                        keep_running = False\n                        break\n                if config[\"write_all\"]:\n                    keep_running = False\n\n        except Exception:\n            error_console.print_exception()\n            sys.exit(1)\n    else:\n        for SceneClass in scene_classes_from_file(file):\n            try:\n                with tempconfig({}):\n                    scene = SceneClass()\n                    scene.render()\n            except Exception:\n                error_console.print_exception()\n                sys.exit(1)\n\n    if config.notify_outdated_version:\n        manim_info_url = \"https://pypi.org/pypi/manim/json\"\n        warn_prompt = \"Cannot check if latest release of manim is installed\"\n\n        try:\n            with urllib.request.urlopen(\n                urllib.request.Request(manim_info_url),\n                timeout=10,\n            ) as response:\n                response = cast(http.client.HTTPResponse, response)\n                json_data = json.loads(response.read())\n        except urllib.error.HTTPError:\n            logger.debug(\"HTTP Error: %s\", warn_prompt)\n        except urllib.error.URLError:\n            logger.debug(\"URL Error: %s\", warn_prompt)\n        except json.JSONDecodeError:\n            logger.debug(\n                \"Error while decoding JSON from %r: %s\", manim_info_url, warn_prompt\n            )\n        except Exception:\n            logger.debug(\"Something went wrong: %s\", warn_prompt)\n        else:\n            stable = json_data[\"info\"][\"version\"]\n            if stable != __version__:\n                console.print(\n                    f\"You are using manim version [red]v{__version__}[/red], but version [green]v{stable}[/green] is available.\",\n                )\n                console.print(\n                    \"You should consider upgrading via [yellow]pip install -U manim[/yellow]\",\n                )\n\n    return kwargs\n"
  },
  {
    "path": "manim/cli/render/ease_of_access_options.py",
    "content": "from __future__ import annotations\n\nfrom cloup import Choice, option, option_group\n\n__all__ = [\"ease_of_access_options\"]\n\nease_of_access_options = option_group(\n    \"Ease of access options\",\n    option(\n        \"--progress_bar\",\n        default=None,\n        show_default=False,\n        type=Choice(\n            [\"display\", \"leave\", \"none\"],\n            case_sensitive=False,\n        ),\n        help=\"Display progress bars and/or keep them displayed.\",\n    ),\n    option(\n        \"-p\",\n        \"--preview\",\n        is_flag=True,\n        help=\"Preview the Scene's animation. OpenGL does a live preview in a \"\n        \"popup window. Cairo opens the rendered video file in the system \"\n        \"default media player.\",\n        default=None,\n    ),\n    option(\n        \"-f\",\n        \"--show_in_file_browser\",\n        is_flag=True,\n        help=\"Show the output file in the file browser.\",\n        default=None,\n    ),\n    option(\n        \"--jupyter\",\n        is_flag=True,\n        help=\"Using jupyter notebook magic.\",\n        default=None,\n    ),\n)\n"
  },
  {
    "path": "manim/cli/render/global_options.py",
    "content": "from __future__ import annotations\n\nimport logging\nimport re\nimport sys\nfrom typing import TYPE_CHECKING\n\nfrom cloup import Choice, option, option_group\n\nif TYPE_CHECKING:\n    from click import Context, Option\n\n__all__ = [\"global_options\"]\n\nlogger = logging.getLogger(\"manim\")\n\n\ndef validate_gui_location(\n    ctx: Context, param: Option, value: str | None\n) -> tuple[int, int] | None:\n    \"\"\"If the ``value`` string is given, extract from it the GUI location,\n    which should be in any of these formats: 'x;y', 'x,y' or 'x-y'.\n\n    Parameters\n    ----------\n    ctx\n        The Click context.\n    param\n        A Click option.\n    value\n        The optional string which will be parsed.\n\n    Returns\n    -------\n    tuple[int, int] | None\n        If ``value`` is ``None``, the return value is ``None``. Otherwise, it's\n        the ``(x, y)`` location for the GUI.\n\n    Raises\n    ------\n    ValueError\n        If ``value`` has an invalid format.\n    \"\"\"\n    if value is None:\n        return None\n\n    try:\n        x_offset, y_offset = map(int, re.split(r\"[;,\\-]\", value))\n    except Exception:\n        logger.error(\"GUI location option is invalid.\")\n        sys.exit()\n\n    return (x_offset, y_offset)\n\n\nglobal_options = option_group(\n    \"Global options\",\n    option(\n        \"-c\",\n        \"--config_file\",\n        help=\"Specify the configuration file to use for render settings.\",\n        default=None,\n    ),\n    option(\n        \"--custom_folders\",\n        is_flag=True,\n        default=None,\n        help=\"Use the folders defined in the [custom_folders] section of the \"\n        \"config file to define the output folder structure.\",\n    ),\n    option(\n        \"--disable_caching\",\n        is_flag=True,\n        default=None,\n        help=\"Disable the use of the cache (still generates cache files).\",\n    ),\n    option(\n        \"--flush_cache\",\n        is_flag=True,\n        help=\"Remove cached partial movie files.\",\n        default=None,\n    ),\n    option(\"--tex_template\", help=\"Specify a custom TeX template file.\", default=None),\n    option(\n        \"-v\",\n        \"--verbosity\",\n        type=Choice(\n            [\"DEBUG\", \"INFO\", \"WARNING\", \"ERROR\", \"CRITICAL\"],\n            case_sensitive=False,\n        ),\n        help=\"Verbosity of CLI output. Changes ffmpeg log level unless 5+.\",\n        default=None,\n    ),\n    option(\n        \"--notify_outdated_version/--silent\",\n        is_flag=True,\n        default=None,\n        help=\"Display warnings for outdated installation.\",\n    ),\n    option(\n        \"--enable_gui\",\n        is_flag=True,\n        help=\"Enable GUI interaction.\",\n        default=None,\n    ),\n    option(\n        \"--gui_location\",\n        default=None,\n        callback=validate_gui_location,\n        help=\"Starting location for the GUI.\",\n    ),\n    option(\n        \"--fullscreen\",\n        is_flag=True,\n        help=\"Expand the window to its maximum possible size.\",\n        default=None,\n    ),\n    option(\n        \"--enable_wireframe\",\n        is_flag=True,\n        help=\"Enable wireframe debugging mode in opengl.\",\n        default=None,\n    ),\n    option(\n        \"--force_window\",\n        is_flag=True,\n        help=\"Force window to open when using the opengl renderer, intended for debugging as it may impact performance\",\n        default=None,\n    ),\n    option(\n        \"--dry_run\",\n        is_flag=True,\n        help=\"Renders animations without outputting image or video files and disables the window\",\n        default=None,\n    ),\n    option(\n        \"--no_latex_cleanup\",\n        is_flag=True,\n        help=\"Prevents deletion of .aux, .dvi, and .log files produced by Tex and MathTex.\",\n        default=None,\n    ),\n    option(\n        \"--preview_command\",\n        help=\"The command used to preview the output file (for example vlc for video files)\",\n        default=None,\n    ),\n    option(\n        \"--seed\",\n        type=int,\n        help=\"Set the random seed to allow reproducibility.\",\n        default=None,\n    ),\n)\n"
  },
  {
    "path": "manim/cli/render/output_options.py",
    "content": "from __future__ import annotations\n\nfrom cloup import IntRange, Path, option, option_group\n\n__all__ = [\"output_options\"]\n\noutput_options = option_group(\n    \"Output options\",\n    option(\n        \"-o\",\n        \"--output_file\",\n        type=str,\n        default=None,\n        help=\"Specify the filename(s) of the rendered scene(s).\",\n    ),\n    option(\n        \"-0\",\n        \"--zero_pad\",\n        type=IntRange(0, 9),\n        default=None,\n        help=\"Zero padding for PNG file names.\",\n    ),\n    option(\n        \"--write_to_movie\",\n        is_flag=True,\n        default=None,\n        help=\"Write the video rendered with opengl to a file.\",\n    ),\n    option(\n        \"--media_dir\",\n        type=Path(),\n        default=None,\n        help=\"Path to store rendered videos and latex.\",\n    ),\n    option(\n        \"--log_dir\",\n        type=Path(),\n        help=\"Path to store render logs.\",\n        default=None,\n    ),\n    option(\n        \"--log_to_file\",\n        is_flag=True,\n        default=None,\n        help=\"Log terminal output to file.\",\n    ),\n)\n"
  },
  {
    "path": "manim/cli/render/render_options.py",
    "content": "from __future__ import annotations\n\nimport logging\nimport re\nimport sys\nfrom typing import TYPE_CHECKING\n\nfrom cloup import Choice, option, option_group\n\nfrom manim.constants import QUALITIES, RendererType\n\nif TYPE_CHECKING:\n    from click import Context, Option\n\n__all__ = [\"render_options\"]\n\nlogger = logging.getLogger(\"manim\")\n\n\ndef validate_scene_range(\n    ctx: Context, param: Option, value: str | None\n) -> tuple[int] | tuple[int, int] | None:\n    \"\"\"If the ``value`` string is given, extract from it the scene range, which\n    should be in any of these formats: 'start', 'start;end', 'start,end' or\n    'start-end'. Otherwise, return ``None``.\n\n    Parameters\n    ----------\n    ctx\n        The Click context.\n    param\n        A Click option.\n    value\n        The optional string which will be parsed.\n\n    Returns\n    -------\n    tuple[int] | tuple[int, int] | None\n        If ``value`` is ``None``, the return value is ``None``. Otherwise, it's\n        the scene range, given by a tuple which may contain a single value\n        ``start`` or two values ``start`` and ``end``.\n\n    Raises\n    ------\n    ValueError\n        If ``value`` has an invalid format.\n    \"\"\"\n    if value is None:\n        return None\n\n    try:\n        start = int(value)\n        return (start,)\n    except Exception:\n        pass\n\n    try:\n        start, end = map(int, re.split(r\"[;,\\-]\", value))\n    except Exception:\n        logger.error(\"Couldn't determine a range for -n option.\")\n        sys.exit()\n\n    return start, end\n\n\ndef validate_resolution(\n    ctx: Context, param: Option, value: str | None\n) -> tuple[int, int] | None:\n    \"\"\"If the ``value`` string is given, extract from it the resolution, which\n    should be in any of these formats: 'W;H', 'W,H' or 'W-H'. Otherwise, return\n    ``None``.\n\n    Parameters\n    ----------\n    ctx\n        The Click context.\n    param\n        A Click option.\n    value\n        The optional string which will be parsed.\n\n    Returns\n    -------\n    tuple[int, int] | None\n        If ``value`` is ``None``, the return value is ``None``. Otherwise, it's\n        the resolution as a ``(W, H)`` tuple.\n\n    Raises\n    ------\n    ValueError\n        If ``value`` has an invalid format.\n    \"\"\"\n    if value is None:\n        return None\n\n    try:\n        width, height = map(int, re.split(r\"[;,\\-]\", value))\n    except Exception:\n        logger.error(\"Resolution option is invalid.\")\n        sys.exit()\n\n    return width, height\n\n\nrender_options = option_group(\n    \"Render Options\",\n    option(\n        \"-n\",\n        \"--from_animation_number\",\n        callback=validate_scene_range,\n        help=\"Start rendering from n_0 until n_1. If n_1 is left unspecified, \"\n        \"renders all scenes after n_0.\",\n        default=None,\n    ),\n    option(\n        \"-a\",\n        \"--write_all\",\n        is_flag=True,\n        help=\"Render all scenes in the input file.\",\n        default=None,\n    ),\n    option(\n        \"--format\",\n        type=Choice([\"png\", \"gif\", \"mp4\", \"webm\", \"mov\"], case_sensitive=False),\n        default=None,\n    ),\n    option(\n        \"-s\",\n        \"--save_last_frame\",\n        default=None,\n        is_flag=True,\n        help=\"Render and save only the last frame of a scene as a PNG image.\",\n    ),\n    option(\n        \"-q\",\n        \"--quality\",\n        default=None,\n        type=Choice(\n            list(reversed([q[\"flag\"] for q in QUALITIES.values() if q[\"flag\"]])),\n            case_sensitive=False,\n        ),\n        help=\"Render quality at the follow resolution framerates, respectively: \"\n        + \", \".join(\n            reversed(\n                [\n                    f\"{q['pixel_width']}x{q['pixel_height']} {q['frame_rate']}FPS\"\n                    for q in QUALITIES.values()\n                    if q[\"flag\"]\n                ]\n            )\n        ),\n    ),\n    option(\n        \"-r\",\n        \"--resolution\",\n        callback=validate_resolution,\n        default=None,\n        help='Resolution in \"W,H\" for when 16:9 aspect ratio isn\\'t possible.',\n    ),\n    option(\n        \"--fps\",\n        \"--frame_rate\",\n        \"frame_rate\",\n        type=float,\n        default=None,\n        help=\"Render at this frame rate.\",\n    ),\n    option(\n        \"--renderer\",\n        type=Choice(\n            [renderer_type.value for renderer_type in RendererType],\n            case_sensitive=False,\n        ),\n        help=\"Select a renderer for your Scene.\",\n        default=\"cairo\",\n    ),\n    option(\n        \"-g\",\n        \"--save_pngs\",\n        is_flag=True,\n        default=None,\n        help=\"Save each frame as png (Deprecated).\",\n    ),\n    option(\n        \"-i\",\n        \"--save_as_gif\",\n        default=None,\n        is_flag=True,\n        help=\"Save as a gif (Deprecated).\",\n    ),\n    option(\n        \"--save_sections\",\n        default=None,\n        is_flag=True,\n        help=\"Save section videos in addition to movie file.\",\n    ),\n    option(\n        \"-t\",\n        \"--transparent\",\n        is_flag=True,\n        help=\"Render scenes with alpha channel.\",\n    ),\n    option(\n        \"--use_projection_fill_shaders\",\n        is_flag=True,\n        help=\"Use shaders for OpenGLVMobject fill which are compatible with transformation matrices.\",\n        default=None,\n    ),\n    option(\n        \"--use_projection_stroke_shaders\",\n        is_flag=True,\n        help=\"Use shaders for OpenGLVMobject stroke which are compatible with transformation matrices.\",\n        default=None,\n    ),\n)\n"
  },
  {
    "path": "manim/constants.py",
    "content": "\"\"\"Constant definitions.\"\"\"\n\nfrom __future__ import annotations\n\nfrom enum import Enum\nfrom typing import TypedDict\n\nimport numpy as np\nfrom cloup import Context\nfrom PIL.Image import Resampling\n\nfrom manim.typing import Vector3D\n\n__all__ = [\n    \"SCENE_NOT_FOUND_MESSAGE\",\n    \"CHOOSE_NUMBER_MESSAGE\",\n    \"INVALID_NUMBER_MESSAGE\",\n    \"NO_SCENE_MESSAGE\",\n    \"NORMAL\",\n    \"ITALIC\",\n    \"OBLIQUE\",\n    \"BOLD\",\n    \"THIN\",\n    \"ULTRALIGHT\",\n    \"LIGHT\",\n    \"SEMILIGHT\",\n    \"BOOK\",\n    \"MEDIUM\",\n    \"SEMIBOLD\",\n    \"ULTRABOLD\",\n    \"HEAVY\",\n    \"ULTRAHEAVY\",\n    \"RESAMPLING_ALGORITHMS\",\n    \"ORIGIN\",\n    \"UP\",\n    \"DOWN\",\n    \"RIGHT\",\n    \"LEFT\",\n    \"IN\",\n    \"OUT\",\n    \"X_AXIS\",\n    \"Y_AXIS\",\n    \"Z_AXIS\",\n    \"UL\",\n    \"UR\",\n    \"DL\",\n    \"DR\",\n    \"START_X\",\n    \"START_Y\",\n    \"DEFAULT_DOT_RADIUS\",\n    \"DEFAULT_SMALL_DOT_RADIUS\",\n    \"DEFAULT_DASH_LENGTH\",\n    \"DEFAULT_ARROW_TIP_LENGTH\",\n    \"SMALL_BUFF\",\n    \"MED_SMALL_BUFF\",\n    \"MED_LARGE_BUFF\",\n    \"LARGE_BUFF\",\n    \"DEFAULT_MOBJECT_TO_EDGE_BUFFER\",\n    \"DEFAULT_MOBJECT_TO_MOBJECT_BUFFER\",\n    \"DEFAULT_POINTWISE_FUNCTION_RUN_TIME\",\n    \"DEFAULT_WAIT_TIME\",\n    \"DEFAULT_POINT_DENSITY_2D\",\n    \"DEFAULT_POINT_DENSITY_1D\",\n    \"DEFAULT_STROKE_WIDTH\",\n    \"DEFAULT_FONT_SIZE\",\n    \"SCALE_FACTOR_PER_FONT_POINT\",\n    \"PI\",\n    \"TAU\",\n    \"DEGREES\",\n    \"QUALITIES\",\n    \"DEFAULT_QUALITY\",\n    \"EPILOG\",\n    \"CONTEXT_SETTINGS\",\n    \"SHIFT_VALUE\",\n    \"CTRL_VALUE\",\n    \"RendererType\",\n    \"LineJointType\",\n    \"CapStyleType\",\n]\n# Messages\n\nSCENE_NOT_FOUND_MESSAGE = \"\"\"\n   {} is not in the script\n\"\"\"\nCHOOSE_NUMBER_MESSAGE = \"\"\"\nChoose number corresponding to desired scene/arguments.\n(Use comma separated list for multiple entries or use \"*\" to select all scenes.)\nChoice(s): \"\"\"\nINVALID_NUMBER_MESSAGE = \"Invalid scene numbers have been specified. Aborting.\"\nNO_SCENE_MESSAGE = \"\"\"\n   There are no scenes inside that module\n\"\"\"\n\n# Pango stuff\nNORMAL = \"NORMAL\"\nITALIC = \"ITALIC\"\nOBLIQUE = \"OBLIQUE\"\nBOLD = \"BOLD\"\n# Only for Pango from below\nTHIN = \"THIN\"\nULTRALIGHT = \"ULTRALIGHT\"\nLIGHT = \"LIGHT\"\nSEMILIGHT = \"SEMILIGHT\"\nBOOK = \"BOOK\"\nMEDIUM = \"MEDIUM\"\nSEMIBOLD = \"SEMIBOLD\"\nULTRABOLD = \"ULTRABOLD\"\nHEAVY = \"HEAVY\"\nULTRAHEAVY = \"ULTRAHEAVY\"\n\nRESAMPLING_ALGORITHMS = {\n    \"nearest\": Resampling.NEAREST,\n    \"none\": Resampling.NEAREST,\n    \"bilinear\": Resampling.BILINEAR,\n    \"linear\": Resampling.BILINEAR,\n    \"bicubic\": Resampling.BICUBIC,\n    \"cubic\": Resampling.BICUBIC,\n}\n\n# Geometry: directions\nORIGIN: Vector3D = np.array((0.0, 0.0, 0.0))\n\"\"\"The center of the coordinate system.\"\"\"\n\nUP: Vector3D = np.array((0.0, 1.0, 0.0))\n\"\"\"One unit step in the positive Y direction.\"\"\"\n\nDOWN: Vector3D = np.array((0.0, -1.0, 0.0))\n\"\"\"One unit step in the negative Y direction.\"\"\"\n\nRIGHT: Vector3D = np.array((1.0, 0.0, 0.0))\n\"\"\"One unit step in the positive X direction.\"\"\"\n\nLEFT: Vector3D = np.array((-1.0, 0.0, 0.0))\n\"\"\"One unit step in the negative X direction.\"\"\"\n\nIN: Vector3D = np.array((0.0, 0.0, -1.0))\n\"\"\"One unit step in the negative Z direction.\"\"\"\n\nOUT: Vector3D = np.array((0.0, 0.0, 1.0))\n\"\"\"One unit step in the positive Z direction.\"\"\"\n\n# Geometry: axes\nX_AXIS: Vector3D = np.array((1.0, 0.0, 0.0))\nY_AXIS: Vector3D = np.array((0.0, 1.0, 0.0))\nZ_AXIS: Vector3D = np.array((0.0, 0.0, 1.0))\n\n# Geometry: useful abbreviations for diagonals\nUL: Vector3D = UP + LEFT\n\"\"\"One step up plus one step left.\"\"\"\n\nUR: Vector3D = UP + RIGHT\n\"\"\"One step up plus one step right.\"\"\"\n\nDL: Vector3D = DOWN + LEFT\n\"\"\"One step down plus one step left.\"\"\"\n\nDR: Vector3D = DOWN + RIGHT\n\"\"\"One step down plus one step right.\"\"\"\n\n# Geometry\nSTART_X = 30\nSTART_Y = 20\nDEFAULT_DOT_RADIUS = 0.08\nDEFAULT_SMALL_DOT_RADIUS = 0.04\nDEFAULT_DASH_LENGTH = 0.05\nDEFAULT_ARROW_TIP_LENGTH = 0.35\n\n# Default buffers (padding)\nSMALL_BUFF = 0.1\nMED_SMALL_BUFF = 0.25\nMED_LARGE_BUFF = 0.5\nLARGE_BUFF = 1\nDEFAULT_MOBJECT_TO_EDGE_BUFFER = MED_LARGE_BUFF\nDEFAULT_MOBJECT_TO_MOBJECT_BUFFER = MED_SMALL_BUFF\n\n# Times in seconds\nDEFAULT_POINTWISE_FUNCTION_RUN_TIME = 3.0\nDEFAULT_WAIT_TIME = 1.0\n\n# Misc\nDEFAULT_POINT_DENSITY_2D = 25\nDEFAULT_POINT_DENSITY_1D = 10\nDEFAULT_STROKE_WIDTH = 4\nDEFAULT_FONT_SIZE = 48\nSCALE_FACTOR_PER_FONT_POINT = 1 / 960\n\n# Mathematical constants\nPI = np.pi\n\"\"\"The ratio of the circumference of a circle to its diameter.\"\"\"\n\nTAU = 2 * PI\n\"\"\"The ratio of the circumference of a circle to its radius.\"\"\"\n\nDEGREES = TAU / 360\n\"\"\"The exchange rate between radians and degrees.\"\"\"\n\n\nclass QualityDict(TypedDict):\n    flag: str | None\n    pixel_height: int\n    pixel_width: int\n    frame_rate: int\n\n\n# Video qualities\nQUALITIES: dict[str, QualityDict] = {\n    \"fourk_quality\": {\n        \"flag\": \"k\",\n        \"pixel_height\": 2160,\n        \"pixel_width\": 3840,\n        \"frame_rate\": 60,\n    },\n    \"production_quality\": {\n        \"flag\": \"p\",\n        \"pixel_height\": 1440,\n        \"pixel_width\": 2560,\n        \"frame_rate\": 60,\n    },\n    \"high_quality\": {\n        \"flag\": \"h\",\n        \"pixel_height\": 1080,\n        \"pixel_width\": 1920,\n        \"frame_rate\": 60,\n    },\n    \"medium_quality\": {\n        \"flag\": \"m\",\n        \"pixel_height\": 720,\n        \"pixel_width\": 1280,\n        \"frame_rate\": 30,\n    },\n    \"low_quality\": {\n        \"flag\": \"l\",\n        \"pixel_height\": 480,\n        \"pixel_width\": 854,\n        \"frame_rate\": 15,\n    },\n    \"example_quality\": {\n        \"flag\": None,\n        \"pixel_height\": 480,\n        \"pixel_width\": 854,\n        \"frame_rate\": 30,\n    },\n}\n\nDEFAULT_QUALITY = \"high_quality\"\n\nEPILOG = \"Made with <3 by Manim Community developers.\"\nSHIFT_VALUE = 65505\nCTRL_VALUE = 65507\n\nCONTEXT_SETTINGS = Context.settings(\n    align_option_groups=True,\n    align_sections=True,\n    show_constraints=True,\n)\n\n\nclass RendererType(Enum):\n    \"\"\"An enumeration of all renderer types that can be assigned to\n    the ``config.renderer`` attribute.\n\n    Manim's configuration allows assigning string values to the renderer\n    setting, the values are then replaced by the corresponding enum object.\n    In other words, you can run::\n\n        config.renderer = \"opengl\"\n\n    and checking the renderer afterwards reveals that the attribute has\n    assumed the value::\n\n        <RendererType.OPENGL: 'opengl'>\n    \"\"\"\n\n    CAIRO = \"cairo\"  #: A renderer based on the cairo backend.\n    OPENGL = \"opengl\"  #: An OpenGL-based renderer.\n\n\nclass LineJointType(Enum):\n    \"\"\"Collection of available line joint types.\n\n    See the example below for a visual illustration of the different\n    joint types.\n\n    Examples\n    --------\n\n    .. manim:: LineJointVariants\n        :save_last_frame:\n\n        class LineJointVariants(Scene):\n            def construct(self):\n                mob = VMobject(stroke_width=20, color=GREEN).set_points_as_corners([\n                    np.array([-2, 0, 0]),\n                    np.array([0, 0, 0]),\n                    np.array([-2, 1, 0]),\n                ])\n                lines = VGroup(*[mob.copy() for _ in range(len(LineJointType))])\n                for line, joint_type in zip(lines, LineJointType):\n                    line.joint_type = joint_type\n\n                lines.arrange(RIGHT, buff=1)\n                self.add(lines)\n                for line in lines:\n                    label = Text(line.joint_type.name).next_to(line, DOWN)\n                    self.add(label)\n    \"\"\"\n\n    AUTO = 0\n    ROUND = 1\n    BEVEL = 2\n    MITER = 3\n\n\nclass CapStyleType(Enum):\n    \"\"\"Collection of available cap styles.\n\n    See the example below for a visual illustration of the different\n    cap styles.\n\n    Examples\n    --------\n\n    .. manim:: CapStyleVariants\n        :save_last_frame:\n\n        class CapStyleVariants(Scene):\n            def construct(self):\n                arcs = VGroup(*[\n                    Arc(\n                        radius=1,\n                        start_angle=0,\n                        angle=TAU / 4,\n                        stroke_width=20,\n                        color=GREEN,\n                        cap_style=cap_style,\n                    )\n                    for cap_style in CapStyleType\n                ])\n                arcs.arrange(RIGHT, buff=1)\n                self.add(arcs)\n                for arc in arcs:\n                    label = Text(arc.cap_style.name, font_size=24).next_to(arc, DOWN)\n                    self.add(label)\n    \"\"\"\n\n    AUTO = 0\n    ROUND = 1\n    BUTT = 2\n    SQUARE = 3\n"
  },
  {
    "path": "manim/data_structures.py",
    "content": "\"\"\"Data classes and other necessary data structures for use in Manim.\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import Iterable\nfrom dataclasses import dataclass\nfrom types import MethodType\nfrom typing import Any\n\n\n@dataclass\nclass MethodWithArgs:\n    \"\"\"Object containing a :attr:`method` which is intended to be called later\n    with the positional arguments :attr:`args` and the keyword arguments\n    :attr:`kwargs`.\n\n    Attributes\n    ----------\n    method : MethodType\n        A callable representing a method of some class.\n    args : Iterable[Any]\n        Positional arguments for :attr:`method`.\n    kwargs : dict[str, Any]\n        Keyword arguments for :attr:`method`.\n    \"\"\"\n\n    __slots__ = [\"method\", \"args\", \"kwargs\"]\n\n    method: MethodType\n    args: Iterable[Any]\n    kwargs: dict[str, Any]\n"
  },
  {
    "path": "manim/mobject/__init__.py",
    "content": ""
  },
  {
    "path": "manim/mobject/frame.py",
    "content": "\"\"\"Special rectangles.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"ScreenRectangle\",\n    \"FullScreenRectangle\",\n]\n\n\nfrom typing import Any\n\nfrom manim.mobject.geometry.polygram import Rectangle\n\nfrom .. import config\n\n\nclass ScreenRectangle(Rectangle):\n    def __init__(\n        self, aspect_ratio: float = 16.0 / 9.0, height: float = 4, **kwargs: Any\n    ) -> None:\n        super().__init__(width=aspect_ratio * height, height=height, **kwargs)\n\n    @property\n    def aspect_ratio(self) -> float:\n        \"\"\"The aspect ratio.\n\n        When set, the width is stretched to accommodate\n        the new aspect ratio.\n        \"\"\"\n        return self.width / self.height\n\n    @aspect_ratio.setter\n    def aspect_ratio(self, value: float) -> None:\n        self.stretch_to_fit_width(value * self.height)\n\n\nclass FullScreenRectangle(ScreenRectangle):\n    def __init__(self, **kwargs: Any) -> None:\n        super().__init__(**kwargs)\n        self.height = config[\"frame_height\"]\n"
  },
  {
    "path": "manim/mobject/geometry/__init__.py",
    "content": "\"\"\"Various geometric Mobjects.\n\nModules\n=======\n\n.. autosummary::\n    :toctree: ../reference\n\n    ~arc\n    ~boolean_ops\n    ~labeled\n    ~line\n    ~polygram\n    ~shape_matchers\n    ~tips\n\"\"\"\n"
  },
  {
    "path": "manim/mobject/geometry/arc.py",
    "content": "r\"\"\"Mobjects that are curved.\n\nExamples\n--------\n.. manim:: UsefulAnnotations\n    :save_last_frame:\n\n    class UsefulAnnotations(Scene):\n        def construct(self):\n            m0 = Dot()\n            m1 = AnnotationDot()\n            m2 = LabeledDot(\"ii\")\n            m3 = LabeledDot(MathTex(r\"\\alpha\").set_color(ORANGE))\n            m4 = CurvedArrow(2*LEFT, 2*RIGHT, radius= -5)\n            m5 = CurvedArrow(2*LEFT, 2*RIGHT, radius= 8)\n            m6 = CurvedDoubleArrow(ORIGIN, 2*RIGHT)\n\n            self.add(m0, m1, m2, m3, m4, m5, m6)\n            for i, mobj in enumerate(self.mobjects):\n                mobj.shift(DOWN * (i-3))\n\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"TipableVMobject\",\n    \"Arc\",\n    \"ArcBetweenPoints\",\n    \"CurvedArrow\",\n    \"CurvedDoubleArrow\",\n    \"Circle\",\n    \"Dot\",\n    \"AnnotationDot\",\n    \"LabeledDot\",\n    \"Ellipse\",\n    \"AnnularSector\",\n    \"Sector\",\n    \"Annulus\",\n    \"CubicBezier\",\n    \"ArcPolygon\",\n    \"ArcPolygonFromArcs\",\n    \"TangentialArc\",\n]\n\nimport itertools\nimport warnings\nfrom typing import TYPE_CHECKING, Any, Self, cast\n\nimport numpy as np\n\nfrom manim.constants import *\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.types.vectorized_mobject import VGroup, VMobject\nfrom manim.utils.color import BLACK, BLUE, RED, WHITE, ParsableManimColor\nfrom manim.utils.iterables import adjacent_pairs\nfrom manim.utils.space_ops import (\n    angle_between_vectors,\n    angle_of_vector,\n    cartesian_to_spherical,\n    line_intersection,\n    perpendicular_bisector,\n    rotate_vector,\n)\n\nif TYPE_CHECKING:\n    from collections.abc import Iterable\n\n    import manim.mobject.geometry.tips as tips\n    from manim.mobject.geometry.line import Line\n    from manim.mobject.mobject import Mobject\n    from manim.mobject.text.tex_mobject import SingleStringMathTex, Tex\n    from manim.mobject.text.text_mobject import Text\n    from manim.typing import (\n        Point3D,\n        Point3DLike,\n        QuadraticSpline,\n        Vector3DLike,\n    )\n\n\nclass TipableVMobject(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"Meant for shared functionality between Arc and Line.\n    Functionality can be classified broadly into these groups:\n\n        * Adding, Creating, Modifying tips\n            - add_tip calls create_tip, before pushing the new tip\n                into the TipableVMobject's list of submobjects\n            - stylistic and positional configuration\n\n        * Checking for tips\n            - Boolean checks for whether the TipableVMobject has a tip\n                and a starting tip\n\n        * Getters\n            - Straightforward accessors, returning information pertaining\n                to the TipableVMobject instance's tip(s), its length etc\n    \"\"\"\n\n    def __init__(\n        self,\n        tip_length: float = DEFAULT_ARROW_TIP_LENGTH,\n        normal_vector: Vector3DLike = OUT,\n        tip_style: dict | None = None,\n        **kwargs: Any,\n    ) -> None:\n        self.tip_length: float = tip_length\n        self.normal_vector = normal_vector\n        self.tip_style: dict = tip_style if tip_style is not None else {}\n        super().__init__(**kwargs)\n\n    # Adding, Creating, Modifying tips\n\n    def add_tip(\n        self,\n        tip: tips.ArrowTip | None = None,\n        tip_shape: type[tips.ArrowTip] | None = None,\n        tip_length: float | None = None,\n        tip_width: float | None = None,\n        at_start: bool = False,\n    ) -> Self:\n        \"\"\"Adds a tip to the TipableVMobject instance, recognising\n        that the endpoints might need to be switched if it's\n        a 'starting tip' or not.\n        \"\"\"\n        if tip is None:\n            tip = self.create_tip(tip_shape, tip_length, tip_width, at_start)\n        else:\n            self.position_tip(tip, at_start)\n        self.reset_endpoints_based_on_tip(tip, at_start)\n        self.assign_tip_attr(tip, at_start)\n        self.add(tip)\n        return self\n\n    def create_tip(\n        self,\n        tip_shape: type[tips.ArrowTip] | None = None,\n        tip_length: float | None = None,\n        tip_width: float | None = None,\n        at_start: bool = False,\n    ) -> tips.ArrowTip:\n        \"\"\"Stylises the tip, positions it spatially, and returns\n        the newly instantiated tip to the caller.\n        \"\"\"\n        tip = self.get_unpositioned_tip(tip_shape, tip_length, tip_width)\n        self.position_tip(tip, at_start)\n        return tip\n\n    def get_unpositioned_tip(\n        self,\n        tip_shape: type[tips.ArrowTip] | None = None,\n        tip_length: float | None = None,\n        tip_width: float | None = None,\n    ) -> tips.ArrowTip | tips.ArrowTriangleFilledTip:\n        \"\"\"Returns a tip that has been stylistically configured,\n        but has not yet been given a position in space.\n        \"\"\"\n        from manim.mobject.geometry.tips import ArrowTriangleFilledTip\n\n        style: dict[str, Any] = {}\n\n        if tip_shape is None:\n            tip_shape = ArrowTriangleFilledTip\n\n        if tip_shape is ArrowTriangleFilledTip:\n            if tip_width is None:\n                tip_width = self.get_default_tip_length()\n            style.update({\"width\": tip_width})\n        if tip_length is None:\n            tip_length = self.get_default_tip_length()\n\n        color = self.get_color()\n        style.update({\"fill_color\": color, \"stroke_color\": color})\n        style.update(self.tip_style)\n        tip = tip_shape(length=tip_length, **style)\n        return tip\n\n    def position_tip(self, tip: tips.ArrowTip, at_start: bool = False) -> tips.ArrowTip:\n        # Last two control points, defining both\n        # the end, and the tangency direction\n        if at_start:\n            anchor = self.get_start()\n            handle = self.get_first_handle()\n        else:\n            handle = self.get_last_handle()\n            anchor = self.get_end()\n        angles = cartesian_to_spherical(handle - anchor)\n        tip.rotate(\n            angles[1] - PI - tip.tip_angle,\n        )  # Rotates the tip along the azimuthal\n        if not hasattr(self, \"_init_positioning_axis\"):\n            axis = np.array(\n                [\n                    np.sin(angles[1]),\n                    -np.cos(angles[1]),\n                    0,\n                ]\n            )  # Obtains the perpendicular of the tip\n            tip.rotate(\n                -angles[2] + PI / 2,\n                axis=axis,\n            )  # Rotates the tip along the vertical wrt the axis\n            self._init_positioning_axis = axis\n\n        tip.shift(anchor - tip.tip_point)\n        return tip\n\n    def reset_endpoints_based_on_tip(self, tip: tips.ArrowTip, at_start: bool) -> Self:\n        if self.get_length() == 0:\n            # Zero length, put_start_and_end_on wouldn't work\n            return self\n\n        if at_start:\n            self.put_start_and_end_on(tip.base, self.get_end())\n        else:\n            self.put_start_and_end_on(self.get_start(), tip.base)\n        return self\n\n    def assign_tip_attr(self, tip: tips.ArrowTip, at_start: bool) -> Self:\n        if at_start:\n            self.start_tip = tip\n        else:\n            self.tip = tip\n        return self\n\n    # Checking for tips\n\n    def has_tip(self) -> bool:\n        return hasattr(self, \"tip\") and self.tip in self\n\n    def has_start_tip(self) -> bool:\n        return hasattr(self, \"start_tip\") and self.start_tip in self\n\n    # Getters\n\n    def pop_tips(self) -> VGroup:\n        start, end = self.get_start_and_end()\n        result = self.get_group_class()()\n        if self.has_tip():\n            result.add(self.tip)\n            self.remove(self.tip)\n        if self.has_start_tip():\n            result.add(self.start_tip)\n            self.remove(self.start_tip)\n        if result.submobjects:\n            self.put_start_and_end_on(start, end)\n        return result\n\n    def get_tips(self) -> VGroup:\n        \"\"\"Returns a VGroup (collection of VMobjects) containing\n        the TipableVMObject instance's tips.\n        \"\"\"\n        result = self.get_group_class()()\n        if hasattr(self, \"tip\"):\n            result.add(self.tip)\n        if hasattr(self, \"start_tip\"):\n            result.add(self.start_tip)\n        return result\n\n    def get_tip(self) -> VMobject:\n        \"\"\"Returns the TipableVMobject instance's (first) tip,\n        otherwise throws an exception.\n        \"\"\"\n        tips = self.get_tips()\n        if len(tips) == 0:\n            raise Exception(\"tip not found\")\n        else:\n            tip: VMobject = tips[0]\n            return tip\n\n    def get_default_tip_length(self) -> float:\n        return self.tip_length\n\n    def get_first_handle(self) -> Point3D:\n        # Type inference of extracting an element from a list, is not\n        # supported by numpy, see this numpy issue\n        # https://github.com/numpy/numpy/issues/16544\n        first_handle: Point3D = self.points[1]\n        return first_handle\n\n    def get_last_handle(self) -> Point3D:\n        # Type inference of extracting an element from a list, is not\n        # supported by numpy, see this numpy issue\n        # https://github.com/numpy/numpy/issues/16544\n        last_handle: Point3D = self.points[-2]\n        return last_handle\n\n    def get_end(self) -> Point3D:\n        if self.has_tip():\n            return self.tip.get_start()\n        else:\n            return super().get_end()\n\n    def get_start(self) -> Point3D:\n        if self.has_start_tip():\n            return self.start_tip.get_start()\n        else:\n            return super().get_start()\n\n    def get_length(self) -> float:\n        start, end = self.get_start_and_end()\n        return float(np.linalg.norm(start - end))\n\n\nclass Arc(TipableVMobject):\n    \"\"\"A circular arc.\n\n    Examples\n    --------\n    A simple arc of angle Pi.\n\n    .. manim:: ArcExample\n        :save_last_frame:\n\n        class ArcExample(Scene):\n            def construct(self):\n                self.add(Arc(angle=PI))\n    \"\"\"\n\n    def __init__(\n        self,\n        radius: float | None = 1.0,\n        start_angle: float = 0,\n        angle: float = TAU / 4,\n        num_components: int = 9,\n        arc_center: Point3DLike = ORIGIN,\n        **kwargs: Any,\n    ):\n        if radius is None:  # apparently None is passed by ArcBetweenPoints\n            radius = 1.0\n        self.radius = radius\n        self.num_components = num_components\n        self.arc_center: Point3D = np.asarray(arc_center)\n        self.start_angle = start_angle\n        self.angle = angle\n        self._failed_to_get_center: bool = False\n        super().__init__(**kwargs)\n\n    def generate_points(self) -> None:\n        self._set_pre_positioned_points()\n        self.scale(self.radius, about_point=ORIGIN)\n        self.shift(self.arc_center)\n\n    # Points are set a bit differently when rendering via OpenGL.\n    # TODO: refactor Arc so that only one strategy for setting points\n    # has to be used.\n    def init_points(self) -> None:\n        self.set_points(\n            Arc._create_quadratic_bezier_points(\n                angle=self.angle,\n                start_angle=self.start_angle,\n                n_components=self.num_components,\n            ),\n        )\n        self.scale(self.radius, about_point=ORIGIN)\n        self.shift(self.arc_center)\n\n    @staticmethod\n    def _create_quadratic_bezier_points(\n        angle: float, start_angle: float = 0, n_components: int = 8\n    ) -> QuadraticSpline:\n        samples = np.array(\n            [\n                [np.cos(a), np.sin(a), 0]\n                for a in np.linspace(\n                    start_angle,\n                    start_angle + angle,\n                    2 * n_components + 1,\n                )\n            ],\n        )\n        theta = angle / n_components\n        samples[1::2] /= np.cos(theta / 2)\n\n        points = np.zeros((3 * n_components, 3))\n        points[0::3] = samples[0:-1:2]\n        points[1::3] = samples[1::2]\n        points[2::3] = samples[2::2]\n        return points\n\n    def _set_pre_positioned_points(self) -> None:\n        anchors = np.array(\n            [\n                np.cos(a) * RIGHT + np.sin(a) * UP\n                for a in np.linspace(\n                    self.start_angle,\n                    self.start_angle + self.angle,\n                    self.num_components,\n                )\n            ],\n        )\n        # Figure out which control points will give the\n        # Appropriate tangent lines to the circle\n        d_theta = self.angle / (self.num_components - 1.0)\n        tangent_vectors = np.zeros(anchors.shape)\n        # Rotate all 90 degrees, via (x, y) -> (-y, x)\n        tangent_vectors[:, 1] = anchors[:, 0]\n        tangent_vectors[:, 0] = -anchors[:, 1]\n        # Use tangent vectors to deduce anchors\n        factor = 4 / 3 * np.tan(d_theta / 4)\n        handles1 = anchors[:-1] + factor * tangent_vectors[:-1]\n        handles2 = anchors[1:] - factor * tangent_vectors[1:]\n        self.set_anchors_and_handles(anchors[:-1], handles1, handles2, anchors[1:])\n\n    def get_arc_center(self, warning: bool = True) -> Point3D:\n        \"\"\"Looks at the normals to the first two\n        anchors, and finds their intersection points\n        \"\"\"\n        # First two anchors and handles\n        a1, h1, h2, a2 = self.points[:4]\n\n        if np.all(a1 == a2):\n            # For a1 and a2 to lie at the same point arc radius\n            # must be zero. Thus arc_center will also lie at\n            # that point.\n            return np.copy(a1)\n        # Tangent vectors\n        t1 = h1 - a1\n        t2 = h2 - a2\n        # Normals\n        n1 = rotate_vector(t1, TAU / 4)\n        n2 = rotate_vector(t2, TAU / 4)\n        try:\n            return line_intersection(line1=(a1, a1 + n1), line2=(a2, a2 + n2))\n        except Exception:\n            if warning:\n                warnings.warn(\n                    \"Can't find Arc center, using ORIGIN instead\", stacklevel=1\n                )\n            self._failed_to_get_center = True\n            return np.array(ORIGIN)\n\n    def move_arc_center_to(self, point: Point3DLike) -> Self:\n        self.shift(point - self.get_arc_center())\n        return self\n\n    def stop_angle(self) -> float:\n        return cast(\n            float,\n            angle_of_vector(self.points[-1] - self.get_arc_center()) % TAU,\n        )\n\n\nclass ArcBetweenPoints(Arc):\n    \"\"\"Inherits from Arc and additionally takes 2 points between which the arc is spanned.\n\n    Example\n    -------\n    .. manim:: ArcBetweenPointsExample\n\n      class ArcBetweenPointsExample(Scene):\n          def construct(self):\n              circle = Circle(radius=2, stroke_color=GREY)\n              dot_1 = Dot(color=GREEN).move_to([2, 0, 0]).scale(0.5)\n              dot_1_text = Tex(\"(2,0)\").scale(0.5).next_to(dot_1, RIGHT).set_color(BLUE)\n              dot_2 = Dot(color=GREEN).move_to([0, 2, 0]).scale(0.5)\n              dot_2_text = Tex(\"(0,2)\").scale(0.5).next_to(dot_2, UP).set_color(BLUE)\n              arc= ArcBetweenPoints(start=2 * RIGHT, end=2 * UP, stroke_color=YELLOW)\n              self.add(circle, dot_1, dot_2, dot_1_text, dot_2_text)\n              self.play(Create(arc))\n    \"\"\"\n\n    def __init__(\n        self,\n        start: Point3DLike,\n        end: Point3DLike,\n        angle: float = TAU / 4,\n        radius: float | None = None,\n        **kwargs: Any,\n    ) -> None:\n        if radius is not None:\n            self.radius = radius\n            if radius < 0:\n                sign = -2\n                radius *= -1\n            else:\n                sign = 2\n            halfdist = np.linalg.norm(np.array(start) - np.array(end)) / 2\n            if radius < halfdist:\n                raise ValueError(\n                    \"\"\"ArcBetweenPoints called with a radius that is\n                            smaller than half the distance between the points.\"\"\",\n                )\n            arc_height = radius - np.sqrt(radius**2 - halfdist**2)\n            angle = np.arccos((radius - arc_height) / radius) * sign\n\n        super().__init__(radius=radius, angle=angle, **kwargs)\n        if angle == 0:\n            self.set_points_as_corners(np.array([LEFT, RIGHT]))\n        self.put_start_and_end_on(start, end)\n\n        if radius is None:\n            center = self.get_arc_center(warning=False)\n            if not self._failed_to_get_center:\n                # np.linalg.norm returns floating[Any] which is not compatible with float\n                self.radius = cast(\n                    float, np.linalg.norm(np.array(start) - np.array(center))\n                )\n            else:\n                self.radius = np.inf\n\n\nclass TangentialArc(ArcBetweenPoints):\n    \"\"\"\n    Construct an arc that is tangent to two intersecting lines.\n    You can choose any of the 4 possible corner arcs via the `corner` tuple.\n    corner = (s1, s2) where each si is ±1 to control direction along each line.\n\n    Examples\n    --------\n    .. manim:: TangentialArcExample\n        :save_last_frame:\n\n        class TangentialArcExample(Scene):\n            def construct(self):\n                line1 = DashedLine(start=3 * LEFT, end=3 * RIGHT)\n                line1.rotate(angle=31 * DEGREES, about_point=ORIGIN)\n                line2 = DashedLine(start=3 * UP, end=3 * DOWN)\n                line2.rotate(angle=12 * DEGREES, about_point=ORIGIN)\n\n                arc = TangentialArc(line1, line2, radius=2.25, corner=(1, 1), color=TEAL)\n                self.add(arc, line1, line2)\n\n    The following example shows all four possible corner configurations:\n\n    .. manim:: TangentialArcCorners\n        :save_last_frame:\n\n        class TangentialArcCorners(Scene):\n            def construct(self):\n                # Create two intersecting lines\n                line1 = DashedLine(start=3 * LEFT, end=3 * RIGHT, color=GREY)\n                line2 = DashedLine(start=3 * UP, end=3 * DOWN, color=GREY)\n\n                # All four corner configurations with different colors\n                arc_pp = TangentialArc(line1, line2, radius=1.5, corner=(1, 1), color=RED)\n                arc_pn = TangentialArc(line1, line2, radius=1.5, corner=(1, -1), color=GREEN)\n                arc_np = TangentialArc(line1, line2, radius=1.5, corner=(-1, 1), color=BLUE)\n                arc_nn = TangentialArc(line1, line2, radius=1.5, corner=(-1, -1), color=YELLOW)\n\n                # Labels for each arc\n                label_pp = Text(\"(1,1)\", font_size=24, color=RED).next_to(arc_pp, UR, buff=0.1)\n                label_pn = Text(\"(1,-1)\", font_size=24, color=GREEN).next_to(arc_pn, DR, buff=0.1)\n                label_np = Text(\"(-1,1)\", font_size=24, color=BLUE).next_to(arc_np, UL, buff=0.1)\n                label_nn = Text(\"(-1,-1)\", font_size=24, color=YELLOW).next_to(arc_nn, DL, buff=0.1)\n\n                self.add(line1, line2, arc_pp, arc_pn, arc_np, arc_nn)\n                self.add(label_pp, label_pn, label_np, label_nn)\n    \"\"\"\n\n    def __init__(\n        self,\n        line1: Line,\n        line2: Line,\n        radius: float,\n        corner: Any = (1, 1),\n        **kwargs: Any,\n    ):\n        self.line1 = line1\n        self.line2 = line2\n\n        intersection_point = line_intersection(\n            [line1.get_start(), line1.get_end()], [line2.get_start(), line2.get_end()]\n        )\n\n        s1, s2 = corner\n        # Get unit vector for specified directions\n        unit_vector1 = s1 * line1.get_unit_vector()\n        unit_vector2 = s2 * line2.get_unit_vector()\n\n        corner_angle = angle_between_vectors(unit_vector1, unit_vector2)\n        tangent_point_distance = radius / np.tan(corner_angle / 2)\n\n        # tangent points\n        tangent_point1 = intersection_point + tangent_point_distance * unit_vector1\n        tangent_point2 = intersection_point + tangent_point_distance * unit_vector2\n\n        cross_product = (\n            unit_vector1[0] * unit_vector2[1] - unit_vector1[1] * unit_vector2[0]\n        )\n\n        # Determine start and end points based on orientation\n        if cross_product < 0:\n            # Counterclockwise orientation - standard order\n            start_point = tangent_point1\n            end_point = tangent_point2\n        else:\n            # Clockwise orientation - reverse the points\n            start_point = tangent_point2\n            end_point = tangent_point1\n\n        super().__init__(start=start_point, end=end_point, radius=radius, **kwargs)\n\n\nclass CurvedArrow(ArcBetweenPoints):\n    def __init__(\n        self, start_point: Point3DLike, end_point: Point3DLike, **kwargs: Any\n    ) -> None:\n        from manim.mobject.geometry.tips import ArrowTriangleFilledTip\n\n        tip_shape = kwargs.pop(\"tip_shape\", ArrowTriangleFilledTip)\n        super().__init__(start_point, end_point, **kwargs)\n        self.add_tip(tip_shape=tip_shape)\n\n\nclass CurvedDoubleArrow(CurvedArrow):\n    def __init__(\n        self, start_point: Point3DLike, end_point: Point3DLike, **kwargs: Any\n    ) -> None:\n        if \"tip_shape_end\" in kwargs:\n            kwargs[\"tip_shape\"] = kwargs.pop(\"tip_shape_end\")\n        from manim.mobject.geometry.tips import ArrowTriangleFilledTip\n\n        tip_shape_start = kwargs.pop(\"tip_shape_start\", ArrowTriangleFilledTip)\n        super().__init__(start_point, end_point, **kwargs)\n        self.add_tip(at_start=True, tip_shape=tip_shape_start)\n\n\nclass Circle(Arc):\n    \"\"\"A circle.\n\n    Parameters\n    ----------\n    color\n        The color of the shape.\n    kwargs\n        Additional arguments to be passed to :class:`Arc`\n\n    Examples\n    --------\n    .. manim:: CircleExample\n        :save_last_frame:\n\n        class CircleExample(Scene):\n            def construct(self):\n                circle_1 = Circle(radius=1.0)\n                circle_2 = Circle(radius=1.5, color=GREEN)\n                circle_3 = Circle(radius=1.0, color=BLUE_B, fill_opacity=1)\n\n                circle_group = Group(circle_1, circle_2, circle_3).arrange(buff=1)\n                self.add(circle_group)\n    \"\"\"\n\n    def __init__(\n        self,\n        radius: float | None = None,\n        color: ParsableManimColor = RED,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(\n            radius=radius,\n            start_angle=0,\n            angle=TAU,\n            color=color,\n            **kwargs,\n        )\n\n    def surround(\n        self,\n        mobject: Mobject,\n        dim_to_match: int = 0,\n        stretch: bool = False,\n        buffer_factor: float = 1.2,\n    ) -> Self:\n        \"\"\"Modifies a circle so that it surrounds a given mobject.\n\n        Parameters\n        ----------\n        mobject\n            The mobject that the circle will be surrounding.\n        dim_to_match\n        buffer_factor\n            Scales the circle with respect to the mobject. A `buffer_factor` < 1 makes the circle smaller than the mobject.\n        stretch\n            Stretches the circle to fit more tightly around the mobject. Note: Does not work with :class:`Line`\n\n        Examples\n        --------\n        .. manim:: CircleSurround\n            :save_last_frame:\n\n            class CircleSurround(Scene):\n                def construct(self):\n                    triangle1 = Triangle()\n                    circle1 = Circle().surround(triangle1)\n                    group1 = Group(triangle1,circle1) # treat the two mobjects as one\n\n                    line2 = Line()\n                    circle2 = Circle().surround(line2, buffer_factor=2.0)\n                    group2 = Group(line2,circle2)\n\n                    # buffer_factor < 1, so the circle is smaller than the square\n                    square3 = Square()\n                    circle3 = Circle().surround(square3, buffer_factor=0.5)\n                    group3 = Group(square3, circle3)\n\n                    group = Group(group1, group2, group3).arrange(buff=1)\n                    self.add(group)\n        \"\"\"\n        # Ignores dim_to_match and stretch; result will always be a circle\n        # TODO: Perhaps create an ellipse class to handle single-dimension stretching\n\n        # Something goes wrong here when surrounding lines?\n        # TODO: Figure out and fix\n        self.replace(mobject, dim_to_match, stretch)\n\n        self.width = np.sqrt(mobject.width**2 + mobject.height**2)\n        return self.scale(buffer_factor)\n\n    def point_at_angle(self, angle: float) -> Point3D:\n        \"\"\"Returns the position of a point on the circle.\n\n        Parameters\n        ----------\n        angle\n            The angle of the point along the circle in radians.\n\n        Returns\n        -------\n        :class:`numpy.ndarray`\n            The location of the point along the circle's circumference.\n\n        Examples\n        --------\n        .. manim:: PointAtAngleExample\n            :save_last_frame:\n\n            class PointAtAngleExample(Scene):\n                def construct(self):\n                    circle = Circle(radius=2.0)\n                    p1 = circle.point_at_angle(PI/2)\n                    p2 = circle.point_at_angle(270*DEGREES)\n\n                    s1 = Square(side_length=0.25).move_to(p1)\n                    s2 = Square(side_length=0.25).move_to(p2)\n                    self.add(circle, s1, s2)\n\n        \"\"\"\n        proportion = angle / TAU\n        proportion -= np.floor(proportion)\n        return self.point_from_proportion(proportion)\n\n    @staticmethod\n    def from_three_points(\n        p1: Point3DLike, p2: Point3DLike, p3: Point3DLike, **kwargs: Any\n    ) -> Circle:\n        \"\"\"Returns a circle passing through the specified\n        three points.\n\n        Example\n        -------\n        .. manim:: CircleFromPointsExample\n            :save_last_frame:\n\n            class CircleFromPointsExample(Scene):\n                def construct(self):\n                    circle = Circle.from_three_points(LEFT, LEFT + UP, UP * 2, color=RED)\n                    dots = VGroup(\n                        Dot(LEFT),\n                        Dot(LEFT + UP),\n                        Dot(UP * 2),\n                    )\n                    self.add(NumberPlane(), circle, dots)\n        \"\"\"\n        center = line_intersection(\n            perpendicular_bisector([np.asarray(p1), np.asarray(p2)]),\n            perpendicular_bisector([np.asarray(p2), np.asarray(p3)]),\n        )\n        # np.linalg.norm returns floating[Any] which is not compatible with float\n        radius = cast(float, np.linalg.norm(p1 - center))\n        return Circle(radius=radius, **kwargs).shift(center)\n\n\nclass Dot(Circle):\n    \"\"\"A circle with a very small radius.\n\n    Parameters\n    ----------\n    point\n        The location of the dot.\n    radius\n        The radius of the dot.\n    stroke_width\n        The thickness of the outline of the dot.\n    fill_opacity\n        The opacity of the dot's fill_colour\n    color\n        The color of the dot.\n    kwargs\n        Additional arguments to be passed to :class:`Circle`\n\n    Examples\n    --------\n    .. manim:: DotExample\n        :save_last_frame:\n\n        class DotExample(Scene):\n            def construct(self):\n                dot1 = Dot(point=LEFT, radius=0.08)\n                dot2 = Dot(point=ORIGIN)\n                dot3 = Dot(point=RIGHT)\n                self.add(dot1,dot2,dot3)\n    \"\"\"\n\n    def __init__(\n        self,\n        point: Point3DLike = ORIGIN,\n        radius: float = DEFAULT_DOT_RADIUS,\n        stroke_width: float = 0,\n        fill_opacity: float = 1.0,\n        color: ParsableManimColor = WHITE,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(\n            arc_center=point,\n            radius=radius,\n            stroke_width=stroke_width,\n            fill_opacity=fill_opacity,\n            color=color,\n            **kwargs,\n        )\n\n\nclass AnnotationDot(Dot):\n    \"\"\"A dot with bigger radius and bold stroke to annotate scenes.\"\"\"\n\n    def __init__(\n        self,\n        radius: float = DEFAULT_DOT_RADIUS * 1.3,\n        stroke_width: float = 5,\n        stroke_color: ParsableManimColor = WHITE,\n        fill_color: ParsableManimColor = BLUE,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(\n            radius=radius,\n            stroke_width=stroke_width,\n            stroke_color=stroke_color,\n            fill_color=fill_color,\n            **kwargs,\n        )\n\n\nclass LabeledDot(Dot):\n    \"\"\"A :class:`Dot` containing a label in its center.\n\n    Parameters\n    ----------\n    label\n        The label of the :class:`Dot`. This is rendered as :class:`~.MathTex`\n        by default (i.e., when passing a :class:`str`), but other classes\n        representing rendered strings like :class:`~.Text` or :class:`~.Tex`\n        can be passed as well.\n    radius\n        The radius of the :class:`Dot`. If provided, the ``buff`` is ignored.\n        If ``None`` (the default), the radius is calculated based on the size\n        of the ``label`` and the ``buff``.\n\n    Examples\n    --------\n    .. manim:: SeveralLabeledDots\n        :save_last_frame:\n\n        class SeveralLabeledDots(Scene):\n            def construct(self):\n                sq = Square(fill_color=RED, fill_opacity=1)\n                self.add(sq)\n                dot1 = LabeledDot(Tex(\"42\", color=RED))\n                dot2 = LabeledDot(MathTex(\"a\", color=GREEN))\n                dot3 = LabeledDot(Text(\"ii\", color=BLUE))\n                dot4 = LabeledDot(\"3\")\n                dot1.next_to(sq, UL)\n                dot2.next_to(sq, UR)\n                dot3.next_to(sq, DL)\n                dot4.next_to(sq, DR)\n                self.add(dot1, dot2, dot3, dot4)\n    \"\"\"\n\n    def __init__(\n        self,\n        label: str | SingleStringMathTex | Text | Tex,\n        radius: float | None = None,\n        buff: float = SMALL_BUFF,\n        **kwargs: Any,\n    ) -> None:\n        if isinstance(label, str):\n            from manim import MathTex\n\n            rendered_label: VMobject = MathTex(label, color=BLACK)\n        else:\n            rendered_label = label\n\n        if radius is None:\n            radius = buff + float(\n                np.linalg.norm([rendered_label.width, rendered_label.height]) / 2\n            )\n        super().__init__(radius=radius, **kwargs)\n        rendered_label.move_to(self.get_center())\n        self.add(rendered_label)\n\n\nclass Ellipse(Circle):\n    \"\"\"A circular shape; oval, circle.\n\n    Parameters\n    ----------\n    width\n       The horizontal width of the ellipse.\n    height\n       The vertical height of the ellipse.\n    kwargs\n       Additional arguments to be passed to :class:`Circle`.\n\n    Examples\n    --------\n    .. manim:: EllipseExample\n        :save_last_frame:\n\n        class EllipseExample(Scene):\n            def construct(self):\n                ellipse_1 = Ellipse(width=2.0, height=4.0, color=BLUE_B)\n                ellipse_2 = Ellipse(width=4.0, height=1.0, color=BLUE_D)\n                ellipse_group = Group(ellipse_1,ellipse_2).arrange(buff=1)\n                self.add(ellipse_group)\n    \"\"\"\n\n    def __init__(self, width: float = 2, height: float = 1, **kwargs: Any) -> None:\n        super().__init__(**kwargs)\n        self.stretch_to_fit_width(width)\n        self.stretch_to_fit_height(height)\n\n\nclass AnnularSector(Arc):\n    \"\"\"A sector of an annulus.\n\n\n    Parameters\n    ----------\n    inner_radius\n       The inside radius of the Annular Sector.\n    outer_radius\n       The outside radius of the Annular Sector.\n    angle\n       The clockwise angle of the Annular Sector.\n    start_angle\n       The starting clockwise angle of the Annular Sector.\n    fill_opacity\n       The opacity of the color filled in the Annular Sector.\n    stroke_width\n       The stroke width of the Annular Sector.\n    color\n       The color filled into the Annular Sector.\n\n    Examples\n    --------\n    .. manim:: AnnularSectorExample\n        :save_last_frame:\n\n        class AnnularSectorExample(Scene):\n            def construct(self):\n                # Changes background color to clearly visualize changes in fill_opacity.\n                self.camera.background_color = WHITE\n\n                # The default parameter start_angle is 0, so the AnnularSector starts from the +x-axis.\n                s1 = AnnularSector(color=YELLOW).move_to(2 * UL)\n\n                # Different inner_radius and outer_radius than the default.\n                s2 = AnnularSector(inner_radius=1.5, outer_radius=2, angle=45 * DEGREES, color=RED).move_to(2 * UR)\n\n                # fill_opacity is typically a number > 0 and <= 1. If fill_opacity=0, the AnnularSector is transparent.\n                s3 = AnnularSector(inner_radius=1, outer_radius=1.5, angle=PI, fill_opacity=0.25, color=BLUE).move_to(2 * DL)\n\n                # With a negative value for the angle, the AnnularSector is drawn clockwise from the start value.\n                s4 = AnnularSector(inner_radius=1, outer_radius=1.5, angle=-3 * PI / 2, color=GREEN).move_to(2 * DR)\n\n                self.add(s1, s2, s3, s4)\n    \"\"\"\n\n    def __init__(\n        self,\n        inner_radius: float = 1,\n        outer_radius: float = 2,\n        angle: float = TAU / 4,\n        start_angle: float = 0,\n        fill_opacity: float = 1,\n        stroke_width: float = 0,\n        color: ParsableManimColor = WHITE,\n        **kwargs: Any,\n    ) -> None:\n        self.inner_radius = inner_radius\n        self.outer_radius = outer_radius\n        super().__init__(\n            start_angle=start_angle,\n            angle=angle,\n            fill_opacity=fill_opacity,\n            stroke_width=stroke_width,\n            color=color,\n            **kwargs,\n        )\n\n    def generate_points(self) -> None:\n        inner_arc, outer_arc = (\n            Arc(\n                start_angle=self.start_angle,\n                angle=self.angle,\n                radius=radius,\n                arc_center=self.arc_center,\n            )\n            for radius in (self.inner_radius, self.outer_radius)\n        )\n        outer_arc.reverse_points()\n        self.append_points(inner_arc.points)\n        self.add_line_to(outer_arc.points[0])\n        self.append_points(outer_arc.points)\n        self.add_line_to(inner_arc.points[0])\n\n    def init_points(self) -> None:\n        self.generate_points()\n\n\nclass Sector(AnnularSector):\n    \"\"\"A sector of a circle.\n\n    Examples\n    --------\n    .. manim:: ExampleSector\n        :save_last_frame:\n\n        class ExampleSector(Scene):\n            def construct(self):\n                sector = Sector(radius=2)\n                sector2 = Sector(radius=2.5, angle=60*DEGREES).move_to([-3, 0, 0])\n                sector.set_color(RED)\n                sector2.set_color(PINK)\n                self.add(sector, sector2)\n    \"\"\"\n\n    def __init__(self, radius: float = 1, **kwargs: Any) -> None:\n        super().__init__(inner_radius=0, outer_radius=radius, **kwargs)\n\n\nclass Annulus(Circle):\n    \"\"\"Region between two concentric :class:`Circles <.Circle>`.\n\n    Parameters\n    ----------\n    inner_radius\n        The radius of the inner :class:`Circle`.\n    outer_radius\n        The radius of the outer :class:`Circle`.\n    kwargs\n        Additional arguments to be passed to :class:`Annulus`\n\n    Examples\n    --------\n    .. manim:: AnnulusExample\n        :save_last_frame:\n\n        class AnnulusExample(Scene):\n            def construct(self):\n                annulus_1 = Annulus(inner_radius=0.5, outer_radius=1).shift(UP)\n                annulus_2 = Annulus(inner_radius=0.3, outer_radius=0.6, color=RED).next_to(annulus_1, DOWN)\n                self.add(annulus_1, annulus_2)\n    \"\"\"\n\n    def __init__(\n        self,\n        inner_radius: float = 1,\n        outer_radius: float = 2,\n        fill_opacity: float = 1,\n        stroke_width: float = 0,\n        color: ParsableManimColor = WHITE,\n        mark_paths_closed: bool = False,\n        **kwargs: Any,\n    ) -> None:\n        self.mark_paths_closed = mark_paths_closed  # is this even used?\n        self.inner_radius = inner_radius\n        self.outer_radius = outer_radius\n        super().__init__(\n            fill_opacity=fill_opacity, stroke_width=stroke_width, color=color, **kwargs\n        )\n\n    def generate_points(self) -> None:\n        self.radius = self.outer_radius\n        outer_circle = Circle(radius=self.outer_radius)\n        inner_circle = Circle(radius=self.inner_radius)\n        inner_circle.reverse_points()\n        self.append_points(outer_circle.points)\n        self.append_points(inner_circle.points)\n        self.shift(self.arc_center)\n\n    def init_points(self) -> None:\n        self.generate_points()\n\n\nclass CubicBezier(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A cubic Bézier curve.\n\n    Example\n    -------\n    .. manim:: BezierSplineExample\n        :save_last_frame:\n\n        class BezierSplineExample(Scene):\n            def construct(self):\n                p1 = np.array([-3, 1, 0])\n                p1b = p1 + [1, 0, 0]\n                d1 = Dot(point=p1).set_color(BLUE)\n                l1 = Line(p1, p1b)\n                p2 = np.array([3, -1, 0])\n                p2b = p2 - [1, 0, 0]\n                d2 = Dot(point=p2).set_color(RED)\n                l2 = Line(p2, p2b)\n                bezier = CubicBezier(p1b, p1b + 3 * RIGHT, p2b - 3 * RIGHT, p2b)\n                self.add(l1, d1, l2, d2, bezier)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        start_anchor: Point3DLike,\n        start_handle: Point3DLike,\n        end_handle: Point3DLike,\n        end_anchor: Point3DLike,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(**kwargs)\n        self.add_cubic_bezier_curve(start_anchor, start_handle, end_handle, end_anchor)\n\n\nclass ArcPolygon(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A generalized polygon allowing for points to be connected with arcs.\n\n    This version tries to stick close to the way :class:`Polygon` is used. Points\n    can be passed to it directly which are used to generate the according arcs\n    (using :class:`ArcBetweenPoints`). An angle or radius can be passed to it to\n    use across all arcs, but to configure arcs individually an ``arc_config`` list\n    has to be passed with the syntax explained below.\n\n    Parameters\n    ----------\n    vertices\n        A list of vertices, start and end points for the arc segments.\n    angle\n        The angle used for constructing the arcs. If no other parameters\n        are set, this angle is used to construct all arcs.\n    radius\n        The circle radius used to construct the arcs. If specified,\n        overrides the specified ``angle``.\n    arc_config\n        When passing a ``dict``, its content will be passed as keyword\n        arguments to :class:`~.ArcBetweenPoints`. Otherwise, a list\n        of dictionaries containing values that are passed as keyword\n        arguments for every individual arc can be passed.\n    kwargs\n        Further keyword arguments that are passed to the constructor of\n        :class:`~.VMobject`.\n\n    Attributes\n    ----------\n    arcs : :class:`list`\n        The arcs created from the input parameters::\n\n            >>> from manim import ArcPolygon\n            >>> ap = ArcPolygon([0, 0, 0], [2, 0, 0], [0, 2, 0])\n            >>> ap.arcs\n            [ArcBetweenPoints, ArcBetweenPoints, ArcBetweenPoints]\n\n\n    .. tip::\n\n        Two instances of :class:`ArcPolygon` can be transformed properly into one\n        another as well. Be advised that any arc initialized with ``angle=0``\n        will actually be a straight line, so if a straight section should seamlessly\n        transform into an arced section or vice versa, initialize the straight section\n        with a negligible angle instead (such as ``angle=0.0001``).\n\n    .. note::\n        There is an alternative version (:class:`ArcPolygonFromArcs`) that is instantiated\n        with pre-defined arcs.\n\n    See Also\n    --------\n    :class:`ArcPolygonFromArcs`\n\n\n    Examples\n    --------\n    .. manim:: SeveralArcPolygons\n\n        class SeveralArcPolygons(Scene):\n            def construct(self):\n                a = [0, 0, 0]\n                b = [2, 0, 0]\n                c = [0, 2, 0]\n                ap1 = ArcPolygon(a, b, c, radius=2)\n                ap2 = ArcPolygon(a, b, c, angle=45*DEGREES)\n                ap3 = ArcPolygon(a, b, c, arc_config={'radius': 1.7, 'color': RED})\n                ap4 = ArcPolygon(a, b, c, color=RED, fill_opacity=1,\n                                            arc_config=[{'radius': 1.7, 'color': RED},\n                                            {'angle': 20*DEGREES, 'color': BLUE},\n                                            {'radius': 1}])\n                ap_group = VGroup(ap1, ap2, ap3, ap4).arrange()\n                self.play(*[Create(ap) for ap in [ap1, ap2, ap3, ap4]])\n                self.wait()\n\n    For further examples see :class:`ArcPolygonFromArcs`.\n    \"\"\"\n\n    def __init__(\n        self,\n        *vertices: Point3DLike,\n        angle: float = PI / 4,\n        radius: float | None = None,\n        arc_config: list[dict] | None = None,\n        **kwargs: Any,\n    ) -> None:\n        n = len(vertices)\n        point_pairs = [(vertices[k], vertices[(k + 1) % n]) for k in range(n)]\n\n        if not arc_config:\n            if radius:\n                all_arc_configs: Iterable[dict] = itertools.repeat(\n                    {\"radius\": radius}, len(point_pairs)\n                )\n            else:\n                all_arc_configs = itertools.repeat({\"angle\": angle}, len(point_pairs))\n        elif isinstance(arc_config, dict):\n            all_arc_configs = itertools.repeat(arc_config, len(point_pairs))\n        else:\n            assert len(arc_config) == n\n            all_arc_configs = arc_config\n\n        arcs = [\n            ArcBetweenPoints(*pair, **conf)\n            for (pair, conf) in zip(point_pairs, all_arc_configs, strict=True)\n        ]\n\n        super().__init__(**kwargs)\n        # Adding the arcs like this makes ArcPolygon double as a VGroup.\n        # Also makes changes to the ArcPolygon, such as scaling, affect\n        # the arcs, so that their new values are usable.\n        self.add(*arcs)\n        for arc in arcs:\n            self.append_points(arc.points)\n\n        # This enables the use of ArcPolygon.arcs as a convenience\n        # because ArcPolygon[0] returns itself, not the first Arc.\n        self.arcs = arcs\n\n\nclass ArcPolygonFromArcs(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A generalized polygon allowing for points to be connected with arcs.\n\n    This version takes in pre-defined arcs to generate the arcpolygon and introduces\n    little new syntax. However unlike :class:`Polygon` it can't be created with points\n    directly.\n\n    For proper appearance the passed arcs should connect seamlessly:\n    ``[a,b][b,c][c,a]``\n\n    If there are any gaps between the arcs, those will be filled in\n    with straight lines, which can be used deliberately for any straight\n    sections. Arcs can also be passed as straight lines such as an arc\n    initialized with ``angle=0``.\n\n    Parameters\n    ----------\n    arcs\n        These are the arcs from which the arcpolygon is assembled.\n    kwargs\n        Keyword arguments that are passed to the constructor of\n        :class:`~.VMobject`. Affects how the ArcPolygon itself is drawn,\n        but doesn't affect passed arcs.\n\n    Attributes\n    ----------\n    arcs\n        The arcs used to initialize the ArcPolygonFromArcs::\n\n            >>> from manim import ArcPolygonFromArcs, Arc, ArcBetweenPoints\n            >>> ap = ArcPolygonFromArcs(Arc(), ArcBetweenPoints([1,0,0], [0,1,0]), Arc())\n            >>> ap.arcs\n            [Arc, ArcBetweenPoints, Arc]\n\n\n    .. tip::\n\n        Two instances of :class:`ArcPolygon` can be transformed properly into\n        one another as well. Be advised that any arc initialized with ``angle=0``\n        will actually be a straight line, so if a straight section should seamlessly\n        transform into an arced section or vice versa, initialize the straight\n        section with a negligible angle instead (such as ``angle=0.0001``).\n\n    .. note::\n        There is an alternative version (:class:`ArcPolygon`) that can be instantiated\n        with points.\n\n    .. seealso::\n        :class:`ArcPolygon`\n\n    Examples\n    --------\n    One example of an arcpolygon is the Reuleaux triangle.\n    Instead of 3 straight lines connecting the outer points,\n    a Reuleaux triangle has 3 arcs connecting those points,\n    making a shape with constant width.\n\n    Passed arcs are stored as submobjects in the arcpolygon.\n    This means that the arcs are changed along with the arcpolygon,\n    for example when it's shifted, and these arcs can be manipulated\n    after the arcpolygon has been initialized.\n\n    Also both the arcs contained in an :class:`~.ArcPolygonFromArcs`, as well as the\n    arcpolygon itself are drawn, which affects draw time in :class:`~.Create`\n    for example. In most cases the arcs themselves don't\n    need to be drawn, in which case they can be passed as invisible.\n\n    .. manim:: ArcPolygonExample\n\n        class ArcPolygonExample(Scene):\n            def construct(self):\n                arc_conf = {\"stroke_width\": 0}\n                poly_conf = {\"stroke_width\": 10, \"stroke_color\": BLUE,\n                      \"fill_opacity\": 1, \"color\": PURPLE}\n                a = [-1, 0, 0]\n                b = [1, 0, 0]\n                c = [0, np.sqrt(3), 0]\n                arc0 = ArcBetweenPoints(a, b, radius=2, **arc_conf)\n                arc1 = ArcBetweenPoints(b, c, radius=2, **arc_conf)\n                arc2 = ArcBetweenPoints(c, a, radius=2, **arc_conf)\n                reuleaux_tri = ArcPolygonFromArcs(arc0, arc1, arc2, **poly_conf)\n                self.play(FadeIn(reuleaux_tri))\n                self.wait(2)\n\n    The arcpolygon itself can also be hidden so that instead only the contained\n    arcs are drawn. This can be used to easily debug arcs or to highlight them.\n\n    .. manim:: ArcPolygonExample2\n\n        class ArcPolygonExample2(Scene):\n            def construct(self):\n                arc_conf = {\"stroke_width\": 3, \"stroke_color\": BLUE,\n                    \"fill_opacity\": 0.5, \"color\": GREEN}\n                poly_conf = {\"color\": None}\n                a = [-1, 0, 0]\n                b = [1, 0, 0]\n                c = [0, np.sqrt(3), 0]\n                arc0 = ArcBetweenPoints(a, b, radius=2, **arc_conf)\n                arc1 = ArcBetweenPoints(b, c, radius=2, **arc_conf)\n                arc2 = ArcBetweenPoints(c, a, radius=2, stroke_color=RED)\n                reuleaux_tri = ArcPolygonFromArcs(arc0, arc1, arc2, **poly_conf)\n                self.play(FadeIn(reuleaux_tri))\n                self.wait(2)\n    \"\"\"\n\n    def __init__(self, *arcs: Arc | ArcBetweenPoints, **kwargs: Any) -> None:\n        if not all(isinstance(m, (Arc, ArcBetweenPoints)) for m in arcs):\n            raise ValueError(\n                \"All ArcPolygon submobjects must be of type Arc/ArcBetweenPoints\",\n            )\n        super().__init__(**kwargs)\n        # Adding the arcs like this makes ArcPolygonFromArcs double as a VGroup.\n        # Also makes changes to the ArcPolygonFromArcs, such as scaling, affect\n        # the arcs, so that their new values are usable.\n        self.add(*arcs)\n        # This enables the use of ArcPolygonFromArcs.arcs as a convenience\n        # because ArcPolygonFromArcs[0] returns itself, not the first Arc.\n        self.arcs = [*arcs]\n        from .line import Line\n\n        for arc1, arc2 in adjacent_pairs(arcs):\n            self.append_points(arc1.points)\n            line = Line(arc1.get_end(), arc2.get_start())\n            len_ratio = line.get_length() / arc1.get_arc_length()\n            if np.isnan(len_ratio) or np.isinf(len_ratio):\n                continue\n            line.insert_n_curves(int(arc1.get_num_curves() * len_ratio))\n            self.append_points(line.points)\n"
  },
  {
    "path": "manim/mobject/geometry/boolean_ops.py",
    "content": "\"\"\"Boolean operations for two-dimensional mobjects.\"\"\"\n\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\nfrom pathops import Path as SkiaPath\nfrom pathops import PathVerb, difference, intersection, union, xor\n\nfrom manim import config\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.types.vectorized_mobject import VMobject\n\nif TYPE_CHECKING:\n    from manim.typing import Point2DLike_Array, Point3D_Array, Point3DLike_Array\n\nfrom ...constants import RendererType\n\n__all__ = [\"Union\", \"Intersection\", \"Difference\", \"Exclusion\"]\n\n\nclass _BooleanOps(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"This class contains some helper functions which\n    helps to convert to and from skia objects and manim\n    objects (:class:`~.VMobject`).\n    \"\"\"\n\n    def _convert_2d_to_3d_array(\n        self,\n        points: Point2DLike_Array | Point3DLike_Array,\n        z_dim: float = 0.0,\n    ) -> Point3D_Array:\n        \"\"\"Converts an iterable with coordinates in 2D to 3D by adding\n        :attr:`z_dim` as the Z coordinate.\n\n        Parameters\n        ----------\n        points\n            An iterable of points.\n        z_dim\n            Default value for the Z coordinate.\n\n        Returns\n        -------\n        Point3D_Array\n            A list of the points converted to 3D.\n\n        Example\n        -------\n        >>> a = _BooleanOps()\n        >>> p = [(1, 2), (3, 4)]\n        >>> a._convert_2d_to_3d_array(p)\n        array([[1., 2., 0.],\n               [3., 4., 0.]])\n        \"\"\"\n        list_of_points = list(points)\n        for i, point in enumerate(list_of_points):\n            if len(point) == 2:\n                list_of_points[i] = np.append(point, z_dim)\n        return np.asarray(list_of_points)\n\n    def _convert_vmobject_to_skia_path(self, vmobject: VMobject) -> SkiaPath:\n        \"\"\"Converts a :class:`~.VMobject` to SkiaPath. This method only works for\n        cairo renderer because it treats the points as Cubic beizer curves.\n\n        Parameters\n        ----------\n        vmobject:\n            The :class:`~.VMobject` to convert from.\n\n        Returns\n        -------\n        SkiaPath\n            The converted path.\n        \"\"\"\n        path = SkiaPath()\n\n        if np.all(np.isfinite(vmobject.points)):\n            points = vmobject.points\n        else:\n            points = np.zeros((1, 3))  # point invalid?\n\n        if len(points) == 0:  # what? No points so return empty path\n            return path\n\n        # In OpenGL it's quadratic beizer curves while on Cairo it's cubic...\n        if config.renderer == RendererType.OPENGL:\n            subpaths = vmobject.get_subpaths_from_points(points)\n            for subpath in subpaths:\n                quads = vmobject.get_bezier_tuples_from_points(subpath)\n                start = subpath[0]\n                path.moveTo(*start[:2])\n                for _p0, p1, p2 in quads:\n                    path.quadTo(*p1[:2], *p2[:2])\n                if vmobject.consider_points_equals(subpath[0], subpath[-1]):\n                    path.close()\n        elif config.renderer == RendererType.CAIRO:\n            subpaths = vmobject.gen_subpaths_from_points_2d(points)  # type: ignore[assignment]\n            for subpath in subpaths:\n                quads = vmobject.gen_cubic_bezier_tuples_from_points(subpath)\n                start = subpath[0]\n                path.moveTo(*start[:2])\n                for _p0, p1, p2, p3 in quads:\n                    path.cubicTo(*p1[:2], *p2[:2], *p3[:2])\n\n                if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]):\n                    path.close()\n\n        return path\n\n    def _convert_skia_path_to_vmobject(self, path: SkiaPath) -> VMobject:\n        \"\"\"Converts SkiaPath back to VMobject.\n        Parameters\n        ----------\n        path:\n            The SkiaPath to convert.\n\n        Returns\n        -------\n        VMobject:\n            The converted VMobject.\n        \"\"\"\n        vmobject = self\n        current_path_start = np.array([0, 0, 0])\n\n        for path_verb, points in path:\n            if path_verb == PathVerb.MOVE:\n                parts = self._convert_2d_to_3d_array(points)\n                for part in parts:\n                    current_path_start = part\n                    vmobject.start_new_path(part)\n                    # vmobject.move_to(*part)\n            elif path_verb == PathVerb.CUBIC:\n                n1, n2, n3 = self._convert_2d_to_3d_array(points)\n                vmobject.add_cubic_bezier_curve_to(n1, n2, n3)\n            elif path_verb == PathVerb.LINE:\n                parts = self._convert_2d_to_3d_array(points)\n                vmobject.add_line_to(parts[0])\n            elif path_verb == PathVerb.CLOSE:\n                vmobject.add_line_to(current_path_start)\n            elif path_verb == PathVerb.QUAD:\n                n1, n2 = self._convert_2d_to_3d_array(points)\n                vmobject.add_quadratic_bezier_curve_to(n1, n2)\n            else:\n                raise Exception(f\"Unsupported: {path_verb}\")\n        return vmobject\n\n\nclass Union(_BooleanOps):\n    \"\"\"Union of two or more :class:`~.VMobject` s. This returns the common region of\n    the :class:`~VMobject` s.\n\n    Parameters\n    ----------\n    vmobjects\n        The :class:`~.VMobject` s to find the union of.\n\n    Raises\n    ------\n    ValueError\n        If less than 2 :class:`~.VMobject` s are passed.\n\n    Example\n    -------\n    .. manim:: UnionExample\n        :save_last_frame:\n\n        class UnionExample(Scene):\n            def construct(self):\n                sq = Square(color=RED, fill_opacity=1)\n                sq.move_to([-2, 0, 0])\n                cr = Circle(color=BLUE, fill_opacity=1)\n                cr.move_to([-1.3, 0.7, 0])\n                un = Union(sq, cr, color=GREEN, fill_opacity=1)\n                un.move_to([1.5, 0.3, 0])\n                self.add(sq, cr, un)\n\n    \"\"\"\n\n    def __init__(self, *vmobjects: VMobject, **kwargs: Any) -> None:\n        if len(vmobjects) < 2:\n            raise ValueError(\"At least 2 mobjects needed for Union.\")\n        super().__init__(**kwargs)\n        paths = [\n            self._convert_vmobject_to_skia_path(vmobject) for vmobject in vmobjects\n        ]\n        outpen = SkiaPath()\n        union(paths, outpen.getPen())\n        self._convert_skia_path_to_vmobject(outpen)\n\n\nclass Difference(_BooleanOps):\n    \"\"\"Subtracts one :class:`~.VMobject` from another one.\n\n    Parameters\n    ----------\n    subject\n        The 1st :class:`~.VMobject`.\n    clip\n        The 2nd :class:`~.VMobject`\n\n    Example\n    -------\n    .. manim:: DifferenceExample\n        :save_last_frame:\n\n        class DifferenceExample(Scene):\n            def construct(self):\n                sq = Square(color=RED, fill_opacity=1)\n                sq.move_to([-2, 0, 0])\n                cr = Circle(color=BLUE, fill_opacity=1)\n                cr.move_to([-1.3, 0.7, 0])\n                un = Difference(sq, cr, color=GREEN, fill_opacity=1)\n                un.move_to([1.5, 0, 0])\n                self.add(sq, cr, un)\n\n    \"\"\"\n\n    def __init__(self, subject: VMobject, clip: VMobject, **kwargs: Any) -> None:\n        super().__init__(**kwargs)\n        outpen = SkiaPath()\n        difference(\n            [self._convert_vmobject_to_skia_path(subject)],\n            [self._convert_vmobject_to_skia_path(clip)],\n            outpen.getPen(),\n        )\n        self._convert_skia_path_to_vmobject(outpen)\n\n\nclass Intersection(_BooleanOps):\n    \"\"\"Find the intersection of two :class:`~.VMobject` s.\n    This keeps the parts covered by both :class:`~.VMobject` s.\n\n    Parameters\n    ----------\n    vmobjects\n        The :class:`~.VMobject` to find the intersection.\n\n    Raises\n    ------\n    ValueError\n        If less the 2 :class:`~.VMobject` are passed.\n\n    Example\n    -------\n    .. manim:: IntersectionExample\n        :save_last_frame:\n\n        class IntersectionExample(Scene):\n            def construct(self):\n                sq = Square(color=RED, fill_opacity=1)\n                sq.move_to([-2, 0, 0])\n                cr = Circle(color=BLUE, fill_opacity=1)\n                cr.move_to([-1.3, 0.7, 0])\n                un = Intersection(sq, cr, color=GREEN, fill_opacity=1)\n                un.move_to([1.5, 0, 0])\n                self.add(sq, cr, un)\n\n    \"\"\"\n\n    def __init__(self, *vmobjects: VMobject, **kwargs: Any) -> None:\n        if len(vmobjects) < 2:\n            raise ValueError(\"At least 2 mobjects needed for Intersection.\")\n\n        super().__init__(**kwargs)\n        outpen = SkiaPath()\n        intersection(\n            [self._convert_vmobject_to_skia_path(vmobjects[0])],\n            [self._convert_vmobject_to_skia_path(vmobjects[1])],\n            outpen.getPen(),\n        )\n        new_outpen = outpen\n        for _i in range(2, len(vmobjects)):\n            new_outpen = SkiaPath()\n            intersection(\n                [outpen],\n                [self._convert_vmobject_to_skia_path(vmobjects[_i])],\n                new_outpen.getPen(),\n            )\n            outpen = new_outpen\n\n        self._convert_skia_path_to_vmobject(outpen)\n\n\nclass Exclusion(_BooleanOps):\n    \"\"\"Find the XOR between two :class:`~.VMobject`.\n    This creates a new :class:`~.VMobject` consisting of the region\n    covered by exactly one of them.\n\n    Parameters\n    ----------\n    subject\n        The 1st :class:`~.VMobject`.\n    clip\n        The 2nd :class:`~.VMobject`\n\n    Example\n    -------\n    .. manim:: IntersectionExample\n        :save_last_frame:\n\n        class IntersectionExample(Scene):\n            def construct(self):\n                sq = Square(color=RED, fill_opacity=1)\n                sq.move_to([-2, 0, 0])\n                cr = Circle(color=BLUE, fill_opacity=1)\n                cr.move_to([-1.3, 0.7, 0])\n                un = Exclusion(sq, cr, color=GREEN, fill_opacity=1)\n                un.move_to([1.5, 0.4, 0])\n                self.add(sq, cr, un)\n\n    \"\"\"\n\n    def __init__(self, subject: VMobject, clip: VMobject, **kwargs: Any) -> None:\n        super().__init__(**kwargs)\n        outpen = SkiaPath()\n        xor(\n            [self._convert_vmobject_to_skia_path(subject)],\n            [self._convert_vmobject_to_skia_path(clip)],\n            outpen.getPen(),\n        )\n        self._convert_skia_path_to_vmobject(outpen)\n"
  },
  {
    "path": "manim/mobject/geometry/labeled.py",
    "content": "r\"\"\"Mobjects that inherit from lines and contain a label along the length.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"Label\", \"LabeledLine\", \"LabeledArrow\", \"LabeledPolygram\"]\n\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom manim.constants import *\nfrom manim.mobject.geometry.line import Arrow, Line\nfrom manim.mobject.geometry.polygram import Polygram\nfrom manim.mobject.geometry.shape_matchers import (\n    BackgroundRectangle,\n    SurroundingRectangle,\n)\nfrom manim.mobject.text.tex_mobject import MathTex, Tex\nfrom manim.mobject.text.text_mobject import Text\nfrom manim.mobject.types.vectorized_mobject import VGroup\nfrom manim.utils.color import WHITE\nfrom manim.utils.polylabel import polylabel\n\nif TYPE_CHECKING:\n    from manim.typing import Point3DLike_Array\n\n\nclass Label(VGroup):\n    \"\"\"A Label consisting of text surrounded by a frame.\n\n    Parameters\n    ----------\n    label\n        Label that will be displayed.\n    label_config\n        A dictionary containing the configuration for the label.\n        This is only applied if ``label`` is of type ``str``.\n    box_config\n        A dictionary containing the configuration for the background box.\n    frame_config\n         A dictionary containing the configuration for the frame.\n\n    Examples\n    --------\n    .. manim:: LabelExample\n        :save_last_frame:\n        :quality: high\n\n        class LabelExample(Scene):\n            def construct(self):\n                label = Label(\n                    label=Text('Label Text', font='sans-serif'),\n                    box_config = {\n                        \"color\" : BLUE,\n                        \"fill_opacity\" : 0.75\n                    }\n                )\n                label.scale(3)\n                self.add(label)\n    \"\"\"\n\n    def __init__(\n        self,\n        label: str | Tex | MathTex | Text,\n        label_config: dict[str, Any] | None = None,\n        box_config: dict[str, Any] | None = None,\n        frame_config: dict[str, Any] | None = None,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(**kwargs)\n\n        # Setup Defaults\n        default_label_config: dict[str, Any] = {\n            \"color\": WHITE,\n            \"font_size\": DEFAULT_FONT_SIZE,\n        }\n\n        default_box_config: dict[str, Any] = {\n            \"color\": None,\n            \"buff\": 0.05,\n            \"fill_opacity\": 1,\n            \"stroke_width\": 0.5,\n        }\n\n        default_frame_config: dict[str, Any] = {\n            \"color\": WHITE,\n            \"buff\": 0.05,\n            \"stroke_width\": 0.5,\n        }\n\n        # Merge Defaults\n        label_config = default_label_config | (label_config or {})\n        box_config = default_box_config | (box_config or {})\n        frame_config = default_frame_config | (frame_config or {})\n\n        # Determine the type of label and instantiate the appropriate object\n        self.rendered_label: MathTex | Tex | Text\n        if isinstance(label, str):\n            self.rendered_label = MathTex(label, **label_config)\n        elif isinstance(label, (MathTex, Tex, Text)):\n            self.rendered_label = label\n        else:\n            raise TypeError(\"Unsupported label type. Must be MathTex, Tex, or Text.\")\n\n        # Add a background box\n        self.background_rect = BackgroundRectangle(self.rendered_label, **box_config)\n\n        # Add a frame around the label\n        self.frame = SurroundingRectangle(self.rendered_label, **frame_config)\n\n        # Add components to the VGroup\n        self.add(self.background_rect, self.rendered_label, self.frame)\n\n\nclass LabeledLine(Line):\n    \"\"\"Constructs a line containing a label box somewhere along its length.\n\n    Parameters\n    ----------\n    label\n        Label that will be displayed on the line.\n    label_position\n        A ratio in the range [0-1] to indicate the position of the label with respect to the length of the line. Default value is 0.5.\n    label_config\n        A dictionary containing the configuration for the label.\n        This is only applied if ``label`` is of type ``str``.\n    box_config\n        A dictionary containing the configuration for the background box.\n    frame_config\n         A dictionary containing the configuration for the frame.\n\n        .. seealso::\n            :class:`LabeledArrow`\n\n    Examples\n    --------\n    .. manim:: LabeledLineExample\n        :save_last_frame:\n        :quality: high\n\n        class LabeledLineExample(Scene):\n            def construct(self):\n                line = LabeledLine(\n                    label          = '0.5',\n                    label_position = 0.8,\n                    label_config = {\n                        \"font_size\" : 20\n                    },\n                    start=LEFT+DOWN,\n                    end=RIGHT+UP)\n\n                line.set_length(line.get_length() * 2)\n                self.add(line)\n    \"\"\"\n\n    def __init__(\n        self,\n        label: str | Tex | MathTex | Text,\n        label_position: float = 0.5,\n        label_config: dict[str, Any] | None = None,\n        box_config: dict[str, Any] | None = None,\n        frame_config: dict[str, Any] | None = None,\n        *args: Any,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(*args, **kwargs)\n\n        # Create Label\n        self.label = Label(\n            label=label,\n            label_config=label_config,\n            box_config=box_config,\n            frame_config=frame_config,\n        )\n\n        # Compute Label Position\n        line_start, line_end = self.get_start_and_end()\n        new_vec = (line_end - line_start) * label_position\n        label_coords = line_start + new_vec\n\n        self.label.move_to(label_coords)\n        self.add(self.label)\n\n\nclass LabeledArrow(LabeledLine, Arrow):\n    \"\"\"Constructs an arrow containing a label box somewhere along its length.\n    This class inherits its label properties from `LabeledLine`, so the main parameters controlling it are the same.\n\n    Parameters\n    ----------\n    label\n        Label that will be displayed on the Arrow.\n    label_position\n        A ratio in the range [0-1] to indicate the position of the label with respect to the length of the line. Default value is 0.5.\n    label_config\n        A dictionary containing the configuration for the label.\n        This is only applied if ``label`` is of type ``str``.\n    box_config\n        A dictionary containing the configuration for the background box.\n    frame_config\n         A dictionary containing the configuration for the frame.\n\n        .. seealso::\n            :class:`LabeledLine`\n\n    Examples\n    --------\n    .. manim:: LabeledArrowExample\n        :save_last_frame:\n        :quality: high\n\n        class LabeledArrowExample(Scene):\n            def construct(self):\n                l_arrow = LabeledArrow(\"0.5\", start=LEFT*3, end=RIGHT*3 + UP*2, label_position=0.5)\n\n                self.add(l_arrow)\n    \"\"\"\n\n    def __init__(\n        self,\n        *args: Any,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(*args, **kwargs)\n\n\nclass LabeledPolygram(Polygram):\n    \"\"\"Constructs a polygram containing a label box at its pole of inaccessibility.\n\n    Parameters\n    ----------\n    vertex_groups\n        Vertices passed to the :class:`~.Polygram` constructor.\n    label\n        Label that will be displayed on the Polygram.\n    precision\n        The precision used by the PolyLabel algorithm.\n    label_config\n        A dictionary containing the configuration for the label.\n        This is only applied if ``label`` is of type ``str``.\n    box_config\n        A dictionary containing the configuration for the background box.\n    frame_config\n         A dictionary containing the configuration for the frame.\n\n        .. note::\n            The PolyLabel Algorithm expects each vertex group to form a closed ring.\n            If the input is open, :class:`LabeledPolygram` will attempt to close it.\n            This may cause the polygon to intersect itself leading to unexpected results.\n\n        .. tip::\n            Make sure the precision corresponds to the scale of your inputs!\n            For instance, if the bounding box of your polygon stretches from 0 to 10,000, a precision of 1.0 or 10.0 should be sufficient.\n\n    Examples\n    --------\n    .. manim:: LabeledPolygramExample\n        :save_last_frame:\n        :quality: high\n\n        class LabeledPolygramExample(Scene):\n            def construct(self):\n                # Define Rings\n                ring1 = [\n                    [-3.8, -2.4, 0], [-2.4, -2.5, 0], [-1.3, -1.6, 0], [-0.2, -1.7, 0],\n                    [1.7, -2.5, 0], [2.9, -2.6, 0], [3.5, -1.5, 0], [4.9, -1.4, 0],\n                    [4.5, 0.2, 0], [4.7, 1.6, 0], [3.5, 2.4, 0], [1.1, 2.5, 0],\n                    [-0.1, 0.9, 0], [-1.2, 0.5, 0], [-1.6, 0.7, 0], [-1.4, 1.9, 0],\n                    [-2.6, 2.6, 0], [-4.4, 1.2, 0], [-4.9, -0.8, 0], [-3.8, -2.4, 0]\n                ]\n                ring2 = [\n                    [0.2, -1.2, 0], [0.9, -1.2, 0], [1.4, -2.0, 0], [2.1, -1.6, 0],\n                    [2.2, -0.5, 0], [1.4, 0.0, 0], [0.4, -0.2, 0], [0.2, -1.2, 0]\n                ]\n                ring3 = [[-2.7, 1.4, 0], [-2.3, 1.7, 0], [-2.8, 1.9, 0], [-2.7, 1.4, 0]]\n\n                # Create Polygons (for reference)\n                p1 = Polygon(*ring1, fill_opacity=0.75)\n                p2 = Polygon(*ring2, fill_color=BLACK, fill_opacity=1)\n                p3 = Polygon(*ring3, fill_color=BLACK, fill_opacity=1)\n\n                # Create Labeled Polygram\n                polygram = LabeledPolygram(\n                    *[ring1, ring2, ring3],\n                    label=Text('Pole', font='sans-serif'),\n                    precision=0.01,\n                )\n\n                # Display Circle (for reference)\n                circle = Circle(radius=polygram.radius, color=WHITE).move_to(polygram.pole)\n\n                self.add(p1, p2, p3)\n                self.add(polygram)\n                self.add(circle)\n\n    .. manim:: LabeledCountryExample\n        :save_last_frame:\n        :quality: high\n\n        import requests\n        import json\n\n        class LabeledCountryExample(Scene):\n            def construct(self):\n                # Fetch JSON data and process arcs\n                data = requests.get('https://cdn.jsdelivr.net/npm/us-atlas@3/nation-10m.json').json()\n                arcs, transform = data['arcs'], data['transform']\n                sarcs = [np.cumsum(arc, axis=0) * transform['scale'] + transform['translate'] for arc in arcs]\n                ssarcs = sorted(sarcs, key=len, reverse=True)[:1]\n\n                # Compute Bounding Box\n                points = np.concatenate(ssarcs)\n                mins, maxs = np.min(points, axis=0), np.max(points, axis=0)\n\n                # Build Axes\n                ax = Axes(\n                    x_range=[mins[0], maxs[0], maxs[0] - mins[0]], x_length=10,\n                    y_range=[mins[1], maxs[1], maxs[1] - mins[1]], y_length=7,\n                    tips=False\n                )\n\n                # Adjust Coordinates\n                array = [[ax.c2p(*point) for point in sarc] for sarc in ssarcs]\n\n                # Add Polygram\n                polygram = LabeledPolygram(\n                    *array,\n                    label=Text('USA', font='sans-serif'),\n                    precision=0.01,\n                    fill_color=BLUE,\n                    stroke_width=0,\n                    fill_opacity=0.75\n                )\n\n                # Display Circle (for reference)\n                circle = Circle(radius=polygram.radius, color=WHITE).move_to(polygram.pole)\n\n                self.add(ax)\n                self.add(polygram)\n                self.add(circle)\n    \"\"\"\n\n    def __init__(\n        self,\n        *vertex_groups: Point3DLike_Array,\n        label: str | Tex | MathTex | Text,\n        precision: float = 0.01,\n        label_config: dict[str, Any] | None = None,\n        box_config: dict[str, Any] | None = None,\n        frame_config: dict[str, Any] | None = None,\n        **kwargs: Any,\n    ) -> None:\n        # Initialize the Polygram with the vertex groups\n        super().__init__(*vertex_groups, **kwargs)\n\n        # Create Label\n        self.label = Label(\n            label=label,\n            label_config=label_config,\n            box_config=box_config,\n            frame_config=frame_config,\n        )\n\n        # Close Vertex Groups\n        rings = [\n            group if np.array_equal(group[0], group[-1]) else list(group) + [group[0]]\n            for group in vertex_groups\n        ]\n\n        # Compute the Pole of Inaccessibility\n        cell = polylabel(rings, precision=precision)\n        self.pole, self.radius = np.pad(cell.c, (0, 1), \"constant\"), cell.d\n\n        # Position the label at the pole\n        self.label.move_to(self.pole)\n        self.add(self.label)\n"
  },
  {
    "path": "manim/mobject/geometry/line.py",
    "content": "r\"\"\"Mobjects that are lines or variations of them.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"Line\",\n    \"DashedLine\",\n    \"TangentLine\",\n    \"Elbow\",\n    \"Arrow\",\n    \"Vector\",\n    \"DoubleArrow\",\n    \"Angle\",\n    \"RightAngle\",\n]\n\nfrom typing import TYPE_CHECKING, Any, Literal, cast\n\nimport numpy as np\n\nfrom manim import config\nfrom manim.constants import *\nfrom manim.mobject.geometry.arc import Arc, ArcBetweenPoints, Dot, TipableVMobject\nfrom manim.mobject.geometry.tips import ArrowTip, ArrowTriangleFilledTip\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.mobject.types.vectorized_mobject import DashedVMobject, VGroup, VMobject\nfrom manim.utils.color import WHITE\nfrom manim.utils.space_ops import angle_of_vector, line_intersection, normalize\n\nif TYPE_CHECKING:\n    from typing import Self, TypeAlias\n\n    from manim.typing import Point3D, Point3DLike, Vector2DLike, Vector3D, Vector3DLike\n    from manim.utils.color import ParsableManimColor\n\n    from ..matrix import Matrix  # Avoid circular import\n\n    AngleQuadrant: TypeAlias = tuple[Literal[-1, 1], Literal[-1, 1]]\n    r\"\"\"A tuple of 2 integers which can be either +1 or -1, allowing to select\n    one of the 4 quadrants of the Cartesian plane.\n\n    Let :math:`L_1,\\ L_2` be two lines defined by start points\n    :math:`S_1,\\ S_2` and end points :math:`E_1,\\ E_2`. We define the \"positive\n    direction\" of :math:`L_1` as the direction from :math:`S_1` to :math:`E_1`,\n    and its \"negative direction\" as the opposite one. We do the same with\n    :math:`L_2`.\n\n    If :math:`L_1` and :math:`L_2` intersect, they divide the plane into 4\n    quadrants. To pick one quadrant, choose the integers in this tuple in the\n    following way:\n\n    -   If the 1st integer is +1, select one of the 2 quadrants towards the\n        positive direction of :math:`L_1`, i.e. closest to `E_1`. Otherwise, if\n        the 1st integer is -1, select one of the 2 quadrants towards the\n        negative direction of :math:`L_1`, i.e. closest to `S_1`.\n\n    -   Similarly, the sign of the 2nd integer picks the positive or negative\n        direction of :math:`L_2` and, thus, selects one of the 2 quadrants\n        which  are closest to :math:`E_2` or :math:`S_2` respectively.\n    \"\"\"\n\n\nclass Line(TipableVMobject):\n    \"\"\"A straight or curved line segment between two points or mobjects.\n\n    Parameters\n    ----------\n    start\n        The starting point or Mobject of the line.\n    end\n        The ending point or Mobject of the line.\n    buff\n        The distance to shorten the line from both ends.\n    path_arc\n        If nonzero, the line will be curved into an arc with this angle (in radians).\n    kwargs\n        Additional arguments to be passed to :class:`TipableVMobject`\n\n    Examples\n    --------\n    .. manim:: LineExample\n        :save_last_frame:\n\n        class LineExample(Scene):\n            def construct(self):\n                line1 = Line(LEFT*2, RIGHT*2)\n                line2 = Line(LEFT*2, RIGHT*2, buff=0.5)\n                line3 = Line(LEFT*2, RIGHT*2, path_arc=PI/2)\n                grp = VGroup(line1,line2,line3).arrange(DOWN, buff=2)\n                self.add(grp)\n    \"\"\"\n\n    def __init__(\n        self,\n        start: Point3DLike | Mobject = LEFT,\n        end: Point3DLike | Mobject = RIGHT,\n        buff: float = 0,\n        path_arc: float = 0,\n        **kwargs: Any,\n    ) -> None:\n        self.dim = 3\n        self.buff = buff\n        self.path_arc = path_arc\n        self._set_start_and_end_attrs(start, end)\n        super().__init__(**kwargs)\n\n    def generate_points(self) -> None:\n        self.set_points_by_ends(\n            start=self.start,\n            end=self.end,\n            buff=self.buff,\n            path_arc=self.path_arc,\n        )\n\n    def set_points_by_ends(\n        self,\n        start: Point3DLike | Mobject,\n        end: Point3DLike | Mobject,\n        buff: float = 0,\n        path_arc: float = 0,\n    ) -> None:\n        \"\"\"Sets the points of the line based on its start and end points.\n        Unlike :meth:`put_start_and_end_on`, this method respects `self.buff` and\n        Mobject bounding boxes.\n\n        Parameters\n        ----------\n        start\n            The start point or Mobject of the line.\n        end\n            The end point or Mobject of the line.\n        buff\n            The empty space between the start and end of the line, by default 0.\n        path_arc\n            The angle of a circle spanned by this arc, by default 0 which is a straight line.\n        \"\"\"\n        self._set_start_and_end_attrs(start, end)\n        if path_arc:\n            arc = ArcBetweenPoints(self.start, self.end, angle=self.path_arc)\n            self.set_points(arc.points)\n        else:\n            self.set_points_as_corners(np.asarray([self.start, self.end]))\n\n        self._account_for_buff(buff)\n\n    def init_points(self) -> None:\n        self.generate_points()\n\n    def _account_for_buff(self, buff: float) -> None:\n        if buff <= 0:\n            return\n        length = self.get_length() if self.path_arc == 0 else self.get_arc_length()\n        if length < 2 * buff:\n            return\n        buff_proportion = buff / length\n        self.pointwise_become_partial(self, buff_proportion, 1 - buff_proportion)\n\n    def _set_start_and_end_attrs(\n        self, start: Point3DLike | Mobject, end: Point3DLike | Mobject\n    ) -> None:\n        # If either start or end are Mobjects, this\n        # gives their centers\n        rough_start = self._pointify(start)\n        rough_end = self._pointify(end)\n        vect = normalize(rough_end - rough_start)\n        # Now that we know the direction between them,\n        # we can find the appropriate boundary point from\n        # start and end, if they're mobjects\n        self.start = self._pointify(start, vect)\n        self.end = self._pointify(end, -vect)\n\n    def _pointify(\n        self,\n        mob_or_point: Mobject | Point3DLike,\n        direction: Vector3DLike | None = None,\n    ) -> Point3D:\n        \"\"\"Transforms a mobject into its corresponding point. Does nothing if a point is passed.\n\n        ``direction`` determines the location of the point along its bounding box in that direction.\n\n        Parameters\n        ----------\n        mob_or_point\n            The mobject or point.\n        direction\n            The direction.\n        \"\"\"\n        if isinstance(mob_or_point, (Mobject, OpenGLMobject)):\n            mob = mob_or_point\n            if direction is None:\n                return mob.get_center()\n            else:\n                return mob.get_boundary_point(direction)\n        return np.array(mob_or_point)\n\n    def set_path_arc(self, new_value: float) -> None:\n        self.path_arc = new_value\n        self.init_points()\n\n    def put_start_and_end_on(\n        self,\n        start: Point3DLike,\n        end: Point3DLike,\n    ) -> Self:\n        \"\"\"Sets starts and end coordinates of a line.\n\n        Examples\n        --------\n        .. manim:: LineExample\n\n            class LineExample(Scene):\n                def construct(self):\n                    d = VGroup()\n                    for i in range(0,10):\n                        d.add(Dot())\n                    d.arrange_in_grid(buff=1)\n                    self.add(d)\n                    l= Line(d[0], d[1])\n                    self.add(l)\n                    self.wait()\n                    l.put_start_and_end_on(d[1].get_center(), d[2].get_center())\n                    self.wait()\n                    l.put_start_and_end_on(d[4].get_center(), d[7].get_center())\n                    self.wait()\n        \"\"\"\n        curr_start, curr_end = self.get_start_and_end()\n        if np.all(curr_start == curr_end):\n            # TODO, any problems with resetting\n            # these attrs?\n            self.start = np.asarray(start)\n            self.end = np.asarray(end)\n            self.generate_points()\n        return super().put_start_and_end_on(start, end)\n\n    def get_vector(self) -> Vector3D:\n        return self.get_end() - self.get_start()\n\n    def get_unit_vector(self) -> Vector3D:\n        return normalize(self.get_vector())\n\n    def get_angle(self) -> float:\n        return angle_of_vector(self.get_vector())\n\n    def get_projection(self, point: Point3DLike) -> Point3D:\n        \"\"\"Returns the projection of a point onto a line.\n\n        Parameters\n        ----------\n        point\n            The point to which the line is projected.\n        \"\"\"\n        start = self.get_start()\n        end = self.get_end()\n        unit_vect = normalize(end - start)\n        return start + float(np.dot(point - start, unit_vect)) * unit_vect\n\n    def get_slope(self) -> float:\n        return float(np.tan(self.get_angle()))\n\n    def set_angle(self, angle: float, about_point: Point3DLike | None = None) -> Self:\n        if about_point is None:\n            about_point = self.get_start()\n\n        self.rotate(\n            angle - self.get_angle(),\n            about_point=about_point,\n        )\n\n        return self\n\n    def set_length(self, length: float) -> Self:\n        scale_factor: float = length / self.get_length()\n        return self.scale(scale_factor)\n\n\nclass DashedLine(Line):\n    \"\"\"A dashed :class:`Line`.\n\n    Parameters\n    ----------\n    args\n        Arguments to be passed to :class:`Line`\n    dash_length\n        The length of each individual dash of the line.\n    dashed_ratio\n        The ratio of dash space to empty space. Range of 0-1.\n    kwargs\n        Additional arguments to be passed to :class:`Line`\n\n\n    .. seealso::\n        :class:`~.DashedVMobject`\n\n    Examples\n    --------\n    .. manim:: DashedLineExample\n        :save_last_frame:\n\n        class DashedLineExample(Scene):\n            def construct(self):\n                # dash_length increased\n                dashed_1 = DashedLine(config.left_side, config.right_side, dash_length=2.0).shift(UP*2)\n                # normal\n                dashed_2 = DashedLine(config.left_side, config.right_side)\n                # dashed_ratio decreased\n                dashed_3 = DashedLine(config.left_side, config.right_side, dashed_ratio=0.1).shift(DOWN*2)\n                self.add(dashed_1, dashed_2, dashed_3)\n    \"\"\"\n\n    def __init__(\n        self,\n        *args: Any,\n        dash_length: float = DEFAULT_DASH_LENGTH,\n        dashed_ratio: float = 0.5,\n        **kwargs: Any,\n    ) -> None:\n        self.dash_length = dash_length\n        self.dashed_ratio = dashed_ratio\n        super().__init__(*args, **kwargs)\n        dashes = DashedVMobject(\n            self,\n            num_dashes=self._calculate_num_dashes(),\n            dashed_ratio=dashed_ratio,\n        )\n        self.clear_points()\n        self.add(*dashes)\n\n    def _calculate_num_dashes(self) -> int:\n        \"\"\"Returns the number of dashes in the dashed line.\n\n        Examples\n        --------\n        ::\n\n            >>> DashedLine()._calculate_num_dashes()\n            20\n        \"\"\"\n        # Minimum number of dashes has to be 2\n        return max(\n            2,\n            int(np.ceil((self.get_length() / self.dash_length) * self.dashed_ratio)),\n        )\n\n    def get_start(self) -> Point3D:\n        \"\"\"Returns the start point of the line.\n\n        Examples\n        --------\n        ::\n\n            >>> DashedLine().get_start()\n            array([-1.,  0.,  0.])\n        \"\"\"\n        if len(self.submobjects) > 0:\n            return self.submobjects[0].get_start()\n        else:\n            return super().get_start()\n\n    def get_end(self) -> Point3D:\n        \"\"\"Returns the end point of the line.\n\n        Examples\n        --------\n        ::\n\n            >>> DashedLine().get_end()\n            array([1., 0., 0.])\n        \"\"\"\n        if len(self.submobjects) > 0:\n            return self.submobjects[-1].get_end()\n        else:\n            return super().get_end()\n\n    def get_first_handle(self) -> Point3D:\n        \"\"\"Returns the point of the first handle.\n\n        Examples\n        --------\n        ::\n\n            >>> DashedLine().get_first_handle()\n            array([-0.98333333,  0.        ,  0.        ])\n        \"\"\"\n        # Type inference of extracting an element from a list, is not\n        # supported by numpy, see this numpy issue\n        # https://github.com/numpy/numpy/issues/16544\n        first_handle: Point3D = self.submobjects[0].points[1]\n        return first_handle\n\n    def get_last_handle(self) -> Point3D:\n        \"\"\"Returns the point of the last handle.\n\n        Examples\n        --------\n        ::\n\n            >>> DashedLine().get_last_handle()\n            array([0.98333333, 0.        , 0.        ])\n        \"\"\"\n        # Type inference of extracting an element from a list, is not\n        # supported by numpy, see this numpy issue\n        # https://github.com/numpy/numpy/issues/16544\n        last_handle: Point3D = self.submobjects[-1].points[2]\n        return last_handle\n\n\nclass TangentLine(Line):\n    \"\"\"Constructs a line tangent to a :class:`~.VMobject` at a specific point.\n\n    Parameters\n    ----------\n    vmob\n        The VMobject on which the tangent line is drawn.\n    alpha\n        How far along the shape that the line will be constructed. range: 0-1.\n    length\n        Length of the tangent line.\n    d_alpha\n        The ``dx`` value\n    kwargs\n        Additional arguments to be passed to :class:`Line`\n\n\n    .. seealso::\n        :meth:`~.VMobject.point_from_proportion`\n\n    Examples\n    --------\n    .. manim:: TangentLineExample\n        :save_last_frame:\n\n        class TangentLineExample(Scene):\n            def construct(self):\n                circle = Circle(radius=2)\n                line_1 = TangentLine(circle, alpha=0.0, length=4, color=BLUE_D) # right\n                line_2 = TangentLine(circle, alpha=0.4, length=4, color=GREEN) # top left\n                self.add(circle, line_1, line_2)\n    \"\"\"\n\n    def __init__(\n        self,\n        vmob: VMobject,\n        alpha: float,\n        length: float = 1,\n        d_alpha: float = 1e-6,\n        **kwargs: Any,\n    ) -> None:\n        self.length = length\n        self.d_alpha = d_alpha\n        da = self.d_alpha\n        a1 = np.clip(alpha - da, 0, 1)\n        a2 = np.clip(alpha + da, 0, 1)\n        super().__init__(\n            vmob.point_from_proportion(a1), vmob.point_from_proportion(a2), **kwargs\n        )\n        self.scale(self.length / self.get_length())\n\n\nclass Elbow(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"Two lines that create a right angle about each other: L-shape.\n\n    Parameters\n    ----------\n    width\n        The length of the elbow's sides.\n    angle\n        The rotation of the elbow.\n    kwargs\n        Additional arguments to be passed to :class:`~.VMobject`\n\n    .. seealso::\n        :class:`RightAngle`\n\n    Examples\n    --------\n    .. manim:: ElbowExample\n        :save_last_frame:\n\n        class ElbowExample(Scene):\n            def construct(self):\n                elbow_1 = Elbow()\n                elbow_2 = Elbow(width=2.0)\n                elbow_3 = Elbow(width=2.0, angle=5*PI/4)\n\n                elbow_group = Group(elbow_1, elbow_2, elbow_3).arrange(buff=1)\n                self.add(elbow_group)\n    \"\"\"\n\n    def __init__(self, width: float = 0.2, angle: float = 0, **kwargs: Any) -> None:\n        self.angle = angle\n        super().__init__(**kwargs)\n        self.set_points_as_corners(np.array([UP, UP + RIGHT, RIGHT]))\n        self.scale_to_fit_width(width, about_point=ORIGIN)\n        self.rotate(self.angle, about_point=ORIGIN)\n\n\nclass Arrow(Line):\n    \"\"\"An arrow.\n\n    Parameters\n    ----------\n    args\n        Arguments to be passed to :class:`Line`.\n    stroke_width\n        The thickness of the arrow. Influenced by :attr:`max_stroke_width_to_length_ratio`.\n    buff\n        The distance of the arrow from its start and end points.\n    max_tip_length_to_length_ratio\n        :attr:`tip_length` scales with the length of the arrow. Increasing this ratio raises the max value of :attr:`tip_length`.\n    max_stroke_width_to_length_ratio\n        :attr:`stroke_width` scales with the length of the arrow. Increasing this ratio ratios the max value of :attr:`stroke_width`.\n    kwargs\n        Additional arguments to be passed to :class:`Line`.\n\n\n    .. seealso::\n        :class:`ArrowTip`\n        :class:`CurvedArrow`\n\n    Examples\n    --------\n    .. manim:: ArrowExample\n        :save_last_frame:\n\n        from manim.mobject.geometry.tips import ArrowSquareTip\n        class ArrowExample(Scene):\n            def construct(self):\n                arrow_1 = Arrow(start=RIGHT, end=LEFT, color=GOLD)\n                arrow_2 = Arrow(start=RIGHT, end=LEFT, color=GOLD, tip_shape=ArrowSquareTip).shift(DOWN)\n                g1 = Group(arrow_1, arrow_2)\n\n                # the effect of buff\n                square = Square(color=MAROON_A)\n                arrow_3 = Arrow(start=LEFT, end=RIGHT)\n                arrow_4 = Arrow(start=LEFT, end=RIGHT, buff=0).next_to(arrow_1, UP)\n                g2 = Group(arrow_3, arrow_4, square)\n\n                # a shorter arrow has a shorter tip and smaller stroke width\n                arrow_5 = Arrow(start=ORIGIN, end=config.top).shift(LEFT * 4)\n                arrow_6 = Arrow(start=config.top + DOWN, end=config.top).shift(LEFT * 3)\n                g3 = Group(arrow_5, arrow_6)\n\n                self.add(Group(g1, g2, g3).arrange(buff=2))\n\n\n    .. manim:: ArrowExample\n        :save_last_frame:\n\n        class ArrowExample(Scene):\n            def construct(self):\n                left_group = VGroup()\n                # As buff increases, the size of the arrow decreases.\n                for buff in np.arange(0, 2.2, 0.45):\n                    left_group += Arrow(buff=buff, start=2 * LEFT, end=2 * RIGHT)\n                # Required to arrange arrows.\n                left_group.arrange(DOWN)\n                left_group.move_to(4 * LEFT)\n\n                middle_group = VGroup()\n                # As max_stroke_width_to_length_ratio gets bigger,\n                # the width of stroke increases.\n                for i in np.arange(0, 5, 0.5):\n                    middle_group += Arrow(max_stroke_width_to_length_ratio=i)\n                middle_group.arrange(DOWN)\n\n                UR_group = VGroup()\n                # As max_tip_length_to_length_ratio increases,\n                # the length of the tip increases.\n                for i in np.arange(0, 0.3, 0.1):\n                    UR_group += Arrow(max_tip_length_to_length_ratio=i)\n                UR_group.arrange(DOWN)\n                UR_group.move_to(4 * RIGHT + 2 * UP)\n\n                DR_group = VGroup()\n                DR_group += Arrow(start=LEFT, end=RIGHT, color=BLUE, tip_shape=ArrowSquareTip)\n                DR_group += Arrow(start=LEFT, end=RIGHT, color=BLUE, tip_shape=ArrowSquareFilledTip)\n                DR_group += Arrow(start=LEFT, end=RIGHT, color=YELLOW, tip_shape=ArrowCircleTip)\n                DR_group += Arrow(start=LEFT, end=RIGHT, color=YELLOW, tip_shape=ArrowCircleFilledTip)\n                DR_group.arrange(DOWN)\n                DR_group.move_to(4 * RIGHT + 2 * DOWN)\n\n                self.add(left_group, middle_group, UR_group, DR_group)\n    \"\"\"\n\n    def __init__(\n        self,\n        *args: Any,\n        stroke_width: float = 6,\n        buff: float = MED_SMALL_BUFF,\n        max_tip_length_to_length_ratio: float = 0.25,\n        max_stroke_width_to_length_ratio: float = 5,\n        **kwargs: Any,\n    ) -> None:\n        self.max_tip_length_to_length_ratio = max_tip_length_to_length_ratio\n        self.max_stroke_width_to_length_ratio = max_stroke_width_to_length_ratio\n        tip_shape = kwargs.pop(\"tip_shape\", ArrowTriangleFilledTip)\n        super().__init__(*args, buff=buff, stroke_width=stroke_width, **kwargs)  # type: ignore[misc]\n        # TODO, should this be affected when\n        # Arrow.set_stroke is called?\n        self.initial_stroke_width = self.stroke_width\n        self.add_tip(tip_shape=tip_shape)\n        self._set_stroke_width_from_length()\n\n    def scale(self, factor: float, scale_tips: bool = False, **kwargs: Any) -> Self:  # type: ignore[override]\n        r\"\"\"Scale an arrow, but keep stroke width and arrow tip size fixed.\n\n\n        .. seealso::\n            :meth:`~.Mobject.scale`\n\n        Examples\n        --------\n        ::\n\n            >>> arrow = Arrow(np.array([-1, -1, 0]), np.array([1, 1, 0]), buff=0)\n            >>> scaled_arrow = arrow.scale(2)\n            >>> np.round(scaled_arrow.get_start_and_end(), 8) + 0\n            array([[-2., -2.,  0.],\n                   [ 2.,  2.,  0.]])\n            >>> arrow.tip.length == scaled_arrow.tip.length\n            True\n\n        Manually scaling the object using the default method\n        :meth:`~.Mobject.scale` does not have the same properties::\n\n            >>> new_arrow = Arrow(np.array([-1, -1, 0]), np.array([1, 1, 0]), buff=0)\n            >>> another_scaled_arrow = VMobject.scale(new_arrow, 2)\n            >>> another_scaled_arrow.tip.length == arrow.tip.length\n            False\n\n        \"\"\"\n        if self.get_length() == 0:\n            return self\n\n        if scale_tips:\n            super().scale(factor, **kwargs)\n            self._set_stroke_width_from_length()\n            return self\n\n        has_tip = self.has_tip()\n        has_start_tip = self.has_start_tip()\n        if has_tip or has_start_tip:\n            old_tips = self.pop_tips()\n\n        super().scale(factor, **kwargs)\n        self._set_stroke_width_from_length()\n\n        if has_tip:\n            # error: Argument \"tip\" to \"add_tip\" of \"TipableVMobject\" has incompatible type \"VMobject\"; expected \"ArrowTip | None\"  [arg-type]\n            self.add_tip(tip=cast(ArrowTip, old_tips[0]))\n        if has_start_tip:\n            # error: Argument \"tip\" to \"add_tip\" of \"TipableVMobject\" has incompatible type \"VMobject\"; expected \"ArrowTip | None\"  [arg-type]\n            self.add_tip(tip=cast(ArrowTip, old_tips[1]), at_start=True)\n        return self\n\n    def get_normal_vector(self) -> Vector3D:\n        \"\"\"Returns the normal of a vector.\n\n        Examples\n        --------\n        ::\n\n            >>> np.round(Arrow().get_normal_vector()) + 0. # add 0. to avoid negative 0 in output\n            array([ 0.,  0., -1.])\n        \"\"\"\n        p0, p1, p2 = self.tip.get_start_anchors()[:3]\n        return normalize(np.cross(p2 - p1, p1 - p0))\n\n    def reset_normal_vector(self) -> Self:\n        \"\"\"Resets the normal of a vector\"\"\"\n        self.normal_vector = self.get_normal_vector()\n        return self\n\n    def get_default_tip_length(self) -> float:\n        \"\"\"Returns the default tip_length of the arrow.\n\n        Examples\n        --------\n\n        ::\n\n            >>> Arrow().get_default_tip_length()\n            0.35\n        \"\"\"\n        max_ratio = self.max_tip_length_to_length_ratio\n        return min(self.tip_length, max_ratio * self.get_length())\n\n    def _set_stroke_width_from_length(self) -> Self:\n        \"\"\"Sets stroke width based on length.\"\"\"\n        max_ratio = self.max_stroke_width_to_length_ratio\n        if config.renderer == RendererType.OPENGL:\n            # Mypy does not recognize that the self object in this case\n            # is a OpenGLVMobject and that the set_stroke method is\n            # defined here:\n            # mobject/opengl/opengl_vectorized_mobject.py#L248\n            self.set_stroke(  # type: ignore[call-arg]\n                width=min(self.initial_stroke_width, max_ratio * self.get_length()),\n                recurse=False,\n            )\n        else:\n            self.set_stroke(\n                width=min(self.initial_stroke_width, max_ratio * self.get_length()),\n                family=False,\n            )\n        return self\n\n\nclass Vector(Arrow):\n    \"\"\"A vector specialized for use in graphs.\n\n    .. caution::\n        Do not confuse with the :class:`~.Vector2D`,\n        :class:`~.Vector3D` or :class:`~.VectorND` type aliases,\n        which are not Mobjects!\n\n    Parameters\n    ----------\n    direction\n        The direction of the arrow.\n    buff\n         The distance of the vector from its endpoints.\n    kwargs\n        Additional arguments to be passed to :class:`Arrow`\n\n    Examples\n    --------\n    .. manim:: VectorExample\n        :save_last_frame:\n\n        class VectorExample(Scene):\n            def construct(self):\n                plane = NumberPlane()\n                vector_1 = Vector([1,2])\n                vector_2 = Vector([-5,-2])\n                self.add(plane, vector_1, vector_2)\n    \"\"\"\n\n    def __init__(\n        self,\n        direction: Vector2DLike | Vector3DLike = RIGHT,\n        buff: float = 0,\n        **kwargs: Any,\n    ) -> None:\n        self.buff = buff\n        if len(direction) == 2:\n            direction = np.hstack([direction, 0])\n\n        super().__init__(ORIGIN, direction, buff=buff, **kwargs)\n\n    def coordinate_label(\n        self,\n        integer_labels: bool = True,\n        n_dim: int = 2,\n        color: ParsableManimColor | None = None,\n        **kwargs: Any,\n    ) -> Matrix:\n        \"\"\"Creates a label based on the coordinates of the vector.\n\n        Parameters\n        ----------\n        integer_labels\n            Whether or not to round the coordinates to integers.\n        n_dim\n            The number of dimensions of the vector.\n        color\n            Sets the color of label, optional.\n        kwargs\n            Additional arguments to be passed to :class:`~.Matrix`.\n\n        Returns\n        -------\n        :class:`~.Matrix`\n            The label.\n\n        Examples\n        --------\n        .. manim:: VectorCoordinateLabel\n            :save_last_frame:\n\n            class VectorCoordinateLabel(Scene):\n                def construct(self):\n                    plane = NumberPlane()\n\n                    vec_1 = Vector([1, 2])\n                    vec_2 = Vector([-3, -2])\n                    label_1 = vec_1.coordinate_label()\n                    label_2 = vec_2.coordinate_label(color=YELLOW)\n\n                    self.add(plane, vec_1, vec_2, label_1, label_2)\n        \"\"\"\n        # avoiding circular imports\n        from ..matrix import Matrix\n\n        vect = np.array(self.get_end())\n        if integer_labels:\n            vect = np.round(vect).astype(int)\n        vect = vect[:n_dim]\n        vect = vect.reshape((n_dim, 1))\n        label = Matrix(vect, **kwargs)\n        label.scale(LARGE_BUFF - 0.2)\n\n        shift_dir = np.array(self.get_end())\n        if shift_dir[0] >= 0:  # Pointing right\n            shift_dir -= label.get_left() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER * LEFT\n        else:  # Pointing left\n            shift_dir -= label.get_right() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER * RIGHT\n        label.shift(shift_dir)\n        if color is not None:\n            label.set_color(color)\n        return label\n\n\nclass DoubleArrow(Arrow):\n    \"\"\"An arrow with tips on both ends.\n\n    Parameters\n    ----------\n    args\n        Arguments to be passed to :class:`Arrow`\n    kwargs\n        Additional arguments to be passed to :class:`Arrow`\n\n\n    .. seealso::\n        :class:`.~ArrowTip`\n        :class:`.~CurvedDoubleArrow`\n\n    Examples\n    --------\n    .. manim:: DoubleArrowExample\n        :save_last_frame:\n\n        from manim.mobject.geometry.tips import ArrowCircleFilledTip\n        class DoubleArrowExample(Scene):\n            def construct(self):\n                circle = Circle(radius=2.0)\n                d_arrow = DoubleArrow(start=circle.get_left(), end=circle.get_right())\n                d_arrow_2 = DoubleArrow(tip_shape_end=ArrowCircleFilledTip, tip_shape_start=ArrowCircleFilledTip)\n                group = Group(Group(circle, d_arrow), d_arrow_2).arrange(UP, buff=1)\n                self.add(group)\n\n\n    .. manim:: DoubleArrowExample2\n        :save_last_frame:\n\n        class DoubleArrowExample2(Scene):\n            def construct(self):\n                box = Square()\n                p1 = box.get_left()\n                p2 = box.get_right()\n                d1 = DoubleArrow(p1, p2, buff=0)\n                d2 = DoubleArrow(p1, p2, buff=0, tip_length=0.2, color=YELLOW)\n                d3 = DoubleArrow(p1, p2, buff=0, tip_length=0.4, color=BLUE)\n                Group(d1, d2, d3).arrange(DOWN)\n                self.add(box, d1, d2, d3)\n    \"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        if \"tip_shape_end\" in kwargs:\n            kwargs[\"tip_shape\"] = kwargs.pop(\"tip_shape_end\")\n        tip_shape_start = kwargs.pop(\"tip_shape_start\", ArrowTriangleFilledTip)\n        super().__init__(*args, **kwargs)\n        self.add_tip(at_start=True, tip_shape=tip_shape_start)\n\n\nclass Angle(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A circular arc or elbow-type mobject representing an angle of two lines.\n\n    Parameters\n    ----------\n    line1 :\n        The first line.\n    line2 :\n        The second line.\n    radius :\n        The radius of the :class:`Arc`.\n    quadrant\n        A sequence of two :class:`int` numbers determining which of the 4 quadrants should be used.\n        The first value indicates whether to anchor the arc on the first line closer to the end point (1)\n        or start point (-1), and the second value functions similarly for the\n        end (1) or start (-1) of the second line.\n        Possibilities: (1,1), (-1,1), (1,-1), (-1,-1).\n    other_angle :\n        Toggles between the two possible angles defined by two points and an arc center. If set to\n        False (default), the arc will always go counterclockwise from the point on line1 until\n        the point on line2 is reached. If set to True, the angle will go clockwise from line1 to line2.\n    dot\n        Allows for a :class:`Dot` in the arc. Mainly used as an convention to indicate a right angle.\n        The dot can be customized in the next three parameters.\n    dot_radius\n        The radius of the :class:`Dot`. If not specified otherwise, this radius will be 1/10 of the arc radius.\n    dot_distance\n        Relative distance from the center to the arc: 0 puts the dot in the center and 1 on the arc itself.\n    dot_color\n        The color of the :class:`Dot`.\n    elbow\n        Produces an elbow-type mobject indicating a right angle, see :class:`RightAngle` for more information\n        and a shorthand.\n    **kwargs\n        Further keyword arguments that are passed to the constructor of :class:`Arc` or :class:`Elbow`.\n\n    Examples\n    --------\n    The first example shows some right angles with a dot in the middle while the second example shows\n    all 8 possible angles defined by two lines.\n\n    .. manim:: RightArcAngleExample\n        :save_last_frame:\n\n        class RightArcAngleExample(Scene):\n            def construct(self):\n                line1 = Line( LEFT, RIGHT )\n                line2 = Line( DOWN, UP )\n                rightarcangles = [\n                    Angle(line1, line2, dot=True),\n                    Angle(line1, line2, radius=0.4, quadrant=(1,-1), dot=True, other_angle=True),\n                    Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8, dot=True, dot_color=YELLOW, dot_radius=0.04, other_angle=True),\n                    Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED, dot=True, dot_color=GREEN, dot_radius=0.08),\n                ]\n                plots = VGroup()\n                for angle in rightarcangles:\n                    plot=VGroup(line1.copy(),line2.copy(), angle)\n                    plots.add(plot)\n                plots.arrange(buff=1.5)\n                self.add(plots)\n\n    .. manim:: AngleExample\n        :save_last_frame:\n\n        class AngleExample(Scene):\n            def construct(self):\n                line1 = Line( LEFT + (1/3) * UP, RIGHT + (1/3) * DOWN )\n                line2 = Line( DOWN + (1/3) * RIGHT, UP + (1/3) * LEFT )\n                angles = [\n                    Angle(line1, line2),\n                    Angle(line1, line2, radius=0.4, quadrant=(1,-1), other_angle=True),\n                    Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8, other_angle=True),\n                    Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED),\n                    Angle(line1, line2, other_angle=True),\n                    Angle(line1, line2, radius=0.4, quadrant=(1,-1)),\n                    Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8),\n                    Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED, other_angle=True),\n                ]\n                plots = VGroup()\n                for angle in angles:\n                    plot=VGroup(line1.copy(),line2.copy(), angle)\n                    plots.add(VGroup(plot,SurroundingRectangle(plot, buff=0.3)))\n                plots.arrange_in_grid(rows=2,buff=1)\n                self.add(plots)\n\n    .. manim:: FilledAngle\n        :save_last_frame:\n\n        class FilledAngle(Scene):\n            def construct(self):\n                l1 = Line(ORIGIN, 2 * UP + RIGHT).set_color(GREEN)\n                l2 = (\n                    Line(ORIGIN, 2 * UP + RIGHT)\n                    .set_color(GREEN)\n                    .rotate(-20 * DEGREES, about_point=ORIGIN)\n                )\n                norm = l1.get_length()\n                a1 = Angle(l1, l2, other_angle=True, radius=norm - 0.5).set_color(GREEN)\n                a2 = Angle(l1, l2, other_angle=True, radius=norm).set_color(GREEN)\n                q1 = a1.points #  save all coordinates of points of angle a1\n                q2 = a2.reverse_direction().points  #  save all coordinates of points of angle a1 (in reversed direction)\n                pnts = np.concatenate([q1, q2, q1[0].reshape(1, 3)])  # adds points and ensures that path starts and ends at same point\n                mfill = VMobject().set_color(ORANGE)\n                mfill.set_points_as_corners(pnts).set_fill(GREEN, opacity=1)\n                self.add(l1, l2)\n                self.add(mfill)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        line1: Line,\n        line2: Line,\n        radius: float | None = None,\n        quadrant: AngleQuadrant = (1, 1),\n        other_angle: bool = False,\n        dot: bool = False,\n        dot_radius: float | None = None,\n        dot_distance: float = 0.55,\n        dot_color: ParsableManimColor = WHITE,\n        elbow: bool = False,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(**kwargs)\n        self.lines = (line1, line2)\n        self.quadrant = quadrant\n        self.dot_distance = dot_distance\n        self.elbow = elbow\n        inter = line_intersection(\n            [line1.get_start(), line1.get_end()],\n            [line2.get_start(), line2.get_end()],\n        )\n\n        if radius is None:\n            if quadrant[0] == 1:\n                dist_1 = np.linalg.norm(line1.get_end() - inter)\n            else:\n                dist_1 = np.linalg.norm(line1.get_start() - inter)\n            if quadrant[1] == 1:\n                dist_2 = np.linalg.norm(line2.get_end() - inter)\n            else:\n                dist_2 = np.linalg.norm(line2.get_start() - inter)\n            if np.minimum(dist_1, dist_2) < 0.6:\n                radius = (2 / 3) * np.minimum(dist_1, dist_2)\n            else:\n                radius = 0.4\n        else:\n            self.radius = radius\n\n        anchor_angle_1 = inter + quadrant[0] * radius * line1.get_unit_vector()\n        anchor_angle_2 = inter + quadrant[1] * radius * line2.get_unit_vector()\n\n        if elbow:\n            anchor_middle = (\n                inter\n                + quadrant[0] * radius * line1.get_unit_vector()\n                + quadrant[1] * radius * line2.get_unit_vector()\n            )\n            angle_mobject: VMobject = Elbow(**kwargs)\n            angle_mobject.set_points_as_corners(\n                np.array([anchor_angle_1, anchor_middle, anchor_angle_2]),\n            )\n        else:\n            angle_1 = angle_of_vector(anchor_angle_1 - inter)\n            angle_2 = angle_of_vector(anchor_angle_2 - inter)\n\n            if not other_angle:\n                start_angle = angle_1\n                if angle_2 > angle_1:\n                    angle_fin = angle_2 - angle_1\n                else:\n                    angle_fin = 2 * np.pi - (angle_1 - angle_2)\n            else:\n                start_angle = angle_1\n                if angle_2 < angle_1:\n                    angle_fin = -angle_1 + angle_2\n                else:\n                    angle_fin = -2 * np.pi + (angle_2 - angle_1)\n\n            self.angle_value = angle_fin\n\n            angle_mobject = Arc(\n                radius=radius,\n                angle=self.angle_value,\n                start_angle=start_angle,\n                arc_center=inter,\n                **kwargs,\n            )\n\n            if dot:\n                if dot_radius is None:\n                    dot_radius = radius / 10\n                else:\n                    self.dot_radius = dot_radius\n                right_dot = Dot(ORIGIN, radius=dot_radius, color=dot_color)\n                dot_anchor = (\n                    inter\n                    + (angle_mobject.get_center() - inter)\n                    / np.linalg.norm(angle_mobject.get_center() - inter)\n                    * radius\n                    * dot_distance\n                )\n                right_dot.move_to(dot_anchor)\n                self.add(right_dot)\n\n        self.set_points(angle_mobject.points)\n\n    def get_lines(self) -> VGroup:\n        \"\"\"Get the lines forming an angle of the :class:`Angle` class.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            A :class:`~.VGroup` containing the lines that form the angle of the :class:`Angle` class.\n\n        Examples\n        --------\n        ::\n\n            >>> line_1, line_2 = Line(ORIGIN, RIGHT), Line(ORIGIN, UR)\n            >>> angle = Angle(line_1, line_2)\n            >>> angle.get_lines()\n            VGroup(Line, Line)\n        \"\"\"\n        return VGroup(*self.lines)\n\n    def get_value(self, degrees: bool = False) -> float:\n        r\"\"\"Get the value of an angle of the :class:`Angle` class.\n\n        Parameters\n        ----------\n        degrees\n            A boolean to decide the unit (deg/rad) in which the value of the angle is returned.\n\n        Returns\n        -------\n        :class:`float`\n            The value in degrees/radians of an angle of the :class:`Angle` class.\n\n        Examples\n        --------\n\n        .. manim:: GetValueExample\n            :save_last_frame:\n\n            class GetValueExample(Scene):\n                def construct(self):\n                    line1 = Line(LEFT+(1/3)*UP, RIGHT+(1/3)*DOWN)\n                    line2 = Line(DOWN+(1/3)*RIGHT, UP+(1/3)*LEFT)\n\n                    angle = Angle(line1, line2, radius=0.4)\n\n                    value = DecimalNumber(angle.get_value(degrees=True), unit=r\"^{\\circ}\")\n                    value.next_to(angle, UR)\n\n                    self.add(line1, line2, angle, value)\n        \"\"\"\n        return self.angle_value / DEGREES if degrees else self.angle_value\n\n    @staticmethod\n    def from_three_points(\n        A: Point3DLike, B: Point3DLike, C: Point3DLike, **kwargs: Any\n    ) -> Angle:\n        r\"\"\"The angle between the lines AB and BC.\n\n        This constructs the angle :math:`\\\\angle ABC`.\n\n        Parameters\n        ----------\n        A\n            The endpoint of the first angle leg\n        B\n            The vertex of the angle\n        C\n            The endpoint of the second angle leg\n\n        **kwargs\n            Further keyword arguments are passed to :class:`.Angle`\n\n        Returns\n        -------\n        The Angle calculated from the three points\n\n                    Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8),\n                    Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED, other_angle=True),\n\n        Examples\n        --------\n        .. manim:: AngleFromThreePointsExample\n            :save_last_frame:\n\n            class AngleFromThreePointsExample(Scene):\n                def construct(self):\n                    sample_angle = Angle.from_three_points(UP, ORIGIN, LEFT)\n                    red_angle = Angle.from_three_points(LEFT + UP, ORIGIN, RIGHT, radius=.8, quadrant=(-1,-1), color=RED, stroke_width=8, other_angle=True)\n                    self.add(red_angle, sample_angle)\n        \"\"\"\n        return Angle(Line(B, A), Line(B, C), **kwargs)\n\n\nclass RightAngle(Angle):\n    \"\"\"An elbow-type mobject representing a right angle between two lines.\n\n    Parameters\n    ----------\n    line1\n        The first line.\n    line2\n        The second line.\n    length\n        The length of the arms.\n    **kwargs\n        Further keyword arguments that are passed to the constructor of :class:`Angle`.\n\n    Examples\n    --------\n    .. manim:: RightAngleExample\n        :save_last_frame:\n\n        class RightAngleExample(Scene):\n            def construct(self):\n                line1 = Line( LEFT, RIGHT )\n                line2 = Line( DOWN, UP )\n                rightangles = [\n                    RightAngle(line1, line2),\n                    RightAngle(line1, line2, length=0.4, quadrant=(1,-1)),\n                    RightAngle(line1, line2, length=0.5, quadrant=(-1,1), stroke_width=8),\n                    RightAngle(line1, line2, length=0.7, quadrant=(-1,-1), color=RED),\n                ]\n                plots = VGroup()\n                for rightangle in rightangles:\n                    plot=VGroup(line1.copy(),line2.copy(), rightangle)\n                    plots.add(plot)\n                plots.arrange(buff=1.5)\n                self.add(plots)\n    \"\"\"\n\n    def __init__(\n        self,\n        line1: Line,\n        line2: Line,\n        length: float | None = None,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(line1, line2, radius=length, elbow=True, **kwargs)\n"
  },
  {
    "path": "manim/mobject/geometry/polygram.py",
    "content": "r\"\"\"Mobjects that are simple geometric shapes.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"Polygram\",\n    \"Polygon\",\n    \"RegularPolygram\",\n    \"RegularPolygon\",\n    \"Star\",\n    \"Triangle\",\n    \"Rectangle\",\n    \"Square\",\n    \"RoundedRectangle\",\n    \"Cutout\",\n    \"ConvexHull\",\n]\n\n\nfrom math import ceil\nfrom typing import TYPE_CHECKING, Any, Literal\n\nimport numpy as np\n\nfrom manim.constants import *\nfrom manim.mobject.geometry.arc import ArcBetweenPoints\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.types.vectorized_mobject import VGroup, VMobject\nfrom manim.utils.color import BLUE, WHITE, ParsableManimColor\nfrom manim.utils.iterables import adjacent_n_tuples, adjacent_pairs\nfrom manim.utils.qhull import QuickHull\nfrom manim.utils.space_ops import angle_between_vectors, normalize, regular_vertices\n\nif TYPE_CHECKING:\n    from typing import Self\n\n    import numpy.typing as npt\n\n    from manim.typing import (\n        Point3D,\n        Point3D_Array,\n        Point3DLike,\n        Point3DLike_Array,\n    )\n    from manim.utils.color import ParsableManimColor\n\n\nclass Polygram(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A generalized :class:`Polygon`, allowing for disconnected sets of edges.\n\n    Parameters\n    ----------\n    vertex_groups\n        The groups of vertices making up the :class:`Polygram`.\n\n        The first vertex in each group is repeated to close the shape.\n        Each point must be 3-dimensional: ``[x,y,z]``\n    color\n        The color of the :class:`Polygram`.\n    kwargs\n        Forwarded to the parent constructor.\n\n    Examples\n    --------\n    .. manim:: PolygramExample\n\n        import numpy as np\n\n        class PolygramExample(Scene):\n            def construct(self):\n                hexagram = Polygram(\n                    [[0, 2, 0], [-np.sqrt(3), -1, 0], [np.sqrt(3), -1, 0]],\n                    [[-np.sqrt(3), 1, 0], [0, -2, 0], [np.sqrt(3), 1, 0]],\n                )\n                self.add(hexagram)\n\n                dot = Dot()\n                self.play(MoveAlongPath(dot, hexagram), run_time=5, rate_func=linear)\n                self.remove(dot)\n                self.wait()\n    \"\"\"\n\n    def __init__(\n        self,\n        *vertex_groups: Point3DLike_Array,\n        color: ParsableManimColor = BLUE,\n        **kwargs: Any,\n    ):\n        super().__init__(color=color, **kwargs)\n\n        for vertices in vertex_groups:\n            # The inferred type for *vertices is Any, but it should be\n            # Point3D_Array\n            first_vertex, *vertices = vertices\n            first_vertex = np.array(first_vertex)\n\n            self.start_new_path(first_vertex)\n            self.add_points_as_corners(\n                [*(np.array(vertex) for vertex in vertices), first_vertex],\n            )\n\n    def get_vertices(self) -> Point3D_Array:\n        \"\"\"Gets the vertices of the :class:`Polygram`.\n\n        Returns\n        -------\n        :class:`numpy.ndarray`\n            The vertices of the :class:`Polygram`.\n\n        Examples\n        --------\n        ::\n\n            >>> sq = Square()\n            >>> sq.get_vertices()\n            array([[ 1.,  1.,  0.],\n                   [-1.,  1.,  0.],\n                   [-1., -1.,  0.],\n                   [ 1., -1.,  0.]])\n        \"\"\"\n        return self.get_start_anchors()\n\n    def get_vertex_groups(self) -> list[Point3D_Array]:\n        \"\"\"Gets the vertex groups of the :class:`Polygram`.\n\n        Returns\n        -------\n        list[Point3D_Array]\n            The list of vertex groups of the :class:`Polygram`.\n\n        Examples\n        --------\n        ::\n\n            >>> poly = Polygram([ORIGIN, RIGHT, UP, LEFT + UP], [LEFT, LEFT + UP, 2 * LEFT])\n            >>> groups = poly.get_vertex_groups()\n            >>> len(groups)\n            2\n            >>> groups[0]\n            array([[ 0.,  0.,  0.],\n                   [ 1.,  0.,  0.],\n                   [ 0.,  1.,  0.],\n                   [-1.,  1.,  0.]])\n            >>> groups[1]\n            array([[-1.,  0.,  0.],\n                   [-1.,  1.,  0.],\n                   [-2.,  0.,  0.]])\n        \"\"\"\n        vertex_groups = []\n\n        # TODO: If any of the original vertex groups contained the starting vertex N\n        # times, then .get_vertex_groups() splits it into N vertex groups.\n        group = []\n        for start, end in zip(\n            self.get_start_anchors(), self.get_end_anchors(), strict=True\n        ):\n            group.append(start)\n\n            if self.consider_points_equals(end, group[0]):\n                vertex_groups.append(np.array(group))\n                group = []\n\n        return vertex_groups\n\n    def round_corners(\n        self,\n        radius: float | list[float] = 0.5,\n        evenly_distribute_anchors: bool = False,\n        components_per_rounded_corner: int = 2,\n    ) -> Self:\n        \"\"\"Rounds off the corners of the :class:`Polygram`.\n\n        Parameters\n        ----------\n        radius\n            The curvature of the corners of the :class:`Polygram`.\n        evenly_distribute_anchors\n            Break long line segments into proportionally-sized segments.\n        components_per_rounded_corner\n            The number of points used to represent the rounded corner curve.\n\n\n        .. seealso::\n            :class:`.~RoundedRectangle`\n\n        .. note::\n            If `radius` is supplied as a single value, then the same radius\n            will be applied to all corners.  If `radius` is a list, then the\n            individual values will be applied sequentially, with the first\n            corner receiving `radius[0]`, the second corner receiving\n            `radius[1]`, etc.  The radius list will be repeated as necessary.\n\n            The `components_per_rounded_corner` value is provided so that the\n            fidelity of the rounded corner may be fine-tuned as needed.  2 is\n            an appropriate value for most shapes, however a larger value may be\n            need if the rounded corner is particularly large.  2 is the minimum\n            number allowed, representing the start and end of the curve.  3 will\n            result in a start, middle, and end point, meaning 2 curves will be\n            generated.\n\n            The option to `evenly_distribute_anchors` is provided so that the\n            line segments (the part part of each line remaining after rounding\n            off the corners) can be subdivided to a density similar to that of\n            the average density of the rounded corners.  This may be desirable\n            in situations in which an even distribution of curves is desired\n            for use in later transformation animations.  Be aware, though, that\n            enabling this option can result in an an object containing\n            significantly more points than the original, especially when the\n            rounded corner curves are small.\n\n        Examples\n        --------\n        .. manim:: PolygramRoundCorners\n            :save_last_frame:\n\n            class PolygramRoundCorners(Scene):\n                def construct(self):\n                    star = Star(outer_radius=2)\n\n                    shapes = VGroup(star)\n                    shapes.add(star.copy().round_corners(radius=0.1))\n                    shapes.add(star.copy().round_corners(radius=0.25))\n\n                    shapes.arrange(RIGHT)\n                    self.add(shapes)\n        \"\"\"\n        if radius == 0:\n            return self\n\n        new_points: list[Point3D] = []\n\n        for vertex_group in self.get_vertex_groups():\n            arcs = []\n\n            # Repeat the radius list as necessary in order to provide a radius\n            # for each vertex.\n            if isinstance(radius, (int, float)):\n                radius_list = [radius] * len(vertex_group)\n            else:\n                radius_list = radius * ceil(len(vertex_group) / len(radius))\n\n            for current_radius, (v1, v2, v3) in zip(\n                radius_list, adjacent_n_tuples(vertex_group, 3), strict=True\n            ):\n                vect1 = v2 - v1\n                vect2 = v3 - v2\n                unit_vect1 = normalize(vect1)\n                unit_vect2 = normalize(vect2)\n\n                angle = angle_between_vectors(vect1, vect2)\n                # Negative radius gives concave curves\n                angle *= np.sign(current_radius)\n\n                # Distance between vertex and start of the arc\n                cut_off_length = current_radius * np.tan(angle / 2)\n\n                # Determines counterclockwise vs. clockwise\n                sign = np.sign(np.cross(vect1, vect2)[2])\n\n                arc = ArcBetweenPoints(\n                    v2 - unit_vect1 * cut_off_length,\n                    v2 + unit_vect2 * cut_off_length,\n                    angle=sign * angle,\n                    num_components=components_per_rounded_corner,\n                )\n                arcs.append(arc)\n\n            if evenly_distribute_anchors:\n                # Determine the average length of each curve\n                nonzero_length_arcs = [arc for arc in arcs if len(arc.points) > 4]\n                if len(nonzero_length_arcs) > 0:\n                    total_arc_length = sum(\n                        [arc.get_arc_length() for arc in nonzero_length_arcs]\n                    )\n                    num_curves = (\n                        sum([len(arc.points) for arc in nonzero_length_arcs]) / 4\n                    )\n                    average_arc_length = total_arc_length / num_curves\n                else:\n                    average_arc_length = 1.0\n\n            # To ensure that we loop through starting with last\n            arcs = [arcs[-1], *arcs[:-1]]\n            from manim.mobject.geometry.line import Line\n\n            for arc1, arc2 in adjacent_pairs(arcs):\n                new_points.extend(arc1.points)\n\n                line = Line(arc1.get_end(), arc2.get_start())\n\n                # Make sure anchors are evenly distributed, if necessary\n                if evenly_distribute_anchors:\n                    line.insert_n_curves(ceil(line.get_length() / average_arc_length))\n\n                new_points.extend(line.points)\n\n        self.set_points(np.array(new_points))\n\n        return self\n\n\nclass Polygon(Polygram):\n    \"\"\"A shape consisting of one closed loop of vertices.\n\n    Parameters\n    ----------\n    vertices\n        The vertices of the :class:`Polygon`.\n    kwargs\n        Forwarded to the parent constructor.\n\n    Examples\n    --------\n    .. manim:: PolygonExample\n        :save_last_frame:\n\n        class PolygonExample(Scene):\n            def construct(self):\n                isosceles = Polygon([-5, 1.5, 0], [-2, 1.5, 0], [-3.5, -2, 0])\n                position_list = [\n                    [4, 1, 0],  # middle right\n                    [4, -2.5, 0],  # bottom right\n                    [0, -2.5, 0],  # bottom left\n                    [0, 3, 0],  # top left\n                    [2, 1, 0],  # middle\n                    [4, 3, 0],  # top right\n                ]\n                square_and_triangles = Polygon(*position_list, color=PURPLE_B)\n                self.add(isosceles, square_and_triangles)\n    \"\"\"\n\n    def __init__(self, *vertices: Point3DLike, **kwargs: Any) -> None:\n        super().__init__(vertices, **kwargs)\n\n\nclass RegularPolygram(Polygram):\n    \"\"\"A :class:`Polygram` with regularly spaced vertices.\n\n    Parameters\n    ----------\n    num_vertices\n        The number of vertices.\n    density\n        The density of the :class:`RegularPolygram`.\n\n        Can be thought of as how many vertices to hop\n        to draw a line between them. Every ``density``-th\n        vertex is connected.\n    radius\n        The radius of the circle that the vertices are placed on.\n    start_angle\n        The angle the vertices start at; the rotation of\n        the :class:`RegularPolygram`.\n    kwargs\n        Forwarded to the parent constructor.\n\n    Examples\n    --------\n    .. manim:: RegularPolygramExample\n        :save_last_frame:\n\n        class RegularPolygramExample(Scene):\n            def construct(self):\n                pentagram = RegularPolygram(5, radius=2)\n                self.add(pentagram)\n    \"\"\"\n\n    def __init__(\n        self,\n        num_vertices: int,\n        *,\n        density: int = 2,\n        radius: float = 1,\n        start_angle: float | None = None,\n        **kwargs: Any,\n    ) -> None:\n        # Regular polygrams can be expressed by the number of their vertices\n        # and their density. This relation can be expressed as its Schläfli\n        # symbol: {num_vertices/density}.\n        #\n        # For instance, a pentagon can be expressed as {5/1} or just {5}.\n        # A pentagram, however, can be expressed as {5/2}.\n        # A hexagram *would* be expressed as {6/2}, except that 6 and 2\n        # are not coprime, and it can be simplified to 2{3}, which corresponds\n        # to the fact that a hexagram is actually made up of 2 triangles.\n        #\n        # See https://en.wikipedia.org/wiki/Polygram_(geometry)#Generalized_regular_polygons\n        # for more information.\n\n        num_gons = np.gcd(num_vertices, density)\n        num_vertices //= num_gons\n        density //= num_gons\n\n        # Utility function for generating the individual\n        # polygon vertices.\n        def gen_polygon_vertices(start_angle: float | None) -> tuple[list[Any], float]:\n            reg_vertices, start_angle = regular_vertices(\n                num_vertices,\n                radius=radius,\n                start_angle=start_angle,\n            )\n\n            vertices = []\n            i = 0\n            while True:\n                vertices.append(reg_vertices[i])\n\n                i += density\n                i %= num_vertices\n                if i == 0:\n                    break\n\n            return vertices, start_angle\n\n        first_group, self.start_angle = gen_polygon_vertices(start_angle)\n        vertex_groups = [first_group]\n\n        for i in range(1, num_gons):\n            start_angle = self.start_angle + (i / num_gons) * TAU / num_vertices\n            group, _ = gen_polygon_vertices(start_angle)\n\n            vertex_groups.append(group)\n\n        super().__init__(*vertex_groups, **kwargs)\n\n\nclass RegularPolygon(RegularPolygram):\n    \"\"\"An n-sided regular :class:`Polygon`.\n\n    Parameters\n    ----------\n    n\n        The number of sides of the :class:`RegularPolygon`.\n    kwargs\n        Forwarded to the parent constructor.\n\n    Examples\n    --------\n    .. manim:: RegularPolygonExample\n        :save_last_frame:\n\n        class RegularPolygonExample(Scene):\n            def construct(self):\n                poly_1 = RegularPolygon(n=6)\n                poly_2 = RegularPolygon(n=6, start_angle=30*DEGREES, color=GREEN)\n                poly_3 = RegularPolygon(n=10, color=RED)\n\n                poly_group = Group(poly_1, poly_2, poly_3).scale(1.5).arrange(buff=1)\n                self.add(poly_group)\n    \"\"\"\n\n    def __init__(self, n: int = 6, **kwargs: Any) -> None:\n        super().__init__(n, density=1, **kwargs)\n\n\nclass Star(Polygon):\n    \"\"\"A regular polygram without the intersecting lines.\n\n    Parameters\n    ----------\n    n\n        How many points on the :class:`Star`.\n    outer_radius\n        The radius of the circle that the outer vertices are placed on.\n    inner_radius\n        The radius of the circle that the inner vertices are placed on.\n\n        If unspecified, the inner radius will be\n        calculated such that the edges of the :class:`Star`\n        perfectly follow the edges of its :class:`RegularPolygram`\n        counterpart.\n    density\n        The density of the :class:`Star`. Only used if\n        ``inner_radius`` is unspecified.\n\n        See :class:`RegularPolygram` for more information.\n    start_angle\n        The angle the vertices start at; the rotation of\n        the :class:`Star`.\n    kwargs\n        Forwardeds to the parent constructor.\n\n    Raises\n    ------\n    :exc:`ValueError`\n        If ``inner_radius`` is unspecified and ``density``\n        is not in the range ``[1, n/2)``.\n\n    Examples\n    --------\n    .. manim:: StarExample\n\n        class StarExample(Scene):\n            def construct(self):\n                pentagram = RegularPolygram(5, radius=2)\n                star = Star(outer_radius=2, color=RED)\n\n                self.add(pentagram)\n                self.play(Create(star), run_time=3)\n                self.play(FadeOut(star), run_time=2)\n\n    .. manim:: DifferentDensitiesExample\n        :save_last_frame:\n\n        class DifferentDensitiesExample(Scene):\n            def construct(self):\n                density_2 = Star(7, outer_radius=2, density=2, color=RED)\n                density_3 = Star(7, outer_radius=2, density=3, color=PURPLE)\n\n                self.add(VGroup(density_2, density_3).arrange(RIGHT))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        n: int = 5,\n        *,\n        outer_radius: float = 1,\n        inner_radius: float | None = None,\n        density: int = 2,\n        start_angle: float | None = TAU / 4,\n        **kwargs: Any,\n    ) -> None:\n        inner_angle = TAU / (2 * n)\n\n        if inner_radius is None:\n            # See https://math.stackexchange.com/a/2136292 for an\n            # overview of how to calculate the inner radius of a\n            # perfect star.\n\n            if density <= 0 or density >= n / 2:\n                raise ValueError(\n                    f\"Incompatible density {density} for number of points {n}\",\n                )\n\n            outer_angle = TAU * density / n\n            inverse_x = 1 - np.tan(inner_angle) * (\n                (np.cos(outer_angle) - 1) / np.sin(outer_angle)\n            )\n\n            inner_radius = outer_radius / (np.cos(inner_angle) * inverse_x)\n\n        outer_vertices, self.start_angle = regular_vertices(\n            n,\n            radius=outer_radius,\n            start_angle=start_angle,\n        )\n        inner_vertices, _ = regular_vertices(\n            n,\n            radius=inner_radius,\n            start_angle=self.start_angle + inner_angle,\n        )\n\n        vertices: list[npt.NDArray] = []\n        for pair in zip(outer_vertices, inner_vertices, strict=True):\n            vertices.extend(pair)\n\n        super().__init__(*vertices, **kwargs)\n\n\nclass Triangle(RegularPolygon):\n    \"\"\"An equilateral triangle.\n\n    Parameters\n    ----------\n    kwargs\n        Additional arguments to be passed to :class:`RegularPolygon`\n\n    Examples\n    --------\n    .. manim:: TriangleExample\n        :save_last_frame:\n\n        class TriangleExample(Scene):\n            def construct(self):\n                triangle_1 = Triangle()\n                triangle_2 = Triangle().scale(2).rotate(60*DEGREES)\n                tri_group = Group(triangle_1, triangle_2).arrange(buff=1)\n                self.add(tri_group)\n    \"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        super().__init__(n=3, **kwargs)\n\n\nclass Rectangle(Polygon):\n    \"\"\"A quadrilateral with two sets of parallel sides.\n\n    Parameters\n    ----------\n    color\n        The color of the rectangle.\n    height\n        The vertical height of the rectangle.\n    width\n        The horizontal width of the rectangle.\n    grid_xstep\n        Space between vertical grid lines.\n    grid_ystep\n        Space between horizontal grid lines.\n    mark_paths_closed\n        No purpose.\n    close_new_points\n        No purpose.\n    kwargs\n        Additional arguments to be passed to :class:`Polygon`\n\n    Examples\n    ----------\n    .. manim:: RectangleExample\n        :save_last_frame:\n\n        class RectangleExample(Scene):\n            def construct(self):\n                rect1 = Rectangle(width=4.0, height=2.0, grid_xstep=1.0, grid_ystep=0.5)\n                rect2 = Rectangle(width=1.0, height=4.0)\n                rect3 = Rectangle(width=2.0, height=2.0, grid_xstep=1.0, grid_ystep=1.0)\n                rect3.grid_lines.set_stroke(width=1)\n\n                rects = Group(rect1, rect2, rect3).arrange(buff=1)\n                self.add(rects)\n    \"\"\"\n\n    def __init__(\n        self,\n        color: ParsableManimColor = WHITE,\n        height: float = 2.0,\n        width: float = 4.0,\n        grid_xstep: float | None = None,\n        grid_ystep: float | None = None,\n        mark_paths_closed: bool = True,\n        close_new_points: bool = True,\n        **kwargs: Any,\n    ):\n        super().__init__(UR, UL, DL, DR, color=color, **kwargs)\n        self.stretch_to_fit_width(width)\n        self.stretch_to_fit_height(height)\n\n        v = self.get_vertices()\n        self.grid_lines = VGroup()\n\n        if grid_xstep or grid_ystep:\n            from manim.mobject.geometry.line import Line\n\n            v = self.get_vertices()\n\n        if grid_xstep:\n            grid_xstep = abs(grid_xstep)\n            count = int(width / grid_xstep)\n            grid = VGroup(\n                *(\n                    Line(\n                        v[1] + i * grid_xstep * RIGHT,\n                        v[1] + i * grid_xstep * RIGHT + height * DOWN,\n                        color=color,\n                    )\n                    for i in range(1, count)\n                )\n            )\n            self.grid_lines.add(grid)\n\n        if grid_ystep:\n            grid_ystep = abs(grid_ystep)\n            count = int(height / grid_ystep)\n            grid = VGroup(\n                *(\n                    Line(\n                        v[1] + i * grid_ystep * DOWN,\n                        v[1] + i * grid_ystep * DOWN + width * RIGHT,\n                        color=color,\n                    )\n                    for i in range(1, count)\n                )\n            )\n            self.grid_lines.add(grid)\n\n        if self.grid_lines:\n            self.add(self.grid_lines)\n\n\nclass Square(Rectangle):\n    \"\"\"A rectangle with equal side lengths.\n\n    Parameters\n    ----------\n    side_length\n        The length of the sides of the square.\n    kwargs\n        Additional arguments to be passed to :class:`Rectangle`.\n\n    Examples\n    --------\n    .. manim:: SquareExample\n        :save_last_frame:\n\n        class SquareExample(Scene):\n            def construct(self):\n                square_1 = Square(side_length=2.0).shift(DOWN)\n                square_2 = Square(side_length=1.0).next_to(square_1, direction=UP)\n                square_3 = Square(side_length=0.5).next_to(square_2, direction=UP)\n                self.add(square_1, square_2, square_3)\n    \"\"\"\n\n    def __init__(self, side_length: float = 2.0, **kwargs: Any) -> None:\n        super().__init__(height=side_length, width=side_length, **kwargs)\n\n    @property\n    def side_length(self) -> float:\n        return float(np.linalg.norm(self.get_vertices()[0] - self.get_vertices()[1]))\n\n    @side_length.setter\n    def side_length(self, value: float) -> None:\n        self.scale(value / self.side_length)\n\n\nclass RoundedRectangle(Rectangle):\n    \"\"\"A rectangle with rounded corners.\n\n    Parameters\n    ----------\n    corner_radius\n        The curvature of the corners of the rectangle.\n    kwargs\n        Additional arguments to be passed to :class:`Rectangle`\n\n    Examples\n    --------\n    .. manim:: RoundedRectangleExample\n        :save_last_frame:\n\n        class RoundedRectangleExample(Scene):\n            def construct(self):\n                rect_1 = RoundedRectangle(corner_radius=0.5)\n                rect_2 = RoundedRectangle(corner_radius=1.5, height=4.0, width=4.0)\n\n                rect_group = Group(rect_1, rect_2).arrange(buff=1)\n                self.add(rect_group)\n    \"\"\"\n\n    def __init__(self, corner_radius: float | list[float] = 0.5, **kwargs: Any):\n        super().__init__(**kwargs)\n        self.corner_radius = corner_radius\n        self.round_corners(self.corner_radius)\n\n\nclass Cutout(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A shape with smaller cutouts.\n\n    Parameters\n    ----------\n    main_shape\n        The primary shape from which cutouts are made.\n    mobjects\n        The smaller shapes which are to be cut out of the ``main_shape``.\n    kwargs\n        Further keyword arguments that are passed to the constructor of\n        :class:`~.VMobject`.\n\n\n    .. warning::\n        Technically, this class behaves similar to a symmetric difference: if\n        parts of the ``mobjects`` are not located within the ``main_shape``,\n        these parts will be added to the resulting :class:`~.VMobject`.\n\n    Examples\n    --------\n    .. manim:: CutoutExample\n\n        class CutoutExample(Scene):\n            def construct(self):\n                s1 = Square().scale(2.5)\n                s2 = Triangle().shift(DOWN + RIGHT).scale(0.5)\n                s3 = Square().shift(UP + RIGHT).scale(0.5)\n                s4 = RegularPolygon(5).shift(DOWN + LEFT).scale(0.5)\n                s5 = RegularPolygon(6).shift(UP + LEFT).scale(0.5)\n                c = Cutout(s1, s2, s3, s4, s5, fill_opacity=1, color=BLUE, stroke_color=RED)\n                self.play(Write(c), run_time=4)\n                self.wait()\n    \"\"\"\n\n    def __init__(\n        self, main_shape: VMobject, *mobjects: VMobject, **kwargs: Any\n    ) -> None:\n        super().__init__(**kwargs)\n        self.append_points(main_shape.points)\n        sub_direction: Literal[\"CCW\", \"CW\"] = (\n            \"CCW\" if main_shape.get_direction() == \"CW\" else \"CW\"\n        )\n        for mobject in mobjects:\n            self.append_points(mobject.force_direction(sub_direction).points)\n\n\nclass ConvexHull(Polygram):\n    \"\"\"Constructs a convex hull for a set of points in no particular order.\n\n    Parameters\n    ----------\n    points\n        The points to consider.\n    tolerance\n        The tolerance used by quickhull.\n    kwargs\n        Forwarded to the parent constructor.\n\n    Examples\n    --------\n    .. manim:: ConvexHullExample\n        :save_last_frame:\n        :quality: high\n\n        class ConvexHullExample(Scene):\n            def construct(self):\n                points = [\n                    [-2.35, -2.25, 0],\n                    [1.65, -2.25, 0],\n                    [2.65, -0.25, 0],\n                    [1.65, 1.75, 0],\n                    [-0.35, 2.75, 0],\n                    [-2.35, 0.75, 0],\n                    [-0.35, -1.25, 0],\n                    [0.65, -0.25, 0],\n                    [-1.35, 0.25, 0],\n                    [0.15, 0.75, 0]\n                ]\n                hull = ConvexHull(*points, color=BLUE)\n                dots = VGroup(*[Dot(point) for point in points])\n                self.add(hull)\n                self.add(dots)\n    \"\"\"\n\n    def __init__(\n        self, *points: Point3DLike, tolerance: float = 1e-5, **kwargs: Any\n    ) -> None:\n        # Build Convex Hull\n        array = np.array(points)[:, :2]\n        hull = QuickHull(tolerance)\n        hull.build(array)\n\n        # Extract Vertices\n        facets = set(hull.facets) - hull.removed\n        facet = facets.pop()\n        subfacets = list(facet.subfacets)\n        while len(subfacets) <= len(facets):\n            sf = subfacets[-1]\n            (facet,) = hull.neighbors[sf] - {facet}\n            (sf,) = facet.subfacets - {sf}\n            subfacets.append(sf)\n\n        # Setup Vertices as Point3D\n        coordinates = np.vstack([sf.coordinates for sf in subfacets])\n        vertices = np.hstack((coordinates, np.zeros((len(coordinates), 1))))\n\n        # Call Polygram\n        super().__init__(vertices, **kwargs)\n"
  },
  {
    "path": "manim/mobject/geometry/shape_matchers.py",
    "content": "\"\"\"Mobjects used to mark and annotate other mobjects.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"SurroundingRectangle\", \"BackgroundRectangle\", \"Cross\", \"Underline\"]\n\nfrom typing import Any, Self\n\nfrom manim import logger\nfrom manim._config import config\nfrom manim.constants import (\n    DOWN,\n    LEFT,\n    RIGHT,\n    SMALL_BUFF,\n    UP,\n)\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.geometry.polygram import RoundedRectangle\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.mobject.types.vectorized_mobject import VGroup\nfrom manim.utils.color import BLACK, PURE_YELLOW, RED, ParsableManimColor\n\n\nclass SurroundingRectangle(RoundedRectangle):\n    r\"\"\"A rectangle surrounding a :class:`~.Mobject`\n\n    Examples\n    --------\n    .. manim:: SurroundingRectExample\n        :save_last_frame:\n\n        class SurroundingRectExample(Scene):\n            def construct(self):\n                title = Title(\"A Quote from Newton\")\n                quote = Text(\n                    \"If I have seen further than others, \\n\"\n                    \"it is by standing upon the shoulders of giants.\",\n                    color=BLUE,\n                ).scale(0.75)\n                box = SurroundingRectangle(quote, color=YELLOW, buff=MED_LARGE_BUFF)\n\n                t2 = Tex(r\"Hello World\").scale(1.5)\n                box2 = SurroundingRectangle(t2, corner_radius=0.2)\n                mobjects = VGroup(VGroup(box, quote), VGroup(t2, box2)).arrange(DOWN)\n                self.add(title, mobjects)\n    \"\"\"\n\n    def __init__(\n        self,\n        *mobjects: Mobject,\n        color: ParsableManimColor = PURE_YELLOW,\n        buff: float | tuple[float, float] = SMALL_BUFF,\n        corner_radius: float = 0.0,\n        **kwargs: Any,\n    ) -> None:\n        from manim.mobject.mobject import Group\n\n        if not all(isinstance(mob, (Mobject, OpenGLMobject)) for mob in mobjects):\n            raise TypeError(\n                \"Expected all inputs for parameter mobjects to be a Mobjects\"\n            )\n\n        if isinstance(buff, tuple):\n            buff_x = buff[0]\n            buff_y = buff[1]\n        else:\n            buff_x = buff_y = buff\n\n        group = Group(*mobjects)\n        super().__init__(\n            color=color,\n            width=group.width + 2 * buff_x,\n            height=group.height + 2 * buff_y,\n            corner_radius=corner_radius,\n            **kwargs,\n        )\n        self.buff = buff\n        self.move_to(group)\n\n\nclass BackgroundRectangle(SurroundingRectangle):\n    \"\"\"A background rectangle. Its default color is the background color\n    of the scene.\n\n    Examples\n    --------\n    .. manim:: ExampleBackgroundRectangle\n        :save_last_frame:\n\n        class ExampleBackgroundRectangle(Scene):\n            def construct(self):\n                circle = Circle().shift(LEFT)\n                circle.set_stroke(color=GREEN, width=20)\n                triangle = Triangle().shift(2 * RIGHT)\n                triangle.set_fill(PINK, opacity=0.5)\n                backgroundRectangle1 = BackgroundRectangle(circle, color=WHITE, fill_opacity=0.15)\n                backgroundRectangle2 = BackgroundRectangle(triangle, color=WHITE, fill_opacity=0.15)\n                self.add(backgroundRectangle1)\n                self.add(backgroundRectangle2)\n                self.add(circle)\n                self.add(triangle)\n                self.play(Rotate(backgroundRectangle1, PI / 4))\n                self.play(Rotate(backgroundRectangle2, PI / 2))\n    \"\"\"\n\n    def __init__(\n        self,\n        *mobjects: Mobject,\n        color: ParsableManimColor | None = None,\n        stroke_width: float = 0,\n        stroke_opacity: float = 0,\n        fill_opacity: float = 0.75,\n        buff: float | tuple[float, float] = 0,\n        **kwargs: Any,\n    ) -> None:\n        if color is None:\n            color = config.background_color\n\n        super().__init__(\n            *mobjects,\n            color=color,\n            stroke_width=stroke_width,\n            stroke_opacity=stroke_opacity,\n            fill_opacity=fill_opacity,\n            buff=buff,\n            **kwargs,\n        )\n        self.original_fill_opacity: float = self.fill_opacity\n\n    def pointwise_become_partial(self, mobject: Mobject, a: Any, b: float) -> Self:\n        self.set_fill(opacity=b * self.original_fill_opacity)\n        return self\n\n    def set_style(self, fill_opacity: float, **kwargs: Any) -> Self:  # type: ignore[override]\n        # Unchangeable style, except for fill_opacity\n        # All other style arguments are ignored\n        super().set_style(\n            stroke_color=BLACK,\n            stroke_width=0,\n            fill_color=BLACK,\n            fill_opacity=fill_opacity,\n        )\n        if len(kwargs) > 0:\n            logger.info(\n                \"Argument %s is ignored in BackgroundRectangle.set_style.\",\n                kwargs,\n            )\n        return self\n\n\nclass Cross(VGroup):\n    \"\"\"Creates a cross.\n\n    Parameters\n    ----------\n    mobject\n        The mobject linked to this instance. It fits the mobject when specified. Defaults to None.\n    stroke_color\n        Specifies the color of the cross lines. Defaults to RED.\n    stroke_width\n        Specifies the width of the cross lines. Defaults to 6.\n    scale_factor\n        Scales the cross to the provided units. Defaults to 1.\n\n    Examples\n    --------\n    .. manim:: ExampleCross\n        :save_last_frame:\n\n        class ExampleCross(Scene):\n            def construct(self):\n                cross = Cross()\n                self.add(cross)\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject | None = None,\n        stroke_color: ParsableManimColor = RED,\n        stroke_width: float = 6.0,\n        scale_factor: float = 1.0,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(\n            Line(UP + LEFT, DOWN + RIGHT), Line(UP + RIGHT, DOWN + LEFT), **kwargs\n        )\n        if mobject is not None:\n            self.replace(mobject, stretch=True)\n        self.scale(scale_factor)\n        self.set_stroke(color=stroke_color, width=stroke_width)\n\n\nclass Underline(Line):\n    \"\"\"Creates an underline.\n\n    Examples\n    --------\n    .. manim:: UnderLine\n        :save_last_frame:\n\n        class UnderLine(Scene):\n            def construct(self):\n                man = Tex(\"Manim\")  # Full Word\n                ul = Underline(man)  # Underlining the word\n                self.add(man, ul)\n    \"\"\"\n\n    def __init__(\n        self, mobject: Mobject, buff: float = SMALL_BUFF, **kwargs: Any\n    ) -> None:\n        super().__init__(LEFT, RIGHT, buff=buff, **kwargs)\n        self.match_width(mobject)\n        self.next_to(mobject, DOWN, buff=self.buff)\n"
  },
  {
    "path": "manim/mobject/geometry/tips.py",
    "content": "r\"\"\"A collection of tip mobjects for use with :class:`~.TipableVMobject`.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"ArrowTip\",\n    \"ArrowCircleFilledTip\",\n    \"ArrowCircleTip\",\n    \"ArrowSquareTip\",\n    \"ArrowSquareFilledTip\",\n    \"ArrowTriangleTip\",\n    \"ArrowTriangleFilledTip\",\n    \"StealthTip\",\n]\n\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom manim.constants import *\nfrom manim.mobject.geometry.arc import Circle\nfrom manim.mobject.geometry.polygram import Square, Triangle\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.types.vectorized_mobject import VMobject\nfrom manim.utils.space_ops import angle_of_vector\n\nif TYPE_CHECKING:\n    from manim.typing import Point3D, Vector3D\n\n\nclass ArrowTip(VMobject, metaclass=ConvertToOpenGL):\n    r\"\"\"Base class for arrow tips.\n\n    .. seealso::\n        :class:`ArrowTriangleTip`\n        :class:`ArrowTriangleFilledTip`\n        :class:`ArrowCircleTip`\n        :class:`ArrowCircleFilledTip`\n        :class:`ArrowSquareTip`\n        :class:`ArrowSquareFilledTip`\n        :class:`StealthTip`\n\n    Examples\n    --------\n    Cannot be used directly, only intended for inheritance::\n\n        >>> tip = ArrowTip()\n        Traceback (most recent call last):\n        ...\n        NotImplementedError: Has to be implemented in inheriting subclasses.\n\n    Instead, use one of the pre-defined ones, or make\n    a custom one like this:\n\n    .. manim:: CustomTipExample\n\n        >>> from manim import RegularPolygon, Arrow\n        >>> class MyCustomArrowTip(ArrowTip, RegularPolygon):\n        ...     def __init__(self, length=0.35, **kwargs):\n        ...         RegularPolygon.__init__(self, n=5, **kwargs)\n        ...         self.width = length\n        ...         self.stretch_to_fit_height(length)\n        >>> arr = Arrow(\n        ...     np.array([-2, -2, 0]), np.array([2, 2, 0]), tip_shape=MyCustomArrowTip\n        ... )\n        >>> isinstance(arr.tip, RegularPolygon)\n        True\n        >>> from manim import Scene, Create\n        >>> class CustomTipExample(Scene):\n        ...     def construct(self):\n        ...         self.play(Create(arr))\n\n    Using a class inherited from :class:`ArrowTip` to get a non-filled\n    tip is a shorthand to manually specifying the arrow tip style as follows::\n\n        >>> arrow = Arrow(np.array([0, 0, 0]), np.array([1, 1, 0]),\n        ...               tip_style={'fill_opacity': 0, 'stroke_width': 3})\n\n    The following example illustrates the usage of all of the predefined\n    arrow tips.\n\n    .. manim:: ArrowTipsShowcase\n        :save_last_frame:\n\n        class ArrowTipsShowcase(Scene):\n            def construct(self):\n                tip_names = [\n                    'Default (YELLOW)', 'ArrowTriangleTip', 'Default', 'ArrowSquareTip',\n                    'ArrowSquareFilledTip', 'ArrowCircleTip', 'ArrowCircleFilledTip', 'StealthTip'\n                ]\n\n                big_arrows = [\n                    Arrow(start=[-4, 3.5, 0], end=[2, 3.5, 0], color=YELLOW),\n                    Arrow(start=[-4, 2.5, 0], end=[2, 2.5, 0], tip_shape=ArrowTriangleTip),\n                    Arrow(start=[-4, 1.5, 0], end=[2, 1.5, 0]),\n                    Arrow(start=[-4, 0.5, 0], end=[2, 0.5, 0], tip_shape=ArrowSquareTip),\n\n                    Arrow([-4, -0.5, 0], [2, -0.5, 0], tip_shape=ArrowSquareFilledTip),\n                    Arrow([-4, -1.5, 0], [2, -1.5, 0], tip_shape=ArrowCircleTip),\n                    Arrow([-4, -2.5, 0], [2, -2.5, 0], tip_shape=ArrowCircleFilledTip),\n                    Arrow([-4, -3.5, 0], [2, -3.5, 0], tip_shape=StealthTip)\n                ]\n\n                small_arrows = (\n                    arrow.copy().scale(0.5, scale_tips=True).next_to(arrow, RIGHT) for arrow in big_arrows\n                )\n\n                labels = (\n                    Text(tip_names[i], font='monospace', font_size=20, color=BLUE).next_to(big_arrows[i], LEFT) for i in range(len(big_arrows))\n                )\n\n                self.add(*big_arrows, *small_arrows, *labels)\n    \"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        raise NotImplementedError(\"Has to be implemented in inheriting subclasses.\")\n\n    @property\n    def base(self) -> Point3D:\n        r\"\"\"The base point of the arrow tip.\n\n        This is the point connecting to the arrow line.\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import Arrow\n            >>> arrow = Arrow(np.array([0, 0, 0]), np.array([2, 0, 0]), buff=0)\n            >>> arrow.tip.base.round(2) + 0.  # add 0. to avoid negative 0 in output\n            array([1.65, 0.  , 0.  ])\n\n        \"\"\"\n        return self.point_from_proportion(0.5)\n\n    @property\n    def tip_point(self) -> Point3D:\n        r\"\"\"The tip point of the arrow tip.\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import Arrow\n            >>> arrow = Arrow(np.array([0, 0, 0]), np.array([2, 0, 0]), buff=0)\n            >>> arrow.tip.tip_point.round(2) + 0.\n            array([2., 0., 0.])\n\n        \"\"\"\n        # Type inference of extracting an element from a list, is not\n        # supported by numpy, see this numpy issue\n        # https://github.com/numpy/numpy/issues/16544\n        tip_point: Point3D = self.points[0]\n        return tip_point\n\n    @property\n    def vector(self) -> Vector3D:\n        r\"\"\"The vector pointing from the base point to the tip point.\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import Arrow\n            >>> arrow = Arrow(np.array([0, 0, 0]), np.array([2, 2, 0]), buff=0)\n            >>> arrow.tip.vector.round(2) + 0.\n            array([0.25, 0.25, 0.  ])\n\n        \"\"\"\n        return self.tip_point - self.base\n\n    @property\n    def tip_angle(self) -> float:\n        r\"\"\"The angle of the arrow tip.\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import Arrow\n            >>> arrow = Arrow(np.array([0, 0, 0]), np.array([1, 1, 0]), buff=0)\n            >>> bool(round(arrow.tip.tip_angle, 5) == round(PI/4, 5))\n            True\n\n        \"\"\"\n        return angle_of_vector(self.vector)\n\n    @property\n    def length(self) -> float:\n        r\"\"\"The length of the arrow tip.\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import Arrow\n            >>> arrow = Arrow(np.array([0, 0, 0]), np.array([1, 2, 0]))\n            >>> round(arrow.tip.length, 3)\n            0.35\n\n        \"\"\"\n        return float(np.linalg.norm(self.vector))\n\n\nclass StealthTip(ArrowTip):\n    r\"\"\"'Stealth' fighter / kite arrow shape.\n\n    Naming is inspired by the corresponding\n    `TikZ arrow shape <https://tikz.dev/tikz-arrows#sec-16.3>`__.\n    \"\"\"\n\n    def __init__(\n        self,\n        fill_opacity: float = 1,\n        stroke_width: float = 3,\n        length: float = DEFAULT_ARROW_TIP_LENGTH / 2,\n        start_angle: float = PI,\n        **kwargs: Any,\n    ):\n        self.start_angle = start_angle\n        VMobject.__init__(\n            self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs\n        )\n        self.set_points_as_corners(\n            np.array(\n                [\n                    [2, 0, 0],  # tip\n                    [-1.2, 1.6, 0],\n                    [0, 0, 0],  # base\n                    [-1.2, -1.6, 0],\n                    [2, 0, 0],  # close path, back to tip\n                ]\n            )\n        )\n        self.scale(length / self.length)\n\n    @property\n    def length(self) -> float:\n        \"\"\"The length of the arrow tip.\n\n        In this case, the length is computed as the height of\n        the triangle encompassing the stealth tip (otherwise,\n        the tip is scaled too large).\n        \"\"\"\n        return float(np.linalg.norm(self.vector) * 1.6)\n\n\nclass ArrowTriangleTip(ArrowTip, Triangle):\n    r\"\"\"Triangular arrow tip.\"\"\"\n\n    def __init__(\n        self,\n        fill_opacity: float = 0,\n        stroke_width: float = 3,\n        length: float = DEFAULT_ARROW_TIP_LENGTH,\n        width: float = DEFAULT_ARROW_TIP_LENGTH,\n        start_angle: float = PI,\n        **kwargs: Any,\n    ) -> None:\n        Triangle.__init__(\n            self,\n            fill_opacity=fill_opacity,\n            stroke_width=stroke_width,\n            start_angle=start_angle,\n            **kwargs,\n        )\n        self.width = width\n\n        self.stretch_to_fit_width(length)\n        self.stretch_to_fit_height(width)\n\n\nclass ArrowTriangleFilledTip(ArrowTriangleTip):\n    r\"\"\"Triangular arrow tip with filled tip.\n\n    This is the default arrow tip shape.\n    \"\"\"\n\n    def __init__(\n        self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs: Any\n    ) -> None:\n        super().__init__(fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs)\n\n\nclass ArrowCircleTip(ArrowTip, Circle):\n    r\"\"\"Circular arrow tip.\"\"\"\n\n    def __init__(\n        self,\n        fill_opacity: float = 0,\n        stroke_width: float = 3,\n        length: float = DEFAULT_ARROW_TIP_LENGTH,\n        start_angle: float = PI,\n        **kwargs: Any,\n    ) -> None:\n        self.start_angle = start_angle\n        Circle.__init__(\n            self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs\n        )\n        self.width = length\n        self.stretch_to_fit_height(length)\n\n\nclass ArrowCircleFilledTip(ArrowCircleTip):\n    r\"\"\"Circular arrow tip with filled tip.\"\"\"\n\n    def __init__(\n        self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs: Any\n    ) -> None:\n        super().__init__(fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs)\n\n\nclass ArrowSquareTip(ArrowTip, Square):\n    r\"\"\"Square arrow tip.\"\"\"\n\n    def __init__(\n        self,\n        fill_opacity: float = 0,\n        stroke_width: float = 3,\n        length: float = DEFAULT_ARROW_TIP_LENGTH,\n        start_angle: float = PI,\n        **kwargs: Any,\n    ) -> None:\n        self.start_angle = start_angle\n        Square.__init__(\n            self,\n            fill_opacity=fill_opacity,\n            stroke_width=stroke_width,\n            side_length=length,\n            **kwargs,\n        )\n        self.width = length\n        self.stretch_to_fit_height(length)\n\n\nclass ArrowSquareFilledTip(ArrowSquareTip):\n    r\"\"\"Square arrow tip with filled tip.\"\"\"\n\n    def __init__(\n        self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs: Any\n    ) -> None:\n        super().__init__(fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs)\n"
  },
  {
    "path": "manim/mobject/graph.py",
    "content": "\"\"\"Mobjects used to represent mathematical graphs (think graph theory, not plotting).\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"Graph\",\n    \"DiGraph\",\n]\n\nimport itertools as it\nfrom collections.abc import Hashable, Iterable, Sequence\nfrom copy import copy\nfrom typing import TYPE_CHECKING, Any, Literal, Protocol, cast\n\nimport networkx as nx\nimport numpy as np\n\nif TYPE_CHECKING:\n    from typing import TypeAlias\n\n    from manim.scene.scene import Scene\n    from manim.typing import Point3D, Point3DLike\n\n    NxGraph: TypeAlias = nx.classes.graph.Graph | nx.classes.digraph.DiGraph\n\nfrom manim.animation.composition import AnimationGroup\nfrom manim.animation.creation import Create, Uncreate\nfrom manim.mobject.geometry.arc import Dot, LabeledDot\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.mobject import Mobject, override_animate\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.mobject.text.tex_mobject import MathTex\nfrom manim.mobject.types.vectorized_mobject import VMobject\nfrom manim.utils.color import BLACK\n\n\nclass LayoutFunction(Protocol):\n    \"\"\"A protocol for automatic layout functions that compute a layout for a graph to be used in :meth:`~.Graph.change_layout`.\n\n    .. note:: The layout function must be a pure function, i.e., it must not modify the graph passed to it.\n\n    Examples\n    --------\n\n    Here is an example that arranges nodes in an n x m grid in sorted order.\n\n    .. manim:: CustomLayoutExample\n        :save_last_frame:\n\n        class CustomLayoutExample(Scene):\n            def construct(self):\n                import numpy as np\n                import networkx as nx\n\n                # create custom layout\n                def custom_layout(\n                    graph: nx.Graph,\n                    scale: float | tuple[float, float, float] = 2,\n                    n: int | None = None,\n                    *args: Any,\n                    **kwargs: Any,\n                ):\n                    nodes = sorted(list(graph))\n                    height = len(nodes) // n\n                    return {\n                        node: (scale * np.array([\n                            (i % n) - (n-1)/2,\n                            -(i // n) + height/2,\n                            0\n                        ])) for i, node in enumerate(graph)\n                    }\n\n                # draw graph\n                n = 4\n                graph = Graph(\n                    [i for i in range(4 * 2 - 1)],\n                    [(0, 1), (0, 4), (1, 2), (1, 5), (2, 3), (2, 6), (4, 5), (5, 6)],\n                    labels=True,\n                    layout=custom_layout,\n                    layout_config={'n': n}\n                )\n                self.add(graph)\n\n    Several automatic layouts are provided by manim, and can be used by passing their name as the ``layout`` parameter to :meth:`~.Graph.change_layout`.\n    Alternatively, a custom layout function can be passed to :meth:`~.Graph.change_layout` as the ``layout`` parameter. Such a function must adhere to the :class:`~.LayoutFunction` protocol.\n\n    The :class:`~.LayoutFunction` s provided by manim are illustrated below:\n\n    - Circular Layout: places the vertices on a circle\n\n    .. manim:: CircularLayout\n        :save_last_frame:\n\n        class CircularLayout(Scene):\n            def construct(self):\n                graph = Graph(\n                    [1, 2, 3, 4, 5, 6],\n                    [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)],\n                    layout=\"circular\",\n                    labels=True\n                )\n                self.add(graph)\n\n    - Kamada Kawai Layout: tries to place the vertices such that the given distances between them are respected\n\n    .. manim:: KamadaKawaiLayout\n        :save_last_frame:\n\n        class KamadaKawaiLayout(Scene):\n            def construct(self):\n                from collections import defaultdict\n                distances: dict[int, dict[int, float]] = defaultdict(dict)\n\n                # set desired distances\n                distances[1][2] = 1  # distance between vertices 1 and 2 is 1\n                distances[2][3] = 1  # distance between vertices 2 and 3 is 1\n                distances[3][4] = 2  # etc\n                distances[4][5] = 3\n                distances[5][6] = 5\n                distances[6][1] = 8\n\n                graph = Graph(\n                    [1, 2, 3, 4, 5, 6],\n                    [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1)],\n                    layout=\"kamada_kawai\",\n                    layout_config={\"dist\": distances},\n                    layout_scale=4,\n                    labels=True\n                )\n                self.add(graph)\n\n    - Partite Layout: places vertices into distinct partitions\n\n    .. manim:: PartiteLayout\n        :save_last_frame:\n\n        class PartiteLayout(Scene):\n            def construct(self):\n                graph = Graph(\n                    [1, 2, 3, 4, 5, 6],\n                    [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)],\n                    layout=\"partite\",\n                    layout_config={\"partitions\": [[1,2],[3,4],[5,6]]},\n                    labels=True\n                )\n                self.add(graph)\n\n    - Planar Layout: places vertices such that edges do not cross\n\n    .. manim:: PlanarLayout\n        :save_last_frame:\n\n        class PlanarLayout(Scene):\n            def construct(self):\n                graph = Graph(\n                    [1, 2, 3, 4, 5, 6],\n                    [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)],\n                    layout=\"planar\",\n                    layout_scale=4,\n                    labels=True\n                )\n                self.add(graph)\n\n    - Random Layout: randomly places vertices\n\n    .. manim:: RandomLayout\n        :save_last_frame:\n\n        class RandomLayout(Scene):\n            def construct(self):\n                graph = Graph(\n                    [1, 2, 3, 4, 5, 6],\n                    [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)],\n                    layout=\"random\",\n                    labels=True\n                )\n                self.add(graph)\n\n    - Shell Layout: places vertices in concentric circles\n\n    .. manim:: ShellLayout\n        :save_last_frame:\n\n        class ShellLayout(Scene):\n            def construct(self):\n                nlist = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]\n                graph = Graph(\n                    [1, 2, 3, 4, 5, 6, 7, 8, 9],\n                    [(1, 2), (2, 3), (3, 1), (4, 1), (4, 2), (5, 2), (6, 2), (6, 3), (7, 3), (8, 3), (8, 1), (9, 1)],\n                    layout=\"shell\",\n                    layout_config={\"nlist\": nlist},\n                    labels=True\n                )\n                self.add(graph)\n\n    - Spectral Layout: places vertices using the eigenvectors of the graph Laplacian (clusters nodes which are an approximation of the ratio cut)\n\n    .. manim:: SpectralLayout\n        :save_last_frame:\n\n        class SpectralLayout(Scene):\n            def construct(self):\n                graph = Graph(\n                    [1, 2, 3, 4, 5, 6],\n                    [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)],\n                    layout=\"spectral\",\n                    labels=True\n                )\n                self.add(graph)\n\n    - Sprial Layout: places vertices in a spiraling pattern\n\n    .. manim:: SpiralLayout\n        :save_last_frame:\n\n        class SpiralLayout(Scene):\n            def construct(self):\n                graph = Graph(\n                    [1, 2, 3, 4, 5, 6],\n                    [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)],\n                    layout=\"spiral\",\n                    labels=True\n                )\n                self.add(graph)\n\n    - Spring Layout: places nodes according to the Fruchterman-Reingold force-directed algorithm (attempts to minimize edge length while maximizing node separation)\n\n    .. manim:: SpringLayout\n        :save_last_frame:\n\n        class SpringLayout(Scene):\n            def construct(self):\n                graph = Graph(\n                    [1, 2, 3, 4, 5, 6],\n                    [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1), (5, 1), (1, 3), (3, 5)],\n                    layout=\"spring\",\n                    labels=True\n                )\n                self.add(graph)\n\n    - Tree Layout: places vertices into a tree with a root node and branches (can only be used with legal trees)\n\n    .. manim:: TreeLayout\n        :save_last_frame:\n\n        class TreeLayout(Scene):\n            def construct(self):\n                graph = Graph(\n                    [1, 2, 3, 4, 5, 6, 7],\n                    [(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)],\n                    layout=\"tree\",\n                    layout_config={\"root_vertex\": 1},\n                    labels=True\n                )\n                self.add(graph)\n\n    \"\"\"\n\n    def __call__(\n        self,\n        graph: NxGraph,\n        scale: float | tuple[float, float, float] = 2,\n        *args: Any,\n        **kwargs: Any,\n    ) -> dict[Hashable, Point3D]:\n        \"\"\"Given a graph and a scale, return a dictionary of coordinates.\n\n        Parameters\n        ----------\n        graph\n            The underlying NetworkX graph to be laid out. DO NOT MODIFY.\n        scale\n            Either a single float value, or a tuple of three float values specifying the scale along each axis.\n\n        Returns\n        -------\n        dict[Hashable, Point3D]\n            A dictionary mapping vertices to their positions.\n        \"\"\"\n        ...\n\n\ndef _partite_layout(\n    nx_graph: NxGraph,\n    scale: float = 2,\n    partitions: Sequence[Sequence[Hashable]] | None = None,\n    **kwargs: Any,\n) -> dict[Hashable, Point3D]:\n    if partitions is None or len(partitions) == 0:\n        raise ValueError(\n            \"The partite layout requires partitions parameter to contain the partition of the vertices\",\n        )\n    partition_count = len(partitions)\n    for i in range(partition_count):\n        for v in partitions[i]:\n            if nx_graph.nodes[v] is None:\n                raise ValueError(\n                    \"The partition must contain arrays of vertices in the graph\",\n                )\n            nx_graph.nodes[v][\"subset\"] = i\n    # Add missing vertices to their own side\n    for v in nx_graph.nodes:\n        if \"subset\" not in nx_graph.nodes[v]:\n            nx_graph.nodes[v][\"subset\"] = partition_count\n\n    return nx.layout.multipartite_layout(nx_graph, scale=scale, **kwargs)\n\n\ndef _random_layout(nx_graph: NxGraph, scale: float = 2, **kwargs: Any):\n    # the random layout places coordinates in [0, 1)\n    # we need to rescale manually afterwards...\n    auto_layout = nx.layout.random_layout(nx_graph, **kwargs)\n    for k, v in auto_layout.items():\n        auto_layout[k] = 2 * scale * (v - np.array([0.5, 0.5]))\n    return {k: np.append(v, [0]) for k, v in auto_layout.items()}\n\n\ndef _tree_layout(\n    T: NxGraph,\n    root_vertex: Hashable | None = None,\n    scale: float | tuple | None = 2,\n    vertex_spacing: tuple | None = None,\n    orientation: str = \"down\",\n):\n    if root_vertex is None:\n        raise ValueError(\"The tree layout requires the root_vertex parameter\")\n    if not nx.is_tree(T):\n        raise ValueError(\"The tree layout must be used with trees\")\n\n    children = {root_vertex: list(T.neighbors(root_vertex))}\n    # The following code is SageMath's tree layout implementation, taken from\n    # https://github.com/sagemath/sage/blob/cc60cfebc4576fed8b01f0fc487271bdee3cefed/src/sage/graphs/graph_plot.py#L1447\n\n    # Always make a copy of the children because they get eaten\n    stack = [list(children[root_vertex]).copy()]\n    stick = [root_vertex]\n    parent = dict.fromkeys(children[root_vertex], root_vertex)\n    pos = {}\n    obstruction = [0.0] * len(T)\n    o = -1 if orientation == \"down\" else 1\n\n    def slide(v, dx):\n        \"\"\"\n        Shift the vertex v and its descendants to the right by dx.\n        Precondition: v and its descendents have already had their\n        positions computed.\n        \"\"\"\n        level = [v]\n        while level:\n            nextlevel = []\n            for u in level:\n                x, y = pos[u]\n                x += dx\n                obstruction[y] = max(x + 1, obstruction[y])\n                pos[u] = x, y\n                nextlevel += children[u]\n            level = nextlevel\n\n    while stack:\n        C = stack[-1]\n        if not C:\n            p = stick.pop()\n            stack.pop()\n            cp = children[p]\n            y = o * len(stack)\n            if not cp:\n                x = obstruction[y]\n                pos[p] = x, y\n            else:\n                x = sum(pos[c][0] for c in cp) / float(len(cp))\n                pos[p] = x, y\n                ox = obstruction[y]\n                if x < ox:\n                    slide(p, ox - x)\n                    x = ox\n            obstruction[y] = x + 1\n            continue\n\n        t = C.pop()\n        pt = parent[t]\n\n        ct = [u for u in list(T.neighbors(t)) if u != pt]\n        for c in ct:\n            parent[c] = t\n        children[t] = copy(ct)\n\n        stack.append(ct)\n        stick.append(t)\n\n    # the resulting layout is then rescaled again to fit on Manim's canvas\n\n    x_min = min(pos.values(), key=lambda t: t[0])[0]\n    x_max = max(pos.values(), key=lambda t: t[0])[0]\n    y_min = min(pos.values(), key=lambda t: t[1])[1]\n    y_max = max(pos.values(), key=lambda t: t[1])[1]\n    center = np.array([x_min + x_max, y_min + y_max, 0]) / 2\n    height = y_max - y_min\n    width = x_max - x_min\n    if vertex_spacing is None:\n        if isinstance(scale, (float, int)) and (width > 0 or height > 0):\n            sf = 2 * scale / max(width, height)\n        elif isinstance(scale, tuple):\n            sw = 2 * scale[0] / width if scale[0] is not None and width > 0 else 1\n\n            sh = 2 * scale[1] / height if scale[1] is not None and height > 0 else 1\n\n            sf = np.array([sw, sh, 0])\n        else:\n            sf = 1\n    else:\n        sx, sy = vertex_spacing\n        sf = np.array([sx, sy, 0])\n    return {v: (np.array([x, y, 0]) - center) * sf for v, (x, y) in pos.items()}\n\n\nLayoutName = Literal[\n    \"circular\",\n    \"kamada_kawai\",\n    \"partite\",\n    \"planar\",\n    \"random\",\n    \"shell\",\n    \"spectral\",\n    \"spiral\",\n    \"spring\",\n    \"tree\",\n]\n\n_layouts: dict[LayoutName, LayoutFunction] = {\n    \"circular\": cast(LayoutFunction, nx.layout.circular_layout),\n    \"kamada_kawai\": cast(LayoutFunction, nx.layout.kamada_kawai_layout),\n    \"partite\": cast(LayoutFunction, _partite_layout),\n    \"planar\": cast(LayoutFunction, nx.layout.planar_layout),\n    \"random\": cast(LayoutFunction, _random_layout),\n    \"shell\": cast(LayoutFunction, nx.layout.shell_layout),\n    \"spectral\": cast(LayoutFunction, nx.layout.spectral_layout),\n    \"spiral\": cast(LayoutFunction, nx.layout.spiral_layout),\n    \"spring\": cast(LayoutFunction, nx.layout.spring_layout),\n    \"tree\": cast(LayoutFunction, _tree_layout),\n}\n\n\ndef _determine_graph_layout(\n    nx_graph: nx.classes.graph.Graph | nx.classes.digraph.DiGraph,\n    layout: LayoutName | dict[Hashable, Point3DLike] | LayoutFunction = \"spring\",\n    layout_scale: float | tuple[float, float, float] = 2,\n    layout_config: dict[str, Any] | None = None,\n) -> dict[Hashable, Point3DLike]:\n    if layout_config is None:\n        layout_config = {}\n\n    if isinstance(layout, dict):\n        return layout\n    elif layout in _layouts:\n        auto_layout = _layouts[layout](nx_graph, scale=layout_scale, **layout_config)\n        # NetworkX returns a dictionary of 3D points if the dimension\n        # is specified to be 3. Otherwise, it returns a dictionary of\n        # 2D points, so adjusting is required.\n        if (\n            layout_config.get(\"dim\") == 3\n            or auto_layout[next(auto_layout.__iter__())].shape[0] == 3\n        ):\n            return auto_layout\n        else:\n            return {k: np.append(v, [0]) for k, v in auto_layout.items()}\n    else:\n        try:\n            return cast(LayoutFunction, layout)(\n                nx_graph, scale=layout_scale, **layout_config\n            )\n        except TypeError as e:\n            raise ValueError(\n                f\"The layout '{layout}' is neither a recognized layout, a layout function,\"\n                \"nor a vertex placement dictionary.\",\n            ) from e\n\n\nclass GenericGraph(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"Abstract base class for graphs (that is, a collection of vertices\n    connected with edges).\n\n    Graphs can be instantiated by passing both a list of (distinct, hashable)\n    vertex names, together with list of edges (as tuples of vertex names). See\n    the examples for concrete implementations of this class for details.\n\n    .. note::\n\n        This implementation uses updaters to make the edges move with\n        the vertices.\n\n\n    See also\n    --------\n\n    :class:`.Graph`\n    :class:`.DiGraph`\n\n\n    Parameters\n    ----------\n\n    vertices\n        A list of vertices. Must be hashable elements.\n    edges\n        A list of edges, specified as tuples ``(u, v)`` where both ``u``\n        and ``v`` are vertices.\n    labels\n        Controls whether or not vertices are labeled. If ``False`` (the default),\n        the vertices are not labeled; if ``True`` they are labeled using their\n        names (as specified in ``vertices``) via :class:`~.MathTex`. Alternatively,\n        custom labels can be specified by passing a dictionary whose keys are\n        the vertices, and whose values are the corresponding vertex labels\n        (rendered via, e.g., :class:`~.Text` or :class:`~.Tex`).\n    label_fill_color\n        Sets the fill color of the default labels generated when ``labels``\n        is set to ``True``. Has no effect for other values of ``labels``.\n    layout\n        Either one of ``\"spring\"`` (the default), ``\"circular\"``, ``\"kamada_kawai\"``,\n        ``\"planar\"``, ``\"random\"``, ``\"shell\"``, ``\"spectral\"``, ``\"spiral\"``, ``\"tree\"``, and ``\"partite\"``\n        for automatic vertex positioning primarily using ``networkx``\n        (see `their documentation <https://networkx.org/documentation/stable/reference/drawing.html#module-networkx.drawing.layout>`_\n        for more details), a dictionary specifying a coordinate (value)\n        for each vertex (key) for manual positioning, or a .:class:`~.LayoutFunction` with a user-defined automatic layout.\n    layout_config\n        Only for automatic layouts. A dictionary whose entries\n        are passed as keyword arguments to the named layout or automatic layout function\n        specified via ``layout``.\n        The ``tree`` layout also accepts a special parameter ``vertex_spacing``\n        passed as a keyword argument inside the ``layout_config`` dictionary.\n        Passing a tuple ``(space_x, space_y)`` as this argument overrides\n        the value of ``layout_scale`` and ensures that vertices are arranged\n        in a way such that the centers of siblings in the same layer are\n        at least ``space_x`` units apart horizontally, and neighboring layers\n        are spaced ``space_y`` units vertically.\n    layout_scale\n        The scale of automatically generated layouts: the vertices will\n        be arranged such that the coordinates are located within the\n        interval ``[-scale, scale]``. Some layouts accept a tuple ``(scale_x, scale_y)``\n        causing the first coordinate to be in the interval ``[-scale_x, scale_x]``,\n        and the second in ``[-scale_y, scale_y]``. Default: 2.\n    vertex_type\n        The mobject class used for displaying vertices in the scene.\n    vertex_config\n        Either a dictionary containing keyword arguments to be passed to\n        the class specified via ``vertex_type``, or a dictionary whose keys\n        are the vertices, and whose values are dictionaries containing keyword\n        arguments for the mobject related to the corresponding vertex.\n    vertex_mobjects\n        A dictionary whose keys are the vertices, and whose values are\n        mobjects to be used as vertices. Passing vertices here overrides\n        all other configuration options for a vertex.\n    edge_type\n        The mobject class used for displaying edges in the scene.\n        Must be a subclass of :class:`~.Line` for default updaters to work.\n    edge_config\n        Either a dictionary containing keyword arguments to be passed\n        to the class specified via ``edge_type``, or a dictionary whose\n        keys are the edges, and whose values are dictionaries containing\n        keyword arguments for the mobject related to the corresponding edge.\n    \"\"\"\n\n    def __init__(\n        self,\n        vertices: Sequence[Hashable],\n        edges: Sequence[tuple[Hashable, Hashable]],\n        labels: bool | dict = False,\n        label_fill_color: str = BLACK,\n        layout: LayoutName | dict[Hashable, Point3DLike] | LayoutFunction = \"spring\",\n        layout_scale: float | tuple[float, float, float] = 2,\n        layout_config: dict | None = None,\n        vertex_type: type[Mobject] = Dot,\n        vertex_config: dict | None = None,\n        vertex_mobjects: dict | None = None,\n        edge_type: type[Mobject] = Line,\n        partitions: Sequence[Sequence[Hashable]] | None = None,\n        root_vertex: Hashable | None = None,\n        edge_config: dict | None = None,\n    ) -> None:\n        super().__init__()\n\n        nx_graph = self._empty_networkx_graph()\n        nx_graph.add_nodes_from(vertices)\n        nx_graph.add_edges_from(edges)\n        self._graph = nx_graph\n\n        if isinstance(labels, dict):\n            self._labels = labels\n        elif isinstance(labels, bool):\n            if labels:\n                self._labels = {v: MathTex(v, color=label_fill_color) for v in vertices}\n            else:\n                self._labels = {}\n\n        if self._labels and vertex_type is Dot:\n            vertex_type = LabeledDot\n\n        if vertex_mobjects is None:\n            vertex_mobjects = {}\n\n        # build vertex_config\n        if vertex_config is None:\n            vertex_config = {}\n        default_vertex_config = {}\n        if vertex_config:\n            default_vertex_config = {\n                k: v for k, v in vertex_config.items() if k not in vertices\n            }\n        self._vertex_config = {\n            v: vertex_config.get(v, copy(default_vertex_config)) for v in vertices\n        }\n        self.default_vertex_config = default_vertex_config\n        for v, label in self._labels.items():\n            self._vertex_config[v][\"label\"] = label\n\n        self.vertices = {v: vertex_type(**self._vertex_config[v]) for v in vertices}\n        self.vertices.update(vertex_mobjects)\n\n        self.change_layout(\n            layout=layout,\n            layout_scale=layout_scale,\n            layout_config=layout_config,\n            partitions=partitions,\n            root_vertex=root_vertex,\n        )\n\n        # build edge_config\n        if edge_config is None:\n            edge_config = {}\n        default_tip_config = {}\n        default_edge_config = {}\n        if edge_config:\n            default_tip_config = edge_config.pop(\"tip_config\", {})\n            default_edge_config = {\n                k: v\n                for k, v in edge_config.items()\n                if not isinstance(\n                    k, tuple\n                )  # everything that is not an edge is an option\n            }\n        self._edge_config = {}\n        self._tip_config = {}\n        for e in edges:\n            if e in edge_config:\n                self._tip_config[e] = edge_config[e].pop(\n                    \"tip_config\", copy(default_tip_config)\n                )\n                self._edge_config[e] = edge_config[e]\n            else:\n                self._tip_config[e] = copy(default_tip_config)\n                self._edge_config[e] = copy(default_edge_config)\n\n        self.default_edge_config = default_edge_config\n        self._populate_edge_dict(edges, edge_type)\n\n        self.add(*self.vertices.values())\n        self.add(*self.edges.values())\n\n        self.add_updater(self.update_edges)\n\n    @staticmethod\n    def _empty_networkx_graph() -> nx.classes.graph.Graph:\n        \"\"\"Return an empty networkx graph for the given graph type.\"\"\"\n        raise NotImplementedError(\"To be implemented in concrete subclasses\")\n\n    def _populate_edge_dict(\n        self, edges: list[tuple[Hashable, Hashable]], edge_type: type[Mobject]\n    ):\n        \"\"\"Helper method for populating the edges of the graph.\"\"\"\n        raise NotImplementedError(\"To be implemented in concrete subclasses\")\n\n    def __getitem__(self: Graph, v: Hashable) -> Mobject:\n        return self.vertices[v]\n\n    def _create_vertex(\n        self,\n        vertex: Hashable,\n        position: Point3DLike | None = None,\n        label: bool = False,\n        label_fill_color: str = BLACK,\n        vertex_type: type[Mobject] = Dot,\n        vertex_config: dict | None = None,\n        vertex_mobject: dict | None = None,\n    ) -> tuple[Hashable, Point3D, dict, Mobject]:\n        np_position: Point3D = (\n            self.get_center() if position is None else np.asarray(position)\n        )\n\n        if vertex_config is None:\n            vertex_config = {}\n\n        if vertex in self.vertices:\n            raise ValueError(\n                f\"Vertex identifier '{vertex}' is already used for a vertex in this graph.\",\n            )\n\n        if label is True:\n            label = MathTex(vertex, color=label_fill_color)\n        elif vertex in self._labels:\n            label = self._labels[vertex]\n        elif not isinstance(label, (Mobject, OpenGLMobject)):\n            label = None\n\n        base_vertex_config = copy(self.default_vertex_config)\n        base_vertex_config.update(vertex_config)\n        vertex_config = base_vertex_config\n\n        if label is not None:\n            vertex_config[\"label\"] = label\n            if vertex_type is Dot:\n                vertex_type = LabeledDot\n\n        if vertex_mobject is None:\n            vertex_mobject = vertex_type(**vertex_config)\n\n        vertex_mobject.move_to(np_position)\n\n        return (vertex, np_position, vertex_config, vertex_mobject)\n\n    def _add_created_vertex(\n        self,\n        vertex: Hashable,\n        position: Point3DLike,\n        vertex_config: dict,\n        vertex_mobject: Mobject,\n    ) -> Mobject:\n        if vertex in self.vertices:\n            raise ValueError(\n                f\"Vertex identifier '{vertex}' is already used for a vertex in this graph.\",\n            )\n\n        self._graph.add_node(vertex)\n        self._layout[vertex] = position\n\n        if \"label\" in vertex_config:\n            self._labels[vertex] = vertex_config[\"label\"]\n\n        self._vertex_config[vertex] = vertex_config\n\n        self.vertices[vertex] = vertex_mobject\n        self.vertices[vertex].move_to(position)\n        self.add(self.vertices[vertex])\n\n        return self.vertices[vertex]\n\n    def _add_vertex(\n        self,\n        vertex: Hashable,\n        position: Point3DLike | None = None,\n        label: bool = False,\n        label_fill_color: str = BLACK,\n        vertex_type: type[Mobject] = Dot,\n        vertex_config: dict | None = None,\n        vertex_mobject: dict | None = None,\n    ) -> Mobject:\n        \"\"\"Add a vertex to the graph.\n\n        Parameters\n        ----------\n\n        vertex\n            A hashable vertex identifier.\n        position\n            The coordinates where the new vertex should be added. If ``None``, the center\n            of the graph is used.\n        label\n            Controls whether or not the vertex is labeled. If ``False`` (the default),\n            the vertex is not labeled; if ``True`` it is labeled using its\n            names (as specified in ``vertex``) via :class:`~.MathTex`. Alternatively,\n            any :class:`~.Mobject` can be passed to be used as the label.\n        label_fill_color\n            Sets the fill color of the default labels generated when ``labels``\n            is set to ``True``. Has no effect for other values of ``label``.\n        vertex_type\n            The mobject class used for displaying vertices in the scene.\n        vertex_config\n            A dictionary containing keyword arguments to be passed to\n            the class specified via ``vertex_type``.\n        vertex_mobject\n            The mobject to be used as the vertex. Overrides all other\n            vertex customization options.\n        \"\"\"\n        return self._add_created_vertex(\n            *self._create_vertex(\n                vertex=vertex,\n                position=position,\n                label=label,\n                label_fill_color=label_fill_color,\n                vertex_type=vertex_type,\n                vertex_config=vertex_config,\n                vertex_mobject=vertex_mobject,\n            )\n        )\n\n    def _create_vertices(\n        self: Graph,\n        *vertices: Hashable,\n        positions: dict | None = None,\n        labels: bool = False,\n        label_fill_color: str = BLACK,\n        vertex_type: type[Mobject] = Dot,\n        vertex_config: dict | None = None,\n        vertex_mobjects: dict | None = None,\n    ) -> Iterable[tuple[Hashable, Point3D, dict, Mobject]]:\n        if positions is None:\n            positions = {}\n        if vertex_mobjects is None:\n            vertex_mobjects = {}\n\n        graph_center = self.get_center()\n        base_positions = dict.fromkeys(vertices, graph_center)\n        base_positions.update(positions)\n        positions = base_positions\n\n        if isinstance(labels, bool):\n            labels = dict.fromkeys(vertices, labels)\n        else:\n            assert isinstance(labels, dict)\n            base_labels = dict.fromkeys(vertices, False)\n            base_labels.update(labels)\n            labels = base_labels\n\n        if vertex_config is None:\n            vertex_config = copy(self.default_vertex_config)\n\n        assert isinstance(vertex_config, dict)\n        base_vertex_config = copy(self.default_vertex_config)\n        base_vertex_config.update(\n            {key: val for key, val in vertex_config.items() if key not in vertices},\n        )\n        vertex_config = {\n            v: (vertex_config[v] if v in vertex_config else copy(base_vertex_config))\n            for v in vertices\n        }\n\n        return [\n            self._create_vertex(\n                v,\n                position=positions[v],\n                label=labels[v],\n                label_fill_color=label_fill_color,\n                vertex_type=vertex_type,\n                vertex_config=vertex_config[v],\n                vertex_mobject=vertex_mobjects.get(v),\n            )\n            for v in vertices\n        ]\n\n    def add_vertices(\n        self: Graph,\n        *vertices: Hashable,\n        positions: dict | None = None,\n        labels: bool = False,\n        label_fill_color: str = BLACK,\n        vertex_type: type[Mobject] = Dot,\n        vertex_config: dict | None = None,\n        vertex_mobjects: dict | None = None,\n    ):\n        \"\"\"Add a list of vertices to the graph.\n\n        Parameters\n        ----------\n\n        vertices\n            Hashable vertex identifiers.\n        positions\n            A dictionary specifying the coordinates where the new vertices should be added.\n            If ``None``, all vertices are created at the center of the graph.\n        labels\n            Controls whether or not the vertex is labeled. If ``False`` (the default),\n            the vertex is not labeled; if ``True`` it is labeled using its\n            names (as specified in ``vertex``) via :class:`~.MathTex`. Alternatively,\n            any :class:`~.Mobject` can be passed to be used as the label.\n        label_fill_color\n            Sets the fill color of the default labels generated when ``labels``\n            is set to ``True``. Has no effect for other values of ``labels``.\n        vertex_type\n            The mobject class used for displaying vertices in the scene.\n        vertex_config\n            A dictionary containing keyword arguments to be passed to\n            the class specified via ``vertex_type``.\n        vertex_mobjects\n            A dictionary whose keys are the vertex identifiers, and whose\n            values are mobjects that should be used as vertices. Overrides\n            all other vertex customization options.\n        \"\"\"\n        return [\n            self._add_created_vertex(*v)\n            for v in self._create_vertices(\n                *vertices,\n                positions=positions,\n                labels=labels,\n                label_fill_color=label_fill_color,\n                vertex_type=vertex_type,\n                vertex_config=vertex_config,\n                vertex_mobjects=vertex_mobjects,\n            )\n        ]\n\n    @override_animate(add_vertices)\n    def _add_vertices_animation(self, *args, anim_args=None, **kwargs):\n        if anim_args is None:\n            anim_args = {}\n\n        animation = anim_args.pop(\"animation\", Create)\n\n        vertex_mobjects = self._create_vertices(*args, **kwargs)\n\n        def on_finish(scene: Scene):\n            for v in vertex_mobjects:\n                scene.remove(v[-1])\n                self._add_created_vertex(*v)\n\n        return AnimationGroup(\n            *(animation(v[-1], **anim_args) for v in vertex_mobjects),\n            group=self,\n            _on_finish=on_finish,\n        )\n\n    def _remove_vertex(self, vertex):\n        \"\"\"Remove a vertex (as well as all incident edges) from the graph.\n\n        Parameters\n        ----------\n\n        vertex\n            The identifier of a vertex to be removed.\n\n        Returns\n        -------\n\n        Group\n            A mobject containing all removed objects.\n\n        \"\"\"\n        if vertex not in self.vertices:\n            raise ValueError(\n                f\"The graph does not contain a vertex with identifier '{vertex}'\",\n            )\n\n        self._graph.remove_node(vertex)\n        self._layout.pop(vertex)\n        if vertex in self._labels:\n            self._labels.pop(vertex)\n        self._vertex_config.pop(vertex)\n\n        edge_tuples = [e for e in self.edges if vertex in e]\n        for e in edge_tuples:\n            self._edge_config.pop(e)\n        to_remove = [self.edges.pop(e) for e in edge_tuples]\n        to_remove.append(self.vertices.pop(vertex))\n\n        self.remove(*to_remove)\n        return self.get_group_class()(*to_remove)\n\n    def remove_vertices(self, *vertices):\n        \"\"\"Remove several vertices from the graph.\n\n        Parameters\n        ----------\n\n        vertices\n            Vertices to be removed from the graph.\n\n        Examples\n        --------\n        ::\n\n            >>> G = Graph([1, 2, 3], [(1, 2), (2, 3)])\n            >>> removed = G.remove_vertices(2, 3); removed\n            VGroup(Line, Line, Dot, Dot)\n            >>> G\n            Undirected graph on 1 vertices and 0 edges\n\n        \"\"\"\n        mobjects = []\n        for v in vertices:\n            mobjects.extend(self._remove_vertex(v).submobjects)\n        return self.get_group_class()(*mobjects)\n\n    @override_animate(remove_vertices)\n    def _remove_vertices_animation(self, *vertices, anim_args=None):\n        if anim_args is None:\n            anim_args = {}\n\n        animation = anim_args.pop(\"animation\", Uncreate)\n\n        mobjects = self.remove_vertices(*vertices)\n        return AnimationGroup(\n            *(animation(mobj, **anim_args) for mobj in mobjects), group=self\n        )\n\n    def _add_edge(\n        self,\n        edge: tuple[Hashable, Hashable],\n        edge_type: type[Mobject] = Line,\n        edge_config: dict | None = None,\n    ):\n        \"\"\"Add a new edge to the graph.\n\n        Parameters\n        ----------\n\n        edge\n            The edge (as a tuple of vertex identifiers) to be added. If a non-existing\n            vertex is passed, a new vertex with default settings will be created. Create\n            new vertices yourself beforehand to customize them.\n        edge_type\n            The mobject class used for displaying edges in the scene.\n        edge_config\n            A dictionary containing keyword arguments to be passed\n            to the class specified via ``edge_type``.\n\n        Returns\n        -------\n        Group\n            A group containing all newly added vertices and edges.\n\n        \"\"\"\n        if edge_config is None:\n            edge_config = self.default_edge_config.copy()\n        added_mobjects = [self._add_vertex(v) for v in edge if v not in self.vertices]\n        u, v = edge\n\n        self._graph.add_edge(u, v)\n\n        base_edge_config = self.default_edge_config.copy()\n        base_edge_config.update(edge_config)\n        edge_config = base_edge_config\n        self._edge_config[(u, v)] = edge_config\n\n        edge_mobject = edge_type(\n            start=self[u].get_center(),\n            end=self[v].get_center(),\n            z_index=-1,\n            **edge_config,\n        )\n        self.edges[(u, v)] = edge_mobject\n\n        self.add(edge_mobject)\n        added_mobjects.append(edge_mobject)\n        return self.get_group_class()(*added_mobjects)\n\n    def add_edges(\n        self,\n        *edges: tuple[Hashable, Hashable],\n        edge_type: type[Mobject] = Line,\n        edge_config: dict | None = None,\n        **kwargs,\n    ):\n        \"\"\"Add new edges to the graph.\n\n        Parameters\n        ----------\n\n        edges\n            Edges (as tuples of vertex identifiers) to be added. If a non-existing\n            vertex is passed, a new vertex with default settings will be created. Create\n            new vertices yourself beforehand to customize them.\n        edge_type\n            The mobject class used for displaying edges in the scene.\n        edge_config\n            A dictionary either containing keyword arguments to be passed\n            to the class specified via ``edge_type``, or a dictionary\n            whose keys are the edge tuples, and whose values are dictionaries\n            containing keyword arguments to be passed for the construction\n            of the corresponding edge.\n        kwargs\n            Any further keyword arguments are passed to :meth:`.add_vertices`\n            which is used to create new vertices in the passed edges.\n\n        Returns\n        -------\n        Group\n            A group containing all newly added vertices and edges.\n\n        \"\"\"\n        if edge_config is None:\n            edge_config = {}\n        non_edge_settings = {k: v for (k, v) in edge_config.items() if k not in edges}\n        base_edge_config = self.default_edge_config.copy()\n        base_edge_config.update(non_edge_settings)\n        base_edge_config = {e: base_edge_config.copy() for e in edges}\n        for e in edges:\n            base_edge_config[e].update(edge_config.get(e, {}))\n        edge_config = base_edge_config\n\n        edge_vertices = set(it.chain(*edges))\n        new_vertices = [v for v in edge_vertices if v not in self.vertices]\n        added_vertices = self.add_vertices(*new_vertices, **kwargs)\n\n        added_mobjects = sum(\n            (\n                self._add_edge(\n                    edge,\n                    edge_type=edge_type,\n                    edge_config=edge_config[edge],\n                ).submobjects\n                for edge in edges\n            ),\n            added_vertices,\n        )\n        return self.get_group_class()(*added_mobjects)\n\n    @override_animate(add_edges)\n    def _add_edges_animation(self, *args, anim_args=None, **kwargs):\n        if anim_args is None:\n            anim_args = {}\n        animation = anim_args.pop(\"animation\", Create)\n\n        mobjects = self.add_edges(*args, **kwargs)\n        return AnimationGroup(\n            *(animation(mobj, **anim_args) for mobj in mobjects), group=self\n        )\n\n    def _remove_edge(self, edge: tuple[Hashable]):\n        \"\"\"Remove an edge from the graph.\n\n        Parameters\n        ----------\n\n        edge\n            The edge (i.e., a tuple of vertex identifiers) to be removed from the graph.\n\n        Returns\n        -------\n\n        Mobject\n            The removed edge.\n\n        \"\"\"\n        if edge not in self.edges:\n            raise ValueError(f\"The graph does not contain a edge '{edge}'\")\n\n        edge_mobject = self.edges.pop(edge)\n\n        self._graph.remove_edge(*edge)\n        self._edge_config.pop(edge, None)\n\n        self.remove(edge_mobject)\n        return edge_mobject\n\n    def remove_edges(self, *edges: tuple[Hashable]):\n        \"\"\"Remove several edges from the graph.\n\n        Parameters\n        ----------\n        edges\n            Edges to be removed from the graph.\n\n        Returns\n        -------\n        Group\n            A group containing all removed edges.\n\n        \"\"\"\n        edge_mobjects = [self._remove_edge(edge) for edge in edges]\n        return self.get_group_class()(*edge_mobjects)\n\n    @override_animate(remove_edges)\n    def _remove_edges_animation(self, *edges, anim_args=None):\n        if anim_args is None:\n            anim_args = {}\n\n        animation = anim_args.pop(\"animation\", Uncreate)\n\n        mobjects = self.remove_edges(*edges)\n        return AnimationGroup(*(animation(mobj, **anim_args) for mobj in mobjects))\n\n    @classmethod\n    def from_networkx(\n        cls, nxgraph: nx.classes.graph.Graph | nx.classes.digraph.DiGraph, **kwargs\n    ):\n        \"\"\"Build a :class:`~.Graph` or :class:`~.DiGraph` from a\n        given ``networkx`` graph.\n\n        Parameters\n        ----------\n\n        nxgraph\n            A ``networkx`` graph or digraph.\n        **kwargs\n            Keywords to be passed to the constructor of :class:`~.Graph`.\n\n        Examples\n        --------\n\n        .. manim:: ImportNetworkxGraph\n\n            import networkx as nx\n\n            nxgraph = nx.erdos_renyi_graph(14, 0.5)\n\n            class ImportNetworkxGraph(Scene):\n                def construct(self):\n                    G = Graph.from_networkx(nxgraph, layout=\"spring\", layout_scale=3.5)\n                    self.play(Create(G))\n                    self.play(*[G[v].animate.move_to(5*RIGHT*np.cos(ind/7 * PI) +\n                                                     3*UP*np.sin(ind/7 * PI))\n                                for ind, v in enumerate(G.vertices)])\n                    self.play(Uncreate(G))\n\n        \"\"\"\n        return cls(list(nxgraph.nodes), list(nxgraph.edges), **kwargs)\n\n    def change_layout(\n        self,\n        layout: LayoutName | dict[Hashable, Point3DLike] | LayoutFunction = \"spring\",\n        layout_scale: float | tuple[float, float, float] = 2,\n        layout_config: dict[str, Any] | None = None,\n        partitions: list[list[Hashable]] | None = None,\n        root_vertex: Hashable | None = None,\n    ) -> Graph:\n        \"\"\"Change the layout of this graph.\n\n        See the documentation of :class:`~.Graph` for details about the\n        keyword arguments.\n\n        Examples\n        --------\n\n        .. manim:: ChangeGraphLayout\n\n            class ChangeGraphLayout(Scene):\n                def construct(self):\n                    G = Graph([1, 2, 3, 4, 5], [(1, 2), (2, 3), (3, 4), (4, 5)],\n                              layout={1: [-2, 0, 0], 2: [-1, 0, 0], 3: [0, 0, 0],\n                                      4: [1, 0, 0], 5: [2, 0, 0]}\n                              )\n                    self.play(Create(G))\n                    self.play(G.animate.change_layout(\"circular\"))\n                    self.wait()\n        \"\"\"\n        layout_config = {} if layout_config is None else layout_config\n        if partitions is not None and \"partitions\" not in layout_config:\n            layout_config[\"partitions\"] = partitions\n        if root_vertex is not None and \"root_vertex\" not in layout_config:\n            layout_config[\"root_vertex\"] = root_vertex\n\n        self._layout = _determine_graph_layout(\n            self._graph,\n            layout=layout,\n            layout_scale=layout_scale,\n            layout_config=layout_config,\n        )\n\n        for v in self.vertices:\n            self[v].move_to(self._layout[v])\n        return self\n\n\nclass Graph(GenericGraph):\n    \"\"\"An undirected graph (vertices connected with edges).\n\n    The graph comes with an updater which makes the edges stick to\n    the vertices when moved around. See :class:`.DiGraph` for\n    a version with directed edges.\n\n    See also\n    --------\n\n    :class:`.GenericGraph`\n\n    Parameters\n    ----------\n\n    vertices\n        A list of vertices. Must be hashable elements.\n    edges\n        A list of edges, specified as tuples ``(u, v)`` where both ``u``\n        and ``v`` are vertices. The vertex order is irrelevant.\n    labels\n        Controls whether or not vertices are labeled. If ``False`` (the default),\n        the vertices are not labeled; if ``True`` they are labeled using their\n        names (as specified in ``vertices``) via :class:`~.MathTex`. Alternatively,\n        custom labels can be specified by passing a dictionary whose keys are\n        the vertices, and whose values are the corresponding vertex labels\n        (rendered via, e.g., :class:`~.Text` or :class:`~.Tex`).\n    label_fill_color\n        Sets the fill color of the default labels generated when ``labels``\n        is set to ``True``. Has no effect for other values of ``labels``.\n    layout\n        Either one of ``\"spring\"`` (the default), ``\"circular\"``, ``\"kamada_kawai\"``,\n        ``\"planar\"``, ``\"random\"``, ``\"shell\"``, ``\"spectral\"``, ``\"spiral\"``, ``\"tree\"``, and ``\"partite\"``\n        for automatic vertex positioning using ``networkx``\n        (see `their documentation <https://networkx.org/documentation/stable/reference/drawing.html#module-networkx.drawing.layout>`_\n        for more details), or a dictionary specifying a coordinate (value)\n        for each vertex (key) for manual positioning.\n    layout_config\n        Only for automatically generated layouts. A dictionary whose entries\n        are passed as keyword arguments to the automatic layout algorithm\n        specified via ``layout`` of ``networkx``.\n        The ``tree`` layout also accepts a special parameter ``vertex_spacing``\n        passed as a keyword argument inside the ``layout_config`` dictionary.\n        Passing a tuple ``(space_x, space_y)`` as this argument overrides\n        the value of ``layout_scale`` and ensures that vertices are arranged\n        in a way such that the centers of siblings in the same layer are\n        at least ``space_x`` units apart horizontally, and neighboring layers\n        are spaced ``space_y`` units vertically.\n    layout_scale\n        The scale of automatically generated layouts: the vertices will\n        be arranged such that the coordinates are located within the\n        interval ``[-scale, scale]``. Some layouts accept a tuple ``(scale_x, scale_y)``\n        causing the first coordinate to be in the interval ``[-scale_x, scale_x]``,\n        and the second in ``[-scale_y, scale_y]``. Default: 2.\n    vertex_type\n        The mobject class used for displaying vertices in the scene.\n    vertex_config\n        Either a dictionary containing keyword arguments to be passed to\n        the class specified via ``vertex_type``, or a dictionary whose keys\n        are the vertices, and whose values are dictionaries containing keyword\n        arguments for the mobject related to the corresponding vertex.\n    vertex_mobjects\n        A dictionary whose keys are the vertices, and whose values are\n        mobjects to be used as vertices. Passing vertices here overrides\n        all other configuration options for a vertex.\n    edge_type\n        The mobject class used for displaying edges in the scene.\n    edge_config\n        Either a dictionary containing keyword arguments to be passed\n        to the class specified via ``edge_type``, or a dictionary whose\n        keys are the edges, and whose values are dictionaries containing\n        keyword arguments for the mobject related to the corresponding edge.\n\n\n    Examples\n    --------\n\n    First, we create a small graph and demonstrate that the edges move\n    together with the vertices.\n\n    .. manim:: MovingVertices\n\n        class MovingVertices(Scene):\n            def construct(self):\n                vertices = [1, 2, 3, 4]\n                edges = [(1, 2), (2, 3), (3, 4), (1, 3), (1, 4)]\n                g = Graph(vertices, edges)\n                self.play(Create(g))\n                self.wait()\n                self.play(g[1].animate.move_to([1, 1, 0]),\n                          g[2].animate.move_to([-1, 1, 0]),\n                          g[3].animate.move_to([1, -1, 0]),\n                          g[4].animate.move_to([-1, -1, 0]))\n                self.wait()\n\n    There are several automatic positioning algorithms to choose from:\n\n    .. manim:: GraphAutoPosition\n        :save_last_frame:\n\n        class GraphAutoPosition(Scene):\n            def construct(self):\n                vertices = [1, 2, 3, 4, 5, 6, 7, 8]\n                edges = [(1, 7), (1, 8), (2, 3), (2, 4), (2, 5),\n                         (2, 8), (3, 4), (6, 1), (6, 2),\n                         (6, 3), (7, 2), (7, 4)]\n                autolayouts = [\"spring\", \"circular\", \"kamada_kawai\",\n                               \"planar\", \"random\", \"shell\",\n                               \"spectral\", \"spiral\"]\n                graphs = [Graph(vertices, edges, layout=lt).scale(0.5)\n                          for lt in autolayouts]\n                r1 = VGroup(*graphs[:3]).arrange()\n                r2 = VGroup(*graphs[3:6]).arrange()\n                r3 = VGroup(*graphs[6:]).arrange()\n                self.add(VGroup(r1, r2, r3).arrange(direction=DOWN))\n\n    Vertices can also be positioned manually:\n\n    .. manim:: GraphManualPosition\n        :save_last_frame:\n\n        class GraphManualPosition(Scene):\n            def construct(self):\n                vertices = [1, 2, 3, 4]\n                edges = [(1, 2), (2, 3), (3, 4), (4, 1)]\n                lt = {1: [0, 0, 0], 2: [1, 1, 0], 3: [1, -1, 0], 4: [-1, 0, 0]}\n                G = Graph(vertices, edges, layout=lt)\n                self.add(G)\n\n    The vertices in graphs can be labeled, and configurations for vertices\n    and edges can be modified both by default and for specific vertices and\n    edges.\n\n    .. note::\n\n        In ``edge_config``, edges can be passed in both directions: if\n        ``(u, v)`` is an edge in the graph, both ``(u, v)`` as well\n        as ``(v, u)`` can be used as keys in the dictionary.\n\n    .. manim:: LabeledModifiedGraph\n        :save_last_frame:\n\n        class LabeledModifiedGraph(Scene):\n            def construct(self):\n                vertices = [1, 2, 3, 4, 5, 6, 7, 8]\n                edges = [(1, 7), (1, 8), (2, 3), (2, 4), (2, 5),\n                         (2, 8), (3, 4), (6, 1), (6, 2),\n                         (6, 3), (7, 2), (7, 4)]\n                g = Graph(vertices, edges, layout=\"circular\", layout_scale=3,\n                          labels=True, vertex_config={7: {\"fill_color\": RED}},\n                          edge_config={(1, 7): {\"stroke_color\": RED},\n                                       (2, 7): {\"stroke_color\": RED},\n                                       (4, 7): {\"stroke_color\": RED}})\n                self.add(g)\n\n    You can also lay out a partite graph on columns by specifying\n    a list of the vertices on each side and choosing the partite layout.\n\n    .. note::\n\n        All vertices in your graph which are not listed in any of the partitions\n        are collected in their own partition and rendered in the rightmost column.\n\n    .. manim:: PartiteGraph\n        :save_last_frame:\n\n        import networkx as nx\n\n        class PartiteGraph(Scene):\n            def construct(self):\n                G = nx.Graph()\n                G.add_nodes_from([0, 1, 2, 3])\n                G.add_edges_from([(0, 2), (0,3), (1, 2)])\n                graph = Graph(list(G.nodes), list(G.edges), layout=\"partite\", partitions=[[0, 1]])\n                self.play(Create(graph))\n\n    The representation of a linear artificial neural network is facilitated\n    by the use of the partite layout and defining partitions for each layer.\n\n    .. manim:: LinearNN\n        :save_last_frame:\n\n        class LinearNN(Scene):\n            def construct(self):\n                edges = []\n                partitions = []\n                c = 0\n                layers = [2, 3, 3, 2]  # the number of neurons in each layer\n\n                for i in layers:\n                    partitions.append(list(range(c + 1, c + i + 1)))\n                    c += i\n                for i, v in enumerate(layers[1:]):\n                        last = sum(layers[:i+1])\n                        for j in range(v):\n                            for k in range(last - layers[i], last):\n                                edges.append((k + 1, j + last + 1))\n\n                vertices = np.arange(1, sum(layers) + 1)\n\n                graph = Graph(\n                    vertices,\n                    edges,\n                    layout='partite',\n                    partitions=partitions,\n                    layout_scale=3,\n                    vertex_config={'radius': 0.20},\n                )\n                self.add(graph)\n\n    The custom tree layout can be used to show the graph\n    by distance from the root vertex. You must pass the root vertex\n    of the tree.\n\n    .. manim:: Tree\n\n        import networkx as nx\n\n        class Tree(Scene):\n            def construct(self):\n                G = nx.Graph()\n\n                G.add_node(\"ROOT\")\n\n                for i in range(5):\n                    G.add_node(\"Child_%i\" % i)\n                    G.add_node(\"Grandchild_%i\" % i)\n                    G.add_node(\"Greatgrandchild_%i\" % i)\n\n                    G.add_edge(\"ROOT\", \"Child_%i\" % i)\n                    G.add_edge(\"Child_%i\" % i, \"Grandchild_%i\" % i)\n                    G.add_edge(\"Grandchild_%i\" % i, \"Greatgrandchild_%i\" % i)\n\n                self.play(Create(\n                    Graph(list(G.nodes), list(G.edges), layout=\"tree\", root_vertex=\"ROOT\")))\n\n    The following code sample illustrates the use of the ``vertex_spacing``\n    layout parameter specific to the ``\"tree\"`` layout. As mentioned\n    above, setting ``vertex_spacing`` overrides the specified value\n    for ``layout_scale``, and as such it is harder to control the size\n    of the mobject. However, we can adjust the captured frame and\n    zoom out by using a :class:`.MovingCameraScene`::\n\n        class LargeTreeGeneration(MovingCameraScene):\n            DEPTH = 4\n            CHILDREN_PER_VERTEX = 3\n            LAYOUT_CONFIG = {\"vertex_spacing\": (0.5, 1)}\n            VERTEX_CONF = {\"radius\": 0.25, \"color\": BLUE_B, \"fill_opacity\": 1}\n\n            def expand_vertex(self, g, vertex_id: str, depth: int):\n                new_vertices = [\n                    f\"{vertex_id}/{i}\" for i in range(self.CHILDREN_PER_VERTEX)\n                ]\n                new_edges = [(vertex_id, child_id) for child_id in new_vertices]\n                g.add_edges(\n                    *new_edges,\n                    vertex_config=self.VERTEX_CONF,\n                    positions={\n                        k: g.vertices[vertex_id].get_center() + 0.1 * DOWN\n                        for k in new_vertices\n                    },\n                )\n                if depth < self.DEPTH:\n                    for child_id in new_vertices:\n                        self.expand_vertex(g, child_id, depth + 1)\n\n                return g\n\n            def construct(self):\n                g = Graph([\"ROOT\"], [], vertex_config=self.VERTEX_CONF)\n                g = self.expand_vertex(g, \"ROOT\", 1)\n                self.add(g)\n\n                self.play(\n                    g.animate.change_layout(\n                        \"tree\",\n                        root_vertex=\"ROOT\",\n                        layout_config=self.LAYOUT_CONFIG,\n                    )\n                )\n                self.play(self.camera.auto_zoom(g, margin=1), run_time=0.5)\n    \"\"\"\n\n    @staticmethod\n    def _empty_networkx_graph() -> nx.Graph:\n        return nx.Graph()\n\n    def _populate_edge_dict(\n        self, edges: list[tuple[Hashable, Hashable]], edge_type: type[Mobject]\n    ):\n        self.edges = {\n            (u, v): edge_type(\n                start=self[u].get_center(),\n                end=self[v].get_center(),\n                z_index=-1,\n                **self._edge_config[(u, v)],\n            )\n            for (u, v) in edges\n        }\n\n    def update_edges(self, graph):\n        for (u, v), edge in graph.edges.items():\n            # Undirected graph has a Line edge\n            edge.set_points_by_ends(\n                graph[u].get_center(),\n                graph[v].get_center(),\n                buff=self._edge_config.get(\"buff\", 0),\n                path_arc=self._edge_config.get(\"path_arc\", 0),\n            )\n\n    def __repr__(self: Graph) -> str:\n        return f\"Undirected graph on {len(self.vertices)} vertices and {len(self.edges)} edges\"\n\n\nclass DiGraph(GenericGraph):\n    \"\"\"A directed graph.\n\n    .. note::\n\n        In contrast to undirected graphs, the order in which vertices in a given\n        edge are specified is relevant here.\n\n    See also\n    --------\n\n    :class:`.GenericGraph`\n\n    Parameters\n    ----------\n\n    vertices\n        A list of vertices. Must be hashable elements.\n    edges\n        A list of edges, specified as tuples ``(u, v)`` where both ``u``\n        and ``v`` are vertices. The edge is directed from ``u`` to ``v``.\n    labels\n        Controls whether or not vertices are labeled. If ``False`` (the default),\n        the vertices are not labeled; if ``True`` they are labeled using their\n        names (as specified in ``vertices``) via :class:`~.MathTex`. Alternatively,\n        custom labels can be specified by passing a dictionary whose keys are\n        the vertices, and whose values are the corresponding vertex labels\n        (rendered via, e.g., :class:`~.Text` or :class:`~.Tex`).\n    label_fill_color\n        Sets the fill color of the default labels generated when ``labels``\n        is set to ``True``. Has no effect for other values of ``labels``.\n    layout\n        Either one of ``\"spring\"`` (the default), ``\"circular\"``, ``\"kamada_kawai\"``,\n        ``\"planar\"``, ``\"random\"``, ``\"shell\"``, ``\"spectral\"``, ``\"spiral\"``, ``\"tree\"``, and ``\"partite\"``\n        for automatic vertex positioning using ``networkx``\n        (see `their documentation <https://networkx.org/documentation/stable/reference/drawing.html#module-networkx.drawing.layout>`_\n        for more details), or a dictionary specifying a coordinate (value)\n        for each vertex (key) for manual positioning.\n    layout_config\n        Only for automatically generated layouts. A dictionary whose entries\n        are passed as keyword arguments to the automatic layout algorithm\n        specified via ``layout`` of ``networkx``.\n        The ``tree`` layout also accepts a special parameter ``vertex_spacing``\n        passed as a keyword argument inside the ``layout_config`` dictionary.\n        Passing a tuple ``(space_x, space_y)`` as this argument overrides\n        the value of ``layout_scale`` and ensures that vertices are arranged\n        in a way such that the centers of siblings in the same layer are\n        at least ``space_x`` units apart horizontally, and neighboring layers\n        are spaced ``space_y`` units vertically.\n    layout_scale\n        The scale of automatically generated layouts: the vertices will\n        be arranged such that the coordinates are located within the\n        interval ``[-scale, scale]``. Some layouts accept a tuple ``(scale_x, scale_y)``\n        causing the first coordinate to be in the interval ``[-scale_x, scale_x]``,\n        and the second in ``[-scale_y, scale_y]``. Default: 2.\n    vertex_type\n        The mobject class used for displaying vertices in the scene.\n    vertex_config\n        Either a dictionary containing keyword arguments to be passed to\n        the class specified via ``vertex_type``, or a dictionary whose keys\n        are the vertices, and whose values are dictionaries containing keyword\n        arguments for the mobject related to the corresponding vertex.\n    vertex_mobjects\n        A dictionary whose keys are the vertices, and whose values are\n        mobjects to be used as vertices. Passing vertices here overrides\n        all other configuration options for a vertex.\n    edge_type\n        The mobject class used for displaying edges in the scene.\n    edge_config\n        Either a dictionary containing keyword arguments to be passed\n        to the class specified via ``edge_type``, or a dictionary whose\n        keys are the edges, and whose values are dictionaries containing\n        keyword arguments for the mobject related to the corresponding edge.\n        You can further customize the tip by adding a ``tip_config`` dictionary\n        for global styling, or by adding the dict to a specific ``edge_config``.\n\n    Examples\n    --------\n\n    .. manim:: MovingDiGraph\n\n        class MovingDiGraph(Scene):\n            def construct(self):\n                vertices = [1, 2, 3, 4]\n                edges = [(1, 2), (2, 3), (3, 4), (1, 3), (1, 4)]\n\n                g = DiGraph(vertices, edges)\n\n                self.add(g)\n                self.play(\n                    g[1].animate.move_to([1, 1, 1]),\n                    g[2].animate.move_to([-1, 1, 2]),\n                    g[3].animate.move_to([1, -1, -1]),\n                    g[4].animate.move_to([-1, -1, 0]),\n                )\n                self.wait()\n\n    You can customize the edges and arrow tips globally or locally.\n\n    .. manim:: CustomDiGraph\n\n        class CustomDiGraph(Scene):\n            def construct(self):\n                vertices = [i for i in range(5)]\n                edges = [\n                    (0, 1),\n                    (1, 2),\n                    (3, 2),\n                    (3, 4),\n                ]\n\n                edge_config = {\n                    \"stroke_width\": 2,\n                    \"tip_config\": {\n                        \"tip_shape\": ArrowSquareTip,\n                        \"tip_length\": 0.15,\n                    },\n                    (3, 4): {\n                        \"color\": RED,\n                        \"tip_config\": {\"tip_length\": 0.25, \"tip_width\": 0.25}\n                    },\n                }\n\n                g = DiGraph(\n                    vertices,\n                    edges,\n                    labels=True,\n                    layout=\"circular\",\n                    edge_config=edge_config,\n                ).scale(1.4)\n\n                self.play(Create(g))\n                self.wait()\n\n    Since this implementation respects the labels boundary you can also use\n    it for an undirected moving graph with labels.\n\n    .. manim:: UndirectedMovingDiGraph\n\n        class UndirectedMovingDiGraph(Scene):\n            def construct(self):\n                vertices = [i for i in range(5)]\n                edges = [\n                    (0, 1),\n                    (1, 2),\n                    (3, 2),\n                    (3, 4),\n                ]\n\n                edge_config = {\n                    \"stroke_width\": 2,\n                    \"tip_config\": {\"tip_length\": 0, \"tip_width\": 0},\n                    (3, 4): {\"color\": RED},\n                }\n\n                g = DiGraph(\n                    vertices,\n                    edges,\n                    labels=True,\n                    layout=\"circular\",\n                    edge_config=edge_config,\n                ).scale(1.4)\n\n                self.play(Create(g))\n                self.wait()\n\n                self.play(\n                    g[1].animate.move_to([1, 1, 1]),\n                    g[2].animate.move_to([-1, 1, 2]),\n                    g[3].animate.move_to([-1.5, -1.5, -1]),\n                    g[4].animate.move_to([1, -2, -1]),\n                )\n                self.wait()\n\n    \"\"\"\n\n    @staticmethod\n    def _empty_networkx_graph() -> nx.DiGraph:\n        return nx.DiGraph()\n\n    def _populate_edge_dict(\n        self, edges: list[tuple[Hashable, Hashable]], edge_type: type[Mobject]\n    ):\n        self.edges = {\n            (u, v): edge_type(\n                start=self[u],\n                end=self[v],\n                z_index=-1,\n                **self._edge_config[(u, v)],\n            )\n            for (u, v) in edges\n        }\n\n        for (u, v), edge in self.edges.items():\n            edge.add_tip(**self._tip_config[(u, v)])\n\n    def update_edges(self, graph):\n        \"\"\"Updates the edges to stick at their corresponding vertices.\n\n        Arrow tips need to be repositioned since otherwise they can be\n        deformed.\n        \"\"\"\n        for (u, v), edge in graph.edges.items():\n            tip = edge.pop_tips()[0]\n            # Passing the Mobject instead of the vertex makes the tip\n            # stop on the bounding box of the vertex.\n            edge.set_points_by_ends(\n                graph[u],\n                graph[v],\n                buff=self._edge_config.get(\"buff\", 0),\n                path_arc=self._edge_config.get(\"path_arc\", 0),\n            )\n            edge.add_tip(tip)\n\n    def __repr__(self: DiGraph) -> str:\n        return f\"Directed graph on {len(self.vertices)} vertices and {len(self.edges)} edges\"\n"
  },
  {
    "path": "manim/mobject/graphing/__init__.py",
    "content": "\"\"\"Coordinate systems and function graphing related mobjects.\n\nModules\n=======\n\n.. autosummary::\n    :toctree: ../reference\n\n    ~coordinate_systems\n    ~functions\n    ~number_line\n    ~probability\n    ~scale\n\"\"\"\n"
  },
  {
    "path": "manim/mobject/graphing/coordinate_systems.py",
    "content": "\"\"\"Mobjects that represent coordinate systems.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"CoordinateSystem\",\n    \"Axes\",\n    \"ThreeDAxes\",\n    \"NumberPlane\",\n    \"PolarPlane\",\n    \"ComplexPlane\",\n]\n\nimport fractions as fr\nimport numbers\nfrom collections.abc import Callable, Iterable, Sequence\nfrom typing import TYPE_CHECKING, Any, Self, TypeVar, overload\n\nimport numpy as np\n\nfrom manim import config\nfrom manim.constants import *\nfrom manim.mobject.geometry.arc import Circle, Dot\nfrom manim.mobject.geometry.line import Arrow, DashedLine, Line\nfrom manim.mobject.geometry.polygram import Polygon, Rectangle, RegularPolygon\nfrom manim.mobject.graphing.functions import ImplicitFunction, ParametricFunction\nfrom manim.mobject.graphing.number_line import NumberLine\nfrom manim.mobject.graphing.scale import LinearBase\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.opengl.opengl_surface import OpenGLSurface\nfrom manim.mobject.text.tex_mobject import MathTex\nfrom manim.mobject.three_d.three_dimensions import Surface\nfrom manim.mobject.types.vectorized_mobject import (\n    VDict,\n    VectorizedPoint,\n    VGroup,\n    VMobject,\n)\nfrom manim.utils.color import (\n    BLACK,\n    BLUE,\n    BLUE_D,\n    GREEN,\n    PURE_YELLOW,\n    WHITE,\n    ManimColor,\n    ParsableManimColor,\n    color_gradient,\n    interpolate_color,\n    invert_color,\n)\nfrom manim.utils.config_ops import merge_dicts_recursively, update_dict_recursively\nfrom manim.utils.simple_functions import binary_search\nfrom manim.utils.space_ops import angle_of_vector\n\nif TYPE_CHECKING:\n    from manim.mobject.mobject import Mobject\n    from manim.typing import (\n        ManimFloat,\n        Point2D,\n        Point2DLike,\n        Point3D,\n        Point3DLike,\n        Vector3D,\n        Vector3DLike,\n    )\n\n    LineType = TypeVar(\"LineType\", bound=Line)\n\n\nclass CoordinateSystem:\n    r\"\"\"Abstract base class for Axes and NumberPlane.\n\n    Examples\n    --------\n    .. manim:: CoordSysExample\n        :save_last_frame:\n\n        class CoordSysExample(Scene):\n            def construct(self):\n                # the location of the ticks depends on the x_range and y_range.\n                grid = Axes(\n                    x_range=[0, 1, 0.05],  # step size determines num_decimal_places.\n                    y_range=[0, 1, 0.05],\n                    x_length=9,\n                    y_length=5.5,\n                    axis_config={\n                        \"numbers_to_include\": np.arange(0, 1 + 0.1, 0.1),\n                        \"font_size\": 24,\n                    },\n                    tips=False,\n                )\n\n                # Labels for the x-axis and y-axis.\n                y_label = grid.get_y_axis_label(\"y\", edge=LEFT, direction=LEFT, buff=0.4)\n                x_label = grid.get_x_axis_label(\"x\")\n                grid_labels = VGroup(x_label, y_label)\n\n                graphs = VGroup()\n                for n in np.arange(1, 20 + 0.5, 0.5):\n                    graphs += grid.plot(lambda x: x ** n, color=WHITE)\n                    graphs += grid.plot(\n                        lambda x: x ** (1 / n), color=WHITE, use_smoothing=False\n                    )\n\n                # Extra lines and labels for point (1,1)\n                graphs += grid.get_horizontal_line(grid @ (1, 1, 0), color=BLUE)\n                graphs += grid.get_vertical_line(grid @ (1, 1, 0), color=BLUE)\n                graphs += Dot(point=grid @ (1, 1, 0), color=YELLOW)\n                graphs += Tex(\"(1,1)\").scale(0.75).next_to(grid @ (1, 1, 0))\n                title = Title(\n                    # spaces between braces to prevent SyntaxError\n                    r\"Graphs of $y=x^{ {1}\\over{n} }$ and $y=x^n (n=1,2,3,...,20)$\",\n                    include_underline=False,\n                    font_size=40,\n                )\n\n                self.add(title, graphs, grid, grid_labels)\n    \"\"\"\n\n    def __init__(\n        self,\n        x_range: Sequence[float] | None = None,\n        y_range: Sequence[float] | None = None,\n        x_length: float | None = None,\n        y_length: float | None = None,\n        dimension: int = 2,\n    ):\n        self.dimension = dimension\n\n        default_step = 1\n        if x_range is None:\n            x_range = [\n                round(-config[\"frame_x_radius\"]),\n                round(config[\"frame_x_radius\"]),\n                default_step,\n            ]\n        elif len(x_range) == 2:\n            x_range = [*x_range, default_step]\n\n        if y_range is None:\n            y_range = [\n                round(-config[\"frame_y_radius\"]),\n                round(config[\"frame_y_radius\"]),\n                default_step,\n            ]\n        elif len(y_range) == 2:\n            y_range = [*y_range, default_step]\n\n        self.x_range = x_range\n        self.y_range = y_range\n        self.x_length = x_length\n        self.y_length = y_length\n        self.num_sampled_graph_points_per_tick = 10\n        self.x_axis: NumberLine\n\n    def coords_to_point(self, *coords: ManimFloat) -> Point3D:\n        # TODO: I think the method should be able to return more than just a single point.\n        # E.g. see the implementation of it on line 2065.\n        raise NotImplementedError()\n\n    def point_to_coords(self, point: Point3DLike) -> list[ManimFloat]:\n        raise NotImplementedError()\n\n    def polar_to_point(self, radius: float, azimuth: float) -> Point2D:\n        r\"\"\"Gets a point from polar coordinates.\n\n        Parameters\n        ----------\n        radius\n            The coordinate radius (:math:`r`).\n\n        azimuth\n            The coordinate azimuth (:math:`\\theta`).\n\n        Returns\n        -------\n        numpy.ndarray\n            The point.\n\n        Examples\n        --------\n        .. manim:: PolarToPointExample\n            :ref_classes: PolarPlane Vector\n            :save_last_frame:\n\n            class PolarToPointExample(Scene):\n                def construct(self):\n                    polarplane_pi = PolarPlane(azimuth_units=\"PI radians\", size=6)\n                    polartopoint_vector = Vector(polarplane_pi.polar_to_point(3, PI/4))\n                    self.add(polarplane_pi)\n                    self.add(polartopoint_vector)\n        \"\"\"\n        return self.coords_to_point(radius * np.cos(azimuth), radius * np.sin(azimuth))\n\n    def point_to_polar(self, point: Point2DLike) -> Point2D:\n        r\"\"\"Gets polar coordinates from a point.\n\n        Parameters\n        ----------\n        point\n            The point.\n\n        Returns\n        -------\n        Point2D\n            The coordinate radius (:math:`r`) and the coordinate azimuth (:math:`\\theta`).\n        \"\"\"\n        x, y = self.point_to_coords(point)\n        return np.sqrt(x**2 + y**2), np.arctan2(y, x)\n\n    def c2p(\n        self, *coords: float | Sequence[float] | Sequence[Sequence[float]] | np.ndarray\n    ) -> np.ndarray:\n        \"\"\"Abbreviation for :meth:`coords_to_point`\"\"\"\n        return self.coords_to_point(*coords)\n\n    def p2c(self, point: Point3DLike) -> list[ManimFloat]:\n        \"\"\"Abbreviation for :meth:`point_to_coords`\"\"\"\n        return self.point_to_coords(point)\n\n    def pr2pt(self, radius: float, azimuth: float) -> np.ndarray:\n        \"\"\"Abbreviation for :meth:`polar_to_point`\"\"\"\n        return self.polar_to_point(radius, azimuth)\n\n    def pt2pr(self, point: np.ndarray) -> Point2D:\n        \"\"\"Abbreviation for :meth:`point_to_polar`\"\"\"\n        return self.point_to_polar(point)\n\n    def get_axes(self) -> VGroup:\n        raise NotImplementedError()\n\n    def get_axis(self, index: int) -> NumberLine:\n        val: NumberLine = self.get_axes()[index]\n        return val\n\n    def get_origin(self) -> Point3D:\n        \"\"\"Gets the origin of :class:`~.Axes`.\n\n        Returns\n        -------\n        np.ndarray\n            The center point.\n        \"\"\"\n        return self.coords_to_point(0, 0)\n\n    def get_x_axis(self) -> NumberLine:\n        return self.get_axis(0)\n\n    def get_y_axis(self) -> NumberLine:\n        return self.get_axis(1)\n\n    def get_z_axis(self) -> NumberLine:\n        return self.get_axis(2)\n\n    def get_x_unit_size(self) -> float:\n        return self.get_x_axis().get_unit_size()\n\n    def get_y_unit_size(self) -> float:\n        return self.get_y_axis().get_unit_size()\n\n    def get_x_axis_label(\n        self,\n        label: float | str | VMobject,\n        edge: Vector3D = UR,\n        direction: Vector3D = UR,\n        buff: float = SMALL_BUFF,\n        **kwargs: Any,\n    ) -> Mobject:\n        \"\"\"Generate an x-axis label.\n\n        Parameters\n        ----------\n        label\n            The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        edge\n            The edge of the x-axis to which the label will be added, by default ``UR``.\n        direction\n            Allows for further positioning of the label from an edge, by default ``UR``.\n        buff\n            The distance of the label from the line.\n\n        Returns\n        -------\n        :class:`~.Mobject`\n            The positioned label.\n\n        Examples\n        --------\n        .. manim:: GetXAxisLabelExample\n            :save_last_frame:\n\n            class GetXAxisLabelExample(Scene):\n                def construct(self):\n                    ax = Axes(x_range=(0, 8), y_range=(0, 5), x_length=8, y_length=5)\n                    x_label = ax.get_x_axis_label(\n                        Tex(\"$x$-values\").scale(0.65), edge=DOWN, direction=DOWN, buff=0.5\n                    )\n                    self.add(ax, x_label)\n        \"\"\"\n        return self._get_axis_label(\n            label, self.get_x_axis(), edge, direction, buff=buff, **kwargs\n        )\n\n    def get_y_axis_label(\n        self,\n        label: float | str | VMobject,\n        edge: Vector3D = UR,\n        direction: Vector3D = UP * 0.5 + RIGHT,\n        buff: float = SMALL_BUFF,\n        **kwargs: Any,\n    ) -> Mobject:\n        \"\"\"Generate a y-axis label.\n\n        Parameters\n        ----------\n        label\n            The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        edge\n            The edge of the y-axis to which the label will be added, by default ``UR``.\n        direction\n            Allows for further positioning of the label from an edge, by default ``UR``\n        buff\n            The distance of the label from the line.\n\n        Returns\n        -------\n        :class:`~.Mobject`\n            The positioned label.\n\n        Examples\n        --------\n        .. manim:: GetYAxisLabelExample\n            :save_last_frame:\n\n            class GetYAxisLabelExample(Scene):\n                def construct(self):\n                    ax = Axes(x_range=(0, 8), y_range=(0, 5), x_length=8, y_length=5)\n                    y_label = ax.get_y_axis_label(\n                        Tex(\"$y$-values\").scale(0.65).rotate(90 * DEGREES),\n                        edge=LEFT,\n                        direction=LEFT,\n                        buff=0.3,\n                    )\n                    self.add(ax, y_label)\n        \"\"\"\n        return self._get_axis_label(\n            label, self.get_y_axis(), edge, direction, buff=buff, **kwargs\n        )\n\n    def _get_axis_label(\n        self,\n        label: float | str | VMobject,\n        axis: Mobject,\n        edge: Vector3DLike,\n        direction: Vector3DLike,\n        buff: float = SMALL_BUFF,\n    ) -> Mobject:\n        \"\"\"Gets the label for an axis.\n\n        Parameters\n        ----------\n        label\n            The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        axis\n            The axis to which the label will be added.\n        edge\n            The edge of the axes to which the label will be added. ``RIGHT`` adds to the right side of the axis\n        direction\n            Allows for further positioning of the label.\n        buff\n            The distance of the label from the line.\n\n        Returns\n        -------\n        :class:`~.Mobject`\n            The positioned label along the given axis.\n        \"\"\"\n        label_mobject: Mobject = self.x_axis._create_label_tex(label)\n        label_mobject.next_to(\n            axis.get_edge_center(edge), direction=direction, buff=buff\n        )\n        label_mobject.shift_onto_screen(buff=MED_SMALL_BUFF)\n        return label_mobject\n\n    def get_axis_labels(self) -> VGroup:\n        raise NotImplementedError()\n\n    def add_coordinates(\n        self,\n        *axes_numbers: Iterable[float] | None | dict[float, str | float | Mobject],\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Adds labels to the axes. Use ``Axes.coordinate_labels`` to\n        access the coordinates after creation.\n\n        Parameters\n        ----------\n        axes_numbers\n            The numbers to be added to the axes. Use ``None`` to represent an axis with default labels.\n\n        Examples\n        --------\n        .. code-block:: python\n\n            ax = ThreeDAxes()\n            x_labels = range(-4, 5)\n            z_labels = range(-4, 4, 2)\n            ax.add_coordinates(\n                x_labels, None, z_labels\n            )  # default y labels, custom x & z labels\n            ax.add_coordinates(x_labels)  # only x labels\n\n        You can also specifically control the position and value of the labels using a dict.\n\n        .. code-block:: python\n\n            ax = Axes(x_range=[0, 7])\n            x_pos = [x for x in range(1, 8)]\n\n            # strings are automatically converted into a Tex mobject.\n            x_vals = [\n                \"Monday\",\n                \"Tuesday\",\n                \"Wednesday\",\n                \"Thursday\",\n                \"Friday\",\n                \"Saturday\",\n                \"Sunday\",\n            ]\n            x_dict = dict(zip(x_pos, x_vals))\n            ax.add_coordinates(x_dict)\n        \"\"\"\n        self.coordinate_labels = VGroup()\n        # if nothing is passed to axes_numbers, produce axes with default labelling\n        if not axes_numbers:\n            axes_numbers = [None for _ in range(self.dimension)]\n\n        for axis, values in zip(self.axes, axes_numbers, strict=False):\n            if isinstance(values, dict):\n                axis.add_labels(values, **kwargs)\n                labels = axis.labels\n            elif values is None and axis.scaling.custom_labels:\n                tick_range = axis.get_tick_range()\n                axis.add_labels(\n                    dict(\n                        zip(\n                            tick_range,\n                            axis.scaling.get_custom_labels(tick_range),\n                            strict=True,\n                        )\n                    )\n                )\n                labels = axis.labels\n            else:\n                axis.add_numbers(values, **kwargs)\n                labels = axis.numbers\n            self.coordinate_labels.add(labels)\n\n        return self\n\n    # overload necessary until https://github.com/python/mypy/issues/3737 is supported\n    @overload\n    def get_line_from_axis_to_point(\n        self,\n        index: int,\n        point: Point3DLike,\n        line_config: dict | None = ...,\n        color: ParsableManimColor | None = ...,\n        stroke_width: float = ...,\n    ) -> DashedLine: ...\n\n    @overload\n    def get_line_from_axis_to_point(\n        self,\n        index: int,\n        point: Point3DLike,\n        line_func: type[LineType],\n        line_config: dict | None = ...,\n        color: ParsableManimColor | None = ...,\n        stroke_width: float = ...,\n    ) -> LineType: ...\n\n    def get_line_from_axis_to_point(  # type: ignore[no-untyped-def]\n        self,\n        index,\n        point,\n        line_func=DashedLine,\n        line_config=None,\n        color=None,\n        stroke_width=2,\n    ):\n        \"\"\"Returns a straight line from a given axis to a point in the scene.\n\n        Parameters\n        ----------\n        index\n            Specifies the axis from which to draw the line. `0 = x_axis`, `1 = y_axis`\n        point\n            The point to which the line will be drawn.\n        line_func\n            The function of the :class:`~.Line` mobject used to construct the line.\n        line_config\n            Optional arguments to passed to :attr:`line_func`.\n        color\n            The color of the line.\n        stroke_width\n            The stroke width of the line.\n\n        Returns\n        -------\n        :class:`~.Line`\n            The line from an axis to a point.\n\n\n        .. seealso::\n            :meth:`~.CoordinateSystem.get_vertical_line`\n            :meth:`~.CoordinateSystem.get_horizontal_line`\n        \"\"\"\n        line_config = line_config if line_config is not None else {}\n\n        if color is None:\n            color = VMobject().color\n\n        line_config[\"color\"] = ManimColor.parse(color)\n        line_config[\"stroke_width\"] = stroke_width\n\n        axis = self.get_axis(index)\n        line = line_func(axis.get_projection(point), point, **line_config)\n        return line\n\n    def get_vertical_line(self, point: Point3DLike, **kwargs: Any) -> Line:\n        \"\"\"A vertical line from the x-axis to a given point in the scene.\n\n        Parameters\n        ----------\n        point\n            The point to which the vertical line will be drawn.\n        kwargs\n            Additional parameters to be passed to :class:`get_line_from_axis_to_point`.\n\n        Returns\n        -------\n        :class:`Line`\n            A vertical line from the x-axis to the point.\n\n        Examples\n        --------\n        .. manim:: GetVerticalLineExample\n            :save_last_frame:\n\n            class GetVerticalLineExample(Scene):\n                def construct(self):\n                    ax = Axes().add_coordinates()\n                    point = ax.coords_to_point(-3.5, 2)\n\n                    dot = Dot(point)\n                    line = ax.get_vertical_line(point, line_config={\"dashed_ratio\": 0.85})\n\n                    self.add(ax, line, dot)\n\n\n        \"\"\"\n        return self.get_line_from_axis_to_point(0, point, **kwargs)\n\n    def get_horizontal_line(self, point: Point3DLike, **kwargs: Any) -> Line:\n        \"\"\"A horizontal line from the y-axis to a given point in the scene.\n\n        Parameters\n        ----------\n        point\n            The point to which the horizontal line will be drawn.\n        kwargs\n            Additional parameters to be passed to :class:`get_line_from_axis_to_point`.\n\n        Returns\n        -------\n        :class:`Line`\n            A horizontal line from the y-axis to the point.\n\n        Examples\n        --------\n        .. manim:: GetHorizontalLineExample\n            :save_last_frame:\n\n            class GetHorizontalLineExample(Scene):\n                def construct(self):\n                    ax = Axes().add_coordinates()\n                    point = ax @ (-4, 1.5)\n\n                    dot = Dot(point)\n                    line = ax.get_horizontal_line(point, line_func=Line)\n\n                    self.add(ax, line, dot)\n        \"\"\"\n        return self.get_line_from_axis_to_point(1, point, **kwargs)\n\n    def get_lines_to_point(self, point: Point3DLike, **kwargs: Any) -> VGroup:\n        \"\"\"Generate both horizontal and vertical lines from the axis to a point.\n\n        Parameters\n        ----------\n        point\n            A point on the scene.\n        kwargs\n            Additional parameters to be passed to :meth:`get_line_from_axis_to_point`\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            A :class:`~.VGroup` of the horizontal and vertical lines.\n\n\n        .. seealso::\n            :meth:`~.CoordinateSystem.get_vertical_line`\n            :meth:`~.CoordinateSystem.get_horizontal_line`\n\n        Examples\n        --------\n        .. manim:: GetLinesToPointExample\n            :save_last_frame:\n\n            class GetLinesToPointExample(Scene):\n                def construct(self):\n                    ax = Axes()\n                    circ = Circle(radius=0.5).move_to([-4, -1.5, 0])\n\n                    lines_1 = ax.get_lines_to_point(circ.get_right(), color=GREEN_B)\n                    lines_2 = ax.get_lines_to_point(circ.get_corner(DL), color=BLUE_B)\n                    self.add(ax, lines_1, lines_2, circ)\n        \"\"\"\n        return VGroup(\n            self.get_horizontal_line(point, **kwargs),\n            self.get_vertical_line(point, **kwargs),\n        )\n\n    # graphing\n\n    def plot(\n        self,\n        function: Callable[[float], float],\n        x_range: Sequence[float] | None = None,\n        use_vectorized: bool = False,\n        colorscale: Iterable[ParsableManimColor]\n        | Iterable[ParsableManimColor, float]\n        | None = None,\n        colorscale_axis: int = 1,\n        **kwargs: Any,\n    ) -> ParametricFunction:\n        \"\"\"Generates a curve based on a function.\n\n        Parameters\n        ----------\n        function\n            The function used to construct the :class:`~.ParametricFunction`.\n        x_range\n            The range of the curve along the axes. ``x_range = [x_min, x_max, x_step]``.\n        use_vectorized\n            Whether to pass in the generated t value array to the function. Only use this if your function supports it.\n            Output should be a numpy array of shape ``[y_0, y_1, ...]``\n        colorscale\n            Colors of the function. Optional parameter used when coloring a function by values. Passing a list of colors\n            and a colorscale_axis will color the function by y-value. Passing a list of tuples in the form ``(color, pivot)``\n            allows user-defined pivots where the color transitions.\n        colorscale_axis\n            Defines the axis on which the colorscale is applied (0 = x, 1 = y), default is y-axis (1).\n        kwargs\n            Additional parameters to be passed to :class:`~.ParametricFunction`.\n\n        Returns\n        -------\n        :class:`~.ParametricFunction`\n            The plotted curve.\n\n\n        .. warning::\n            This method may not produce accurate graphs since Manim currently relies on interpolation between\n            evenly-spaced samples of the curve, instead of intelligent plotting.\n            See the example below for some solutions to this problem.\n\n        Examples\n        --------\n        .. manim:: PlotExample\n            :save_last_frame:\n\n            class PlotExample(Scene):\n                def construct(self):\n                    # construct the axes\n                    ax_1 = Axes(\n                        x_range=[0.001, 6],\n                        y_range=[-8, 2],\n                        x_length=5,\n                        y_length=3,\n                        tips=False,\n                    )\n                    ax_2 = ax_1.copy()\n                    ax_3 = ax_1.copy()\n\n                    # position the axes\n                    ax_1.to_corner(UL)\n                    ax_2.to_corner(UR)\n                    ax_3.to_edge(DOWN)\n                    axes = VGroup(ax_1, ax_2, ax_3)\n\n                    # create the logarithmic curves\n                    def log_func(x):\n                        return np.log(x)\n\n                    # a curve without adjustments; poor interpolation.\n                    curve_1 = ax_1.plot(log_func, color=PURE_RED)\n\n                    # disabling interpolation makes the graph look choppy as not enough\n                    # inputs are available\n                    curve_2 = ax_2.plot(log_func, use_smoothing=False, color=ORANGE)\n\n                    # taking more inputs of the curve by specifying a step for the\n                    # x_range yields expected results, but increases rendering time.\n                    curve_3 = ax_3.plot(\n                        log_func, x_range=(0.001, 6, 0.001), color=PURE_GREEN\n                    )\n\n                    curves = VGroup(curve_1, curve_2, curve_3)\n\n                    self.add(axes, curves)\n        \"\"\"\n        t_range = np.array(self.x_range, dtype=float)\n        if x_range is not None:\n            t_range[: len(x_range)] = x_range\n\n        if x_range is None or len(x_range) < 3:\n            # if t_range has a defined step size, increase the number of sample points per tick\n            t_range[2] /= self.num_sampled_graph_points_per_tick\n        # For axes, the third coordinate of x_range indicates\n        # tick frequency.  But for functions, it indicates a\n        # sample frequency\n\n        graph = ParametricFunction(\n            lambda t: self.coords_to_point(t, function(t)),\n            t_range=t_range,\n            scaling=self.x_axis.scaling,\n            use_vectorized=use_vectorized,\n            **kwargs,\n        )\n\n        graph.underlying_function = function\n\n        if colorscale:\n            if type(colorscale[0]) in (list, tuple):\n                new_colors, pivots = [\n                    [i for i, j in colorscale],\n                    [j for i, j in colorscale],\n                ]\n            else:\n                new_colors = colorscale\n\n                ranges = [self.x_range, self.y_range]\n                pivot_min = ranges[colorscale_axis][0]\n                pivot_max = ranges[colorscale_axis][1]\n                pivot_frequency = (pivot_max - pivot_min) / (len(new_colors) - 1)\n                pivots = np.arange(\n                    start=pivot_min,\n                    stop=pivot_max + pivot_frequency,\n                    step=pivot_frequency,\n                )\n\n            resolution = 0.01 if len(x_range) == 2 else x_range[2]\n            sample_points = np.arange(x_range[0], x_range[1] + resolution, resolution)\n            color_list = []\n            for samp_x in sample_points:\n                axis_value = (samp_x, function(samp_x))[colorscale_axis]\n                if axis_value <= pivots[0]:\n                    color_list.append(new_colors[0])\n                elif axis_value >= pivots[-1]:\n                    color_list.append(new_colors[-1])\n                else:\n                    for i, pivot in enumerate(pivots):\n                        if pivot > axis_value:\n                            color_index = (axis_value - pivots[i - 1]) / (\n                                pivots[i] - pivots[i - 1]\n                            )\n                            color_index = min(color_index, 1)\n                            mob_color = interpolate_color(\n                                new_colors[i - 1],\n                                new_colors[i],\n                                color_index,\n                            )\n                            color_list.append(mob_color)\n                            break\n            if config.renderer == RendererType.OPENGL:\n                graph.set_color(color_list)\n            else:\n                graph.set_stroke(color_list)\n                graph.set_sheen_direction(RIGHT)\n\n        return graph\n\n    def plot_implicit_curve(\n        self,\n        func: Callable[[float, float], float],\n        min_depth: int = 5,\n        max_quads: int = 1500,\n        **kwargs: Any,\n    ) -> ImplicitFunction:\n        \"\"\"Creates the curves of an implicit function.\n\n        Parameters\n        ----------\n        func\n            The function to graph, in the form of f(x, y) = 0.\n        min_depth\n            The minimum depth of the function to calculate.\n        max_quads\n            The maximum number of quads to use.\n        kwargs\n            Additional parameters to pass into :class:`ImplicitFunction`.\n\n        Examples\n        --------\n        .. manim:: ImplicitExample\n            :save_last_frame:\n\n            class ImplicitExample(Scene):\n                def construct(self):\n                    ax = Axes()\n                    a = ax.plot_implicit_curve(\n                        lambda x, y: y * (x - y) ** 2 - 4 * x - 8, color=BLUE\n                    )\n                    self.add(ax, a)\n        \"\"\"\n        x_scale = self.get_x_axis().scaling\n        y_scale = self.get_y_axis().scaling\n        graph = ImplicitFunction(\n            func=(lambda x, y: func(x_scale.function(x), y_scale.function(y))),\n            x_range=self.x_range[:2],\n            y_range=self.y_range[:2],\n            min_depth=min_depth,\n            max_quads=max_quads,\n            **kwargs,\n        )\n        (\n            graph.stretch(self.get_x_unit_size(), 0, about_point=ORIGIN)\n            .stretch(self.get_y_unit_size(), 1, about_point=ORIGIN)\n            .shift(self.get_origin())\n        )\n        return graph\n\n    def plot_parametric_curve(\n        self,\n        function: Callable[[float], np.ndarray],\n        use_vectorized: bool = False,\n        **kwargs: Any,\n    ) -> ParametricFunction:\n        \"\"\"A parametric curve.\n\n        Parameters\n        ----------\n        function\n            A parametric function mapping a number to a point in the\n            coordinate system.\n        use_vectorized\n            Whether to pass in the generated t value array to the function. Only use this if your function supports it.\n        kwargs\n            Any further keyword arguments are passed to :class:`.ParametricFunction`.\n\n        Example\n        -------\n        .. manim:: ParametricCurveExample\n            :save_last_frame:\n\n            class ParametricCurveExample(Scene):\n                def construct(self):\n                    ax = Axes()\n                    cardioid = ax.plot_parametric_curve(\n                        lambda t: np.array(\n                            [\n                                np.exp(1) * np.cos(t) * (1 - np.cos(t)),\n                                np.exp(1) * np.sin(t) * (1 - np.cos(t)),\n                                0,\n                            ]\n                        ),\n                        t_range=[0, 2 * PI],\n                        color=\"#0FF1CE\",\n                    )\n                    self.add(ax, cardioid)\n        \"\"\"\n        dim = self.dimension\n        graph = ParametricFunction(\n            lambda t: self.coords_to_point(*function(t)[:dim]),\n            use_vectorized=use_vectorized,\n            **kwargs,\n        )\n        graph.underlying_function = function\n        return graph\n\n    def plot_polar_graph(\n        self,\n        r_func: Callable[[float], float],\n        theta_range: Sequence[float] | None = None,\n        **kwargs: Any,\n    ) -> ParametricFunction:\n        \"\"\"A polar graph.\n\n        Parameters\n        ----------\n        r_func\n            The function r of theta.\n        theta_range\n            The range of theta as ``theta_range = [theta_min, theta_max, theta_step]``.\n        kwargs\n            Additional parameters passed to :class:`~.ParametricFunction`.\n\n        Examples\n        --------\n        .. manim:: PolarGraphExample\n            :ref_classes: PolarPlane\n            :save_last_frame:\n\n            class PolarGraphExample(Scene):\n                def construct(self):\n                    plane = PolarPlane()\n                    r = lambda theta: 2 * np.sin(theta * 5)\n                    graph = plane.plot_polar_graph(r, [0, 2 * PI], color=ORANGE)\n                    self.add(plane, graph)\n        \"\"\"\n        theta_range = theta_range if theta_range is not None else [0, 2 * PI]\n        graph = ParametricFunction(\n            function=lambda th: self.pr2pt(r_func(th), th),\n            t_range=theta_range,\n            **kwargs,\n        )\n        graph.underlying_function = r_func\n        return graph\n\n    def plot_surface(\n        self,\n        function: Callable[[float], float],\n        u_range: Sequence[float] | None = None,\n        v_range: Sequence[float] | None = None,\n        colorscale: (\n            Sequence[ParsableManimColor]\n            | Sequence[tuple[ParsableManimColor, float]]\n            | None\n        ) = None,\n        colorscale_axis: int = 2,\n        **kwargs: Any,\n    ) -> Surface | OpenGLSurface:\n        \"\"\"Generates a surface based on a function.\n\n        Parameters\n        ----------\n        function\n            The function used to construct the :class:`~.Surface`.\n        u_range\n            The range of the ``u`` variable: ``(u_min, u_max)``.\n        v_range\n            The range of the ``v`` variable: ``(v_min, v_max)``.\n        colorscale\n            Colors of the surface. Passing a list of colors will color the surface by z-value.\n            Passing a list of tuples in the form ``(color, pivot)`` allows user-defined pivots\n            where the color transitions.\n        colorscale_axis\n            Defines the axis on which the colorscale is applied (0 = x, 1 = y, 2 = z), default\n            is z-axis (2).\n        kwargs\n            Additional parameters to be passed to :class:`~.Surface`.\n\n        Returns\n        -------\n        :class:`~.Surface`\n            The plotted surface.\n\n        Examples\n        --------\n        .. manim:: PlotSurfaceExample\n            :save_last_frame:\n\n            class PlotSurfaceExample(ThreeDScene):\n                def construct(self):\n                    resolution_fa = 16\n                    self.set_camera_orientation(phi=75 * DEGREES, theta=-60 * DEGREES)\n                    axes = ThreeDAxes(x_range=(-3, 3, 1), y_range=(-3, 3, 1), z_range=(-5, 5, 1))\n                    def param_trig(u, v):\n                        x = u\n                        y = v\n                        z = 2 * np.sin(x) + 2 * np.cos(y)\n                        return z\n                    trig_plane = axes.plot_surface(\n                        param_trig,\n                        resolution=(resolution_fa, resolution_fa),\n                        u_range = (-3, 3),\n                        v_range = (-3, 3),\n                        colorscale = [BLUE, GREEN, YELLOW, ORANGE, RED],\n                        )\n                    self.add(axes, trig_plane)\n        \"\"\"\n        if config.renderer == RendererType.CAIRO:\n            surface = Surface(\n                lambda u, v: self.c2p(u, v, function(u, v)),\n                u_range=u_range,\n                v_range=v_range,\n                **kwargs,\n            )\n            if colorscale:\n                surface.set_fill_by_value(\n                    axes=self.copy(),\n                    colorscale=colorscale,\n                    axis=colorscale_axis,\n                )\n        elif config.renderer == RendererType.OPENGL:\n            surface = OpenGLSurface(\n                lambda u, v: self.c2p(u, v, function(u, v)),\n                u_range=u_range,\n                v_range=v_range,\n                axes=self.copy(),\n                colorscale=colorscale,\n                colorscale_axis=colorscale_axis,\n                **kwargs,\n            )\n\n        return surface\n\n    def input_to_graph_point(\n        self,\n        x: float,\n        graph: ParametricFunction | VMobject,\n    ) -> Point3D:\n        \"\"\"Returns the coordinates of the point on a ``graph`` corresponding to an ``x`` value.\n\n        Parameters\n        ----------\n        x\n            The x-value of a point on the ``graph``.\n        graph\n            The :class:`~.ParametricFunction` on which the point lies.\n\n        Returns\n        -------\n        :class:`np.ndarray`\n            The coordinates of the point on the :attr:`graph` corresponding to the :attr:`x` value.\n\n        Raises\n        ------\n        :exc:`ValueError`\n            When the target x is not in the range of the line graph.\n\n        Examples\n        --------\n        .. manim:: InputToGraphPointExample\n            :save_last_frame:\n\n            class InputToGraphPointExample(Scene):\n                def construct(self):\n                    ax = Axes()\n                    curve = ax.plot(lambda x : np.cos(x))\n\n                    # move a square to PI on the cosine curve.\n                    position = ax.input_to_graph_point(x=PI, graph=curve)\n                    sq = Square(side_length=1, color=YELLOW).move_to(position)\n\n                    self.add(ax, curve, sq)\n        \"\"\"\n        if hasattr(graph, \"underlying_function\"):\n            return graph.function(x)\n        else:\n            alpha = binary_search(\n                function=lambda a: self.point_to_coords(graph.point_from_proportion(a))[\n                    0\n                ],\n                target=x,\n                lower_bound=0,\n                upper_bound=1,\n            )\n            if alpha is not None:\n                return graph.point_from_proportion(alpha)\n            else:\n                raise ValueError(\n                    f\"x={x} not located in the range of the graph ([{self.p2c(graph.get_start())[0]}, {self.p2c(graph.get_end())[0]}])\",\n                )\n\n    def input_to_graph_coords(\n        self, x: float, graph: ParametricFunction\n    ) -> tuple[float, float]:\n        \"\"\"Returns a tuple of the axis relative coordinates of the point\n        on the graph based on the x-value given.\n\n        Examples\n        --------\n        .. code-block:: pycon\n\n            >>> from manim import Axes\n            >>> ax = Axes()\n            >>> parabola = ax.plot(lambda x: x**2)\n            >>> ax.input_to_graph_coords(x=3, graph=parabola)\n            (3, 9)\n        \"\"\"\n        return x, graph.underlying_function(x)\n\n    def i2gc(self, x: float, graph: ParametricFunction) -> tuple[float, float]:\n        \"\"\"Alias for :meth:`input_to_graph_coords`.\"\"\"\n        return self.input_to_graph_coords(x, graph)\n\n    def i2gp(self, x: float, graph: ParametricFunction) -> np.ndarray:\n        \"\"\"Alias for :meth:`input_to_graph_point`.\"\"\"\n        return self.input_to_graph_point(x, graph)\n\n    def get_graph_label(\n        self,\n        graph: ParametricFunction,\n        label: float | str | VMobject = \"f(x)\",\n        x_val: float | None = None,\n        direction: Sequence[float] = RIGHT,\n        buff: float = MED_SMALL_BUFF,\n        color: ParsableManimColor | None = None,\n        dot: bool = False,\n        dot_config: dict[str, Any] | None = None,\n    ) -> Mobject:\n        r\"\"\"Creates a properly positioned label for the passed graph, with an optional dot.\n\n        Parameters\n        ----------\n        graph\n            The curve.\n        label\n            The label for the function's curve. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        x_val\n            The x_value along the curve that positions the label.\n        direction\n            The cartesian position, relative to the curve that the label will be at --> ``LEFT``, ``RIGHT``.\n        buff\n            The distance between the curve and the label.\n        color\n            The color of the label. Defaults to the color of the curve.\n        dot\n            Whether to add a dot at the point on the graph.\n        dot_config\n            Additional parameters to be passed to :class:`~.Dot`.\n\n        Returns\n        -------\n        :class:`Mobject`\n            The positioned label and :class:`~.Dot`, if applicable.\n\n        Examples\n        --------\n        .. manim:: GetGraphLabelExample\n            :save_last_frame:\n\n            class GetGraphLabelExample(Scene):\n                def construct(self):\n                    ax = Axes()\n                    sin = ax.plot(lambda x: np.sin(x), color=PURPLE_B)\n                    label = ax.get_graph_label(\n                        graph=sin,\n                        label= MathTex(r\"\\frac{\\pi}{2}\"),\n                        x_val=PI / 2,\n                        dot=True,\n                        direction=UR,\n                    )\n\n                    self.add(ax, sin, label)\n        \"\"\"\n        if dot_config is None:\n            dot_config = {}\n        if color is None:\n            color = graph.get_color()\n        label_object: Mobject = self.x_axis._create_label_tex(label).set_color(color)\n\n        if x_val is None:\n            # Search from right to left\n            for x in np.linspace(self.x_range[1], self.x_range[0], 100):\n                point = self.input_to_graph_point(x, graph)\n                if point[1] < config[\"frame_y_radius\"]:\n                    break\n        else:\n            point = self.input_to_graph_point(x_val, graph)\n\n        label_object.next_to(point, direction, buff=buff)\n        label_object.shift_onto_screen()\n\n        if dot:\n            dot = Dot(point=point, **dot_config)\n            label_object.add(dot)\n            label_object.dot = dot\n        return label_object\n\n    # calculus\n\n    def get_riemann_rectangles(\n        self,\n        graph: ParametricFunction,\n        x_range: Sequence[float] | None = None,\n        dx: float = 0.1,\n        input_sample_type: str = \"left\",\n        stroke_width: float = 1,\n        stroke_color: ParsableManimColor = BLACK,\n        fill_opacity: float = 1,\n        color: Iterable[ParsableManimColor] | ParsableManimColor = (BLUE, GREEN),\n        show_signed_area: bool = True,\n        bounded_graph: ParametricFunction | None = None,\n        blend: bool = False,\n        width_scale_factor: float = 1.001,\n    ) -> VGroup:\n        \"\"\"Generates a :class:`~.VGroup` of the Riemann Rectangles for a given curve.\n\n        Parameters\n        ----------\n        graph\n            The graph whose area will be approximated by Riemann rectangles.\n        x_range\n            The minimum and maximum x-values of the rectangles. ``x_range = [x_min, x_max]``.\n        dx\n            The change in x-value that separates each rectangle.\n        input_sample_type\n            Can be any of ``\"left\"``, ``\"right\"`` or ``\"center\"``. Refers to where\n            the sample point for the height of each Riemann Rectangle\n            will be inside the segments of the partition.\n        stroke_width\n            The stroke_width of the border of the rectangles.\n        stroke_color\n            The color of the border of the rectangle.\n        fill_opacity\n            The opacity of the rectangles.\n        color\n            The colors of the rectangles. Creates a balanced gradient if multiple colors are passed.\n        show_signed_area\n            Indicates negative area when the curve dips below the x-axis by inverting its color.\n        blend\n            Sets the :attr:`stroke_color` to :attr:`fill_color`, blending the rectangles without clear separation.\n        bounded_graph\n            If a secondary graph is specified, encloses the area between the two curves.\n        width_scale_factor\n            The factor by which the width of the rectangles is scaled.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            A :class:`~.VGroup` containing the Riemann Rectangles.\n\n        Examples\n        --------\n        .. manim:: GetRiemannRectanglesExample\n            :save_last_frame:\n\n            class GetRiemannRectanglesExample(Scene):\n                def construct(self):\n                    ax = Axes(y_range=[-2, 10])\n                    quadratic = ax.plot(lambda x: 0.5 * x ** 2 - 0.5)\n\n                    # the rectangles are constructed from their top right corner.\n                    # passing an iterable to `color` produces a gradient\n                    rects_right = ax.get_riemann_rectangles(\n                        quadratic,\n                        x_range=[-4, -3],\n                        dx=0.25,\n                        color=(TEAL, BLUE_B, DARK_BLUE),\n                        input_sample_type=\"right\",\n                    )\n\n                    # the colour of rectangles below the x-axis is inverted\n                    # due to show_signed_area\n                    rects_left = ax.get_riemann_rectangles(\n                        quadratic, x_range=[-1.5, 1.5], dx=0.15, color=YELLOW\n                    )\n\n                    bounding_line = ax.plot(\n                        lambda x: 1.5 * x, color=BLUE_B, x_range=[3.3, 6]\n                    )\n                    bounded_rects = ax.get_riemann_rectangles(\n                        bounding_line,\n                        bounded_graph=quadratic,\n                        dx=0.15,\n                        x_range=[4, 5],\n                        show_signed_area=False,\n                        color=(MAROON_A, RED_B, PURPLE_D),\n                    )\n\n                    self.add(\n                        ax, bounding_line, quadratic, rects_right, rects_left, bounded_rects\n                    )\n        \"\"\"\n        # setting up x_range, overwrite user's third input\n        if x_range is None:\n            if bounded_graph is None:\n                x_range = [graph.t_min, graph.t_max]\n            else:\n                x_min = max(graph.t_min, bounded_graph.t_min)\n                x_max = min(graph.t_max, bounded_graph.t_max)\n                x_range = [x_min, x_max]\n\n        x_range = [*x_range[:2], dx]\n\n        rectangles = VGroup()\n        x_range_array = np.arange(*x_range)\n\n        if isinstance(color, (list, tuple)):\n            color = [ManimColor(c) for c in color]\n        else:\n            color = [ManimColor(color)]\n\n        colors = color_gradient(color, len(x_range_array))\n\n        for x, color in zip(x_range_array, colors, strict=True):\n            if input_sample_type == \"left\":\n                sample_input = x\n            elif input_sample_type == \"right\":\n                sample_input = x + dx\n            elif input_sample_type == \"center\":\n                sample_input = x + 0.5 * dx\n            else:\n                raise ValueError(\"Invalid input sample type\")\n            graph_point = self.input_to_graph_point(sample_input, graph)\n\n            if bounded_graph is None:\n                y_point = self._origin_shift(self.y_range)\n            else:\n                y_point = bounded_graph.underlying_function(x)\n\n            points = VGroup(\n                *list(\n                    map(\n                        VectorizedPoint,\n                        [\n                            self.coords_to_point(x, y_point),\n                            self.coords_to_point(x + width_scale_factor * dx, y_point),\n                            graph_point,\n                        ],\n                    ),\n                )\n            )\n\n            rect = Rectangle().replace(points, stretch=True)\n            rectangles.add(rect)\n\n            # checks if the rectangle is under the x-axis\n            if self.p2c(graph_point)[1] < y_point and show_signed_area:\n                color = invert_color(color)\n\n            # blends rectangles smoothly\n            if blend:\n                stroke_color = color\n\n            rect.set_style(\n                fill_color=color,\n                fill_opacity=fill_opacity,\n                stroke_color=stroke_color,\n                stroke_width=stroke_width,\n            )\n\n        return rectangles\n\n    def get_area(\n        self,\n        graph: ParametricFunction,\n        x_range: tuple[float, float] | None = None,\n        color: ParsableManimColor | Iterable[ParsableManimColor] = (BLUE, GREEN),\n        opacity: float = 0.3,\n        bounded_graph: ParametricFunction | None = None,\n        **kwargs: Any,\n    ) -> Polygon:\n        \"\"\"Returns a :class:`~.Polygon` representing the area under the graph passed.\n\n        Parameters\n        ----------\n        graph\n            The graph/curve for which the area needs to be gotten.\n        x_range\n            The range of the minimum and maximum x-values of the area. ``x_range = [x_min, x_max]``.\n        color\n            The color of the area. Creates a gradient if a list of colors is provided.\n        opacity\n            The opacity of the area.\n        bounded_graph\n            If a secondary :attr:`graph` is specified, encloses the area between the two curves.\n        kwargs\n            Additional parameters passed to :class:`~.Polygon`.\n\n        Returns\n        -------\n        :class:`~.Polygon`\n            The :class:`~.Polygon` representing the area.\n\n        Raises\n        ------\n        :exc:`ValueError`\n            When x_ranges do not match (either area x_range, graph's x_range or bounded_graph's x_range).\n\n        Examples\n        --------\n        .. manim:: GetAreaExample\n            :save_last_frame:\n\n            class GetAreaExample(Scene):\n                def construct(self):\n                    ax = Axes().add_coordinates()\n                    curve = ax.plot(lambda x: 2 * np.sin(x), color=DARK_BLUE)\n                    area = ax.get_area(\n                        curve,\n                        x_range=(PI / 2, 3 * PI / 2),\n                        color=(GREEN_B, GREEN_D),\n                        opacity=1,\n                    )\n\n                    self.add(ax, curve, area)\n        \"\"\"\n        if x_range is None:\n            a = graph.t_min\n            b = graph.t_max\n        else:\n            a, b = x_range\n        if bounded_graph is not None:\n            if bounded_graph.t_min > b:\n                raise ValueError(\n                    f\"Ranges not matching: {bounded_graph.t_min} < {b}\",\n                )\n            if bounded_graph.t_max < a:\n                raise ValueError(\n                    f\"Ranges not matching: {bounded_graph.t_max} > {a}\",\n                )\n            a = max(a, bounded_graph.t_min)\n            b = min(b, bounded_graph.t_max)\n\n        if bounded_graph is None:\n            points = (\n                [self.c2p(a), graph.function(a)]\n                + [p for p in graph.points if a <= self.p2c(p)[0] <= b]\n                + [graph.function(b), self.c2p(b)]\n            )\n        else:\n            graph_points, bounded_graph_points = (\n                [g.function(a)]\n                + [p for p in g.points if a <= self.p2c(p)[0] <= b]\n                + [g.function(b)]\n                for g in (graph, bounded_graph)\n            )\n            points = graph_points + bounded_graph_points[::-1]\n        return Polygon(*points, **kwargs).set_opacity(opacity).set_color(color)\n\n    def angle_of_tangent(\n        self,\n        x: float,\n        graph: ParametricFunction,\n        dx: float = 1e-8,\n    ) -> float:\n        \"\"\"Returns the angle to the x-axis of the tangent\n        to the plotted curve at a particular x-value.\n\n        Parameters\n        ----------\n        x\n            The x-value at which the tangent must touch the curve.\n        graph\n            The :class:`~.ParametricFunction` for which to calculate the tangent.\n        dx\n            The change in `x` used to determine the angle of the tangent to the curve.\n\n        Returns\n        -------\n        :class:`float`\n            The angle of the tangent to the curve.\n\n        Examples\n        --------\n        .. code-block:: python\n\n            ax = Axes()\n            curve = ax.plot(lambda x: x**2)\n            ax.angle_of_tangent(x=3, graph=curve)\n            # 1.4056476493802699\n        \"\"\"\n        p0 = np.array([*self.input_to_graph_coords(x, graph)])\n        p1 = np.array([*self.input_to_graph_coords(x + dx, graph)])\n        return angle_of_vector(p1 - p0)\n\n    def slope_of_tangent(\n        self, x: float, graph: ParametricFunction, **kwargs: Any\n    ) -> float:\n        \"\"\"Returns the slope of the tangent to the plotted curve\n        at a particular x-value.\n\n        Parameters\n        ----------\n        x\n            The x-value at which the tangent must touch the curve.\n        graph\n            The :class:`~.ParametricFunction` for which to calculate the tangent.\n\n        Returns\n        -------\n        :class:`float`\n            The slope of the tangent with the x axis.\n\n        Examples\n        --------\n        .. code-block:: python\n\n            ax = Axes()\n            curve = ax.plot(lambda x: x**2)\n            ax.slope_of_tangent(x=-2, graph=curve)\n            # -3.5000000259052038\n        \"\"\"\n        val: float = np.tan(self.angle_of_tangent(x, graph, **kwargs))\n        return val\n\n    def plot_derivative_graph(\n        self,\n        graph: ParametricFunction,\n        color: ParsableManimColor = GREEN,\n        **kwargs: Any,\n    ) -> ParametricFunction:\n        \"\"\"Returns the curve of the derivative of the passed graph.\n\n        Parameters\n        ----------\n        graph\n            The graph for which the derivative will be found.\n        color\n            The color of the derivative curve.\n        kwargs\n            Any valid keyword argument of :class:`~.ParametricFunction`.\n\n        Returns\n        -------\n        :class:`~.ParametricFunction`\n            The curve of the derivative.\n\n        Examples\n        --------\n        .. manim:: DerivativeGraphExample\n            :save_last_frame:\n\n            class DerivativeGraphExample(Scene):\n                def construct(self):\n                    ax = NumberPlane(y_range=[-1, 7], background_line_style={\"stroke_opacity\": 0.4})\n\n                    curve_1 = ax.plot(lambda x: x ** 2, color=PURPLE_B)\n                    curve_2 = ax.plot_derivative_graph(curve_1)\n                    curves = VGroup(curve_1, curve_2)\n\n                    label_1 = ax.get_graph_label(curve_1, \"x^2\", x_val=-2, direction=DL)\n                    label_2 = ax.get_graph_label(curve_2, \"2x\", x_val=3, direction=RIGHT)\n                    labels = VGroup(label_1, label_2)\n\n                    self.add(ax, curves, labels)\n        \"\"\"\n\n        def deriv(x: float) -> float:\n            return self.slope_of_tangent(x, graph)\n\n        return self.plot(deriv, color=color, **kwargs)\n\n    def plot_antiderivative_graph(\n        self,\n        graph: ParametricFunction,\n        y_intercept: float = 0,\n        samples: int = 50,\n        use_vectorized: bool = False,\n        **kwargs: Any,\n    ) -> ParametricFunction:\n        \"\"\"Plots an antiderivative graph.\n\n        Parameters\n        ----------\n        graph\n            The graph for which the antiderivative will be found.\n        y_intercept\n            The y-value at which the graph intercepts the y-axis.\n        samples\n            The number of points to take the area under the graph.\n        use_vectorized\n            Whether to use the vectorized version of the antiderivative. This means\n            to pass in the generated t value array to the function. Only use this if your function supports it.\n            Output should be a numpy array of shape ``[y_0, y_1, ...]``\n        kwargs\n            Any valid keyword argument of :class:`~.ParametricFunction`.\n\n        Returns\n        -------\n        :class:`~.ParametricFunction`\n            The curve of the antiderivative.\n\n\n        .. note::\n            This graph is plotted from the values of area under the reference graph.\n            The result might not be ideal if the reference graph contains uncalculatable\n            areas from x=0.\n\n        Examples\n        --------\n        .. manim:: AntiderivativeExample\n            :save_last_frame:\n\n            class AntiderivativeExample(Scene):\n                def construct(self):\n                    ax = Axes()\n                    graph1 = ax.plot(\n                        lambda x: (x ** 2 - 2) / 3,\n                        color=RED,\n                    )\n                    graph2 = ax.plot_antiderivative_graph(graph1, color=BLUE)\n                    self.add(ax, graph1, graph2)\n        \"\"\"\n\n        def antideriv(x):\n            x_vals = np.linspace(0, x, samples, axis=1 if use_vectorized else 0)\n            f_vec = np.vectorize(graph.underlying_function)\n            y_vals = f_vec(x_vals)\n            return np.trapezoid(y_vals, x_vals) + y_intercept\n\n        return self.plot(antideriv, use_vectorized=use_vectorized, **kwargs)\n\n    def get_secant_slope_group(\n        self,\n        x: float,\n        graph: ParametricFunction,\n        dx: float | None = None,\n        dx_line_color: ParsableManimColor = PURE_YELLOW,\n        dy_line_color: ParsableManimColor | None = None,\n        dx_label: float | str | None = None,\n        dy_label: float | str | None = None,\n        include_secant_line: bool = True,\n        secant_line_color: ParsableManimColor = GREEN,\n        secant_line_length: float = 10,\n    ) -> VGroup:\n        \"\"\"Creates two lines representing `dx` and `df`, the labels for `dx` and `df`, and\n         the secant to the curve at a particular x-value.\n\n        Parameters\n        ----------\n        x\n            The x-value at which the secant intersects the graph for the first time.\n        graph\n            The curve for which the secant will be found.\n        dx\n            The change in `x` after which the secant exits.\n        dx_line_color\n            The color of the line that indicates the change in `x`.\n        dy_line_color\n            The color of the line that indicates the change in `y`. Defaults to the color of :attr:`graph`.\n        dx_label\n            The label for the `dx` line. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        dy_label\n            The label for the `dy` line. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        include_secant_line\n            Whether to include the secant line in the graph,\n            or just the df/dx lines and labels.\n        secant_line_color\n            The color of the secant line.\n        secant_line_length\n            The length of the secant line.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            A group containing the elements: `dx_line`, `df_line`, and\n            if applicable also :attr:`dx_label`, :attr:`df_label`, `secant_line`.\n\n        Examples\n        --------\n         .. manim:: GetSecantSlopeGroupExample\n            :save_last_frame:\n\n            class GetSecantSlopeGroupExample(Scene):\n                def construct(self):\n                    ax = Axes(y_range=[-1, 7])\n                    graph = ax.plot(lambda x: 1 / 4 * x ** 2, color=BLUE)\n                    slopes = ax.get_secant_slope_group(\n                        x=2.0,\n                        graph=graph,\n                        dx=1.0,\n                        dx_label=Tex(\"dx = 1.0\"),\n                        dy_label=\"dy\",\n                        dx_line_color=GREEN_B,\n                        secant_line_length=4,\n                        secant_line_color=RED_D,\n                    )\n\n                    self.add(ax, graph, slopes)\n        \"\"\"\n        group = VGroup()\n\n        dx = dx or float(self.x_range[1] - self.x_range[0]) / 10\n        dy_line_color = dy_line_color or graph.get_color()\n\n        p1 = self.input_to_graph_point(x, graph)\n        p2 = self.input_to_graph_point(x + dx, graph)\n        interim_point = p2[0] * RIGHT + p1[1] * UP\n\n        group.dx_line = Line(p1, interim_point, color=dx_line_color)\n        group.df_line = Line(interim_point, p2, color=dy_line_color)\n        group.add(group.dx_line, group.df_line)\n\n        labels = VGroup()\n        if dx_label is not None:\n            group.dx_label = self.x_axis._create_label_tex(dx_label)\n            labels.add(group.dx_label)\n            group.add(group.dx_label)\n        if dy_label is not None:\n            group.df_label = self.x_axis._create_label_tex(dy_label)\n            labels.add(group.df_label)\n            group.add(group.df_label)\n\n        if len(labels) > 0:\n            max_width = 0.8 * group.dx_line.width\n            max_height = 0.8 * group.df_line.height\n            if labels.width > max_width:\n                labels.width = max_width\n            if labels.height > max_height:\n                labels.height = max_height\n\n        if dx_label is not None:\n            group.dx_label.next_to(\n                group.dx_line,\n                np.sign(dx) * DOWN,\n                buff=group.dx_label.height / 2,\n            )\n            group.dx_label.set_color(group.dx_line.get_color())\n\n        if dy_label is not None:\n            group.df_label.next_to(\n                group.df_line,\n                np.sign(dx) * RIGHT,\n                buff=group.df_label.height / 2,\n            )\n            group.df_label.set_color(group.df_line.get_color())\n\n        if include_secant_line:\n            group.secant_line = Line(p1, p2, color=secant_line_color)\n            group.secant_line.scale(\n                secant_line_length / group.secant_line.get_length(),\n            )\n            group.add(group.secant_line)\n        return group\n\n    def get_vertical_lines_to_graph(\n        self,\n        graph: ParametricFunction,\n        x_range: Sequence[float] | None = None,\n        num_lines: int = 20,\n        **kwargs: Any,\n    ) -> VGroup:\n        \"\"\"Obtains multiple lines from the x-axis to the curve.\n\n        Parameters\n        ----------\n        graph\n            The graph along which the lines are placed.\n        x_range\n            A list containing the lower and and upper bounds of the lines: ``x_range = [x_min, x_max]``.\n        num_lines\n            The number of evenly spaced lines.\n        kwargs\n            Additional arguments to be passed to :meth:`~.CoordinateSystem.get_vertical_line`.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            The :class:`~.VGroup` of the evenly spaced lines.\n\n        Examples\n        --------\n        .. manim:: GetVerticalLinesToGraph\n            :save_last_frame:\n\n            class GetVerticalLinesToGraph(Scene):\n                def construct(self):\n                    ax = Axes(\n                        x_range=[0, 8.0, 1],\n                        y_range=[-1, 1, 0.2],\n                        axis_config={\"font_size\": 24},\n                    ).add_coordinates()\n\n                    curve = ax.plot(lambda x: np.sin(x) / np.e ** 2 * x)\n\n                    lines = ax.get_vertical_lines_to_graph(\n                        curve, x_range=[0, 4], num_lines=30, color=BLUE\n                    )\n\n                    self.add(ax, curve, lines)\n        \"\"\"\n        x_range = x_range if x_range is not None else self.x_range\n\n        return VGroup(\n            *(\n                self.get_vertical_line(self.i2gp(x, graph), **kwargs)\n                for x in np.linspace(x_range[0], x_range[1], num_lines)\n            )\n        )\n\n    def get_T_label(\n        self,\n        x_val: float,\n        graph: ParametricFunction,\n        label: float | str | Mobject | None = None,\n        label_color: ParsableManimColor | None = None,\n        triangle_size: float = MED_SMALL_BUFF,\n        triangle_color: ParsableManimColor | None = WHITE,\n        line_func: type[Line] = Line,\n        line_color: ParsableManimColor = PURE_YELLOW,\n    ) -> VGroup:\n        \"\"\"Creates a labelled triangle marker with a vertical line from the x-axis\n        to a curve at a given x-value.\n\n        Parameters\n        ----------\n        x_val\n            The position along the curve at which the label, line and triangle will be constructed.\n        graph\n            The :class:`~.ParametricFunction` for which to construct the label.\n        label\n            The label of the vertical line and triangle.\n        label_color\n            The color of the label.\n        triangle_size\n            The size of the triangle.\n        triangle_color\n            The color of the triangle.\n        line_func\n            The function used to construct the vertical line.\n        line_color\n            The color of the vertical line.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            A :class:`~.VGroup` of the label, triangle and vertical line mobjects.\n\n        Examples\n        --------\n        .. manim:: TLabelExample\n            :save_last_frame:\n\n            class TLabelExample(Scene):\n                def construct(self):\n                    # defines the axes and linear function\n                    axes = Axes(x_range=[-1, 10], y_range=[-1, 10], x_length=9, y_length=6)\n                    func = axes.plot(lambda x: x, color=BLUE)\n                    # creates the T_label\n                    t_label = axes.get_T_label(x_val=4, graph=func, label=Tex(\"x-value\"))\n                    self.add(axes, func, t_label)\n        \"\"\"\n        T_label_group = VGroup()\n        triangle = RegularPolygon(n=3, start_angle=np.pi / 2, stroke_width=0).set_fill(\n            color=triangle_color,\n            opacity=1,\n        )\n        triangle.height = triangle_size\n        triangle.move_to(self.coords_to_point(x_val, 0), UP)\n        if label is not None:\n            t_label = self.x_axis._create_label_tex(label, color=label_color)\n            t_label.next_to(triangle, DOWN)\n            T_label_group.add(t_label)\n\n        v_line = self.get_vertical_line(\n            self.i2gp(x_val, graph),\n            color=line_color,\n            line_func=line_func,\n        )\n\n        T_label_group.add(triangle, v_line)\n\n        return T_label_group\n\n    def __matmul__(self, coord: Point3DLike | Mobject) -> Point3DLike:\n        if isinstance(coord, Mobject):\n            coord = coord.get_center()\n        return self.coords_to_point(*coord)\n\n    def __rmatmul__(self, point: Point3DLike) -> Point3DLike:\n        return self.point_to_coords(point)\n\n    @staticmethod\n    def _origin_shift(axis_range: Sequence[float]) -> float: ...\n\n\nclass Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):\n    \"\"\"Creates a set of axes.\n\n    Parameters\n    ----------\n    x_range\n        The ``(x_min, x_max, x_step)`` values of the x-axis.\n    y_range\n        The ``(y_min, y_max, y_step)`` values of the y-axis.\n    x_length\n        The length of the x-axis.\n    y_length\n        The length of the y-axis.\n    axis_config\n        Arguments to be passed to :class:`~.NumberLine` that influences both axes.\n    x_axis_config\n        Arguments to be passed to :class:`~.NumberLine` that influence the x-axis.\n    y_axis_config\n        Arguments to be passed to :class:`~.NumberLine` that influence the y-axis.\n    tips\n        Whether or not to include the tips on both axes.\n    kwargs\n        Additional arguments to be passed to :class:`CoordinateSystem` and :class:`~.VGroup`.\n\n    Examples\n    --------\n    .. manim:: LogScalingExample\n        :save_last_frame:\n\n        class LogScalingExample(Scene):\n            def construct(self):\n                ax = Axes(\n                    x_range=[0, 10, 1],\n                    y_range=[-2, 6, 1],\n                    tips=False,\n                    axis_config={\"include_numbers\": True},\n                    y_axis_config={\"scaling\": LogBase(custom_labels=True)},\n                )\n\n                # x_min must be > 0 because log is undefined at 0.\n                graph = ax.plot(lambda x: x ** 2, x_range=[0.001, 10], use_smoothing=False)\n                self.add(ax, graph)\n\n    Styling arguments can be passed to the underlying :class:`.NumberLine`\n    mobjects that represent the axes:\n\n    .. manim:: AxesWithDifferentTips\n        :save_last_frame:\n\n        class AxesWithDifferentTips(Scene):\n            def construct(self):\n                ax = Axes(axis_config={'tip_shape': StealthTip})\n                self.add(ax)\n    \"\"\"\n\n    def __init__(\n        self,\n        x_range: Sequence[float] | None = None,\n        y_range: Sequence[float] | None = None,\n        x_length: float | None = round(config.frame_width) - 2,\n        y_length: float | None = round(config.frame_height) - 2,\n        axis_config: dict | None = None,\n        x_axis_config: dict | None = None,\n        y_axis_config: dict | None = None,\n        tips: bool = True,\n        **kwargs: Any,\n    ):\n        VGroup.__init__(self, **kwargs)\n        CoordinateSystem.__init__(self, x_range, y_range, x_length, y_length)\n\n        self.axis_config = {\n            \"include_tip\": tips,\n            \"numbers_to_exclude\": [0],\n        }\n        self.x_axis_config: dict[str, Any] = {}\n        self.y_axis_config: dict[str, Any] = {\n            \"rotation\": 90 * DEGREES,\n            \"label_direction\": LEFT,\n        }\n\n        self._update_default_configs(\n            (self.axis_config, self.x_axis_config, self.y_axis_config),\n            (axis_config, x_axis_config, y_axis_config),\n        )\n\n        self.x_axis_config = merge_dicts_recursively(\n            self.axis_config,\n            self.x_axis_config,\n        )\n        self.y_axis_config = merge_dicts_recursively(\n            self.axis_config,\n            self.y_axis_config,\n        )\n\n        # excluding the origin tick removes a tick at the 0-point of the axis\n        # This is desired for LinearBase because the 0 point is always the x-axis\n        # For non-LinearBase, the \"0-point\" does not have this quality, so it must be included.\n\n        # i.e. with LogBase range [-2, 4]:\n        # it would remove the \"0\" tick, which is actually 10^0,\n        # not the lowest tick on the graph (which is 10^-2).\n\n        if self.x_axis_config.get(\"scaling\") is None or isinstance(\n            self.x_axis_config.get(\"scaling\"), LinearBase\n        ):\n            self.x_axis_config[\"exclude_origin_tick\"] = True\n        else:\n            self.x_axis_config[\"exclude_origin_tick\"] = False\n\n        if self.y_axis_config.get(\"scaling\") is None or isinstance(\n            self.y_axis_config.get(\"scaling\"), LinearBase\n        ):\n            self.y_axis_config[\"exclude_origin_tick\"] = True\n        else:\n            self.y_axis_config[\"exclude_origin_tick\"] = False\n\n        self.x_axis = self._create_axis(self.x_range, self.x_axis_config, self.x_length)\n        self.y_axis = self._create_axis(self.y_range, self.y_axis_config, self.y_length)\n\n        # Add as a separate group in case various other\n        # mobjects are added to self, as for example in\n        # NumberPlane below\n        self.axes = VGroup(self.x_axis, self.y_axis)\n        self.add(*self.axes)\n\n        # finds the middle-point on each axis\n        lines_center_point = [\n            axis.scaling.function((axis.x_range[1] + axis.x_range[0]) / 2)\n            for axis in self.axes\n        ]\n\n        self.shift(-self.coords_to_point(*lines_center_point))\n\n    @staticmethod\n    def _update_default_configs(\n        default_configs: tuple[dict[Any, Any]], passed_configs: tuple[dict[Any, Any]]\n    ) -> None:\n        \"\"\"Takes in two tuples of dicts and return modifies the first such that values from\n        ``passed_configs`` overwrite values in ``default_configs``. If a key does not exist\n        in default_configs, it is added to the dict.\n\n        This method is useful for having defaults in a class and being able to overwrite\n        them with user-defined input.\n\n        Parameters\n        ----------\n        default_configs\n            The dict that will be updated.\n        passed_configs\n            The dict that will be used to update.\n\n        Examples\n        --------\n        To create a tuple with one dictionary, add a comma after the element:\n\n        .. code-block:: python\n\n            self._update_default_configs(\n                (dict_1,)(\n                    dict_2,\n                )\n            )\n        \"\"\"\n        for default_config, passed_config in zip(\n            default_configs, passed_configs, strict=False\n        ):\n            if passed_config is not None:\n                update_dict_recursively(default_config, passed_config)\n\n    def _create_axis(\n        self,\n        range_terms: Sequence[float],\n        axis_config: dict[str, Any],\n        length: float,\n    ) -> NumberLine:\n        \"\"\"Creates an axis and dynamically adjusts its position depending on where 0 is located on the line.\n\n        Parameters\n        ----------\n        range_terms\n            The range of the the axis : ``(x_min, x_max, x_step)``.\n        axis_config\n            Additional parameters that are passed to :class:`~.NumberLine`.\n        length\n            The length of the axis.\n\n        Returns\n        -------\n        :class:`NumberLine`\n            Returns a number line based on ``range_terms``.\n        \"\"\"\n        axis_config[\"length\"] = length\n        axis = NumberLine(range_terms, **axis_config)\n\n        # without the call to _origin_shift, graph does not exist when min > 0 or max < 0\n        # shifts the axis so that 0 is centered\n        axis.shift(-axis.number_to_point(self._origin_shift([axis.x_min, axis.x_max])))\n        return axis\n\n    def coords_to_point(\n        self, *coords: float | Sequence[float] | Sequence[Sequence[float]] | np.ndarray\n    ) -> np.ndarray:\n        \"\"\"Accepts coordinates from the axes and returns a point with respect to the scene.\n        Equivalent to `ax @ (coord1)`\n\n        Parameters\n        ----------\n        coords\n            The coordinates. Each coord is passed as a separate argument: ``ax.coords_to_point(1, 2, 3)``.\n\n            Also accepts a list of coordinates\n\n            ``ax.coords_to_point( [x_0, x_1, ...], [y_0, y_1, ...], ... )``\n\n            ``ax.coords_to_point( [[x_0, y_0, z_0], [x_1, y_1, z_1]] )``\n\n            A single coordinate can also be passed as a flat list or 1D array:\n\n            ``ax.coords_to_point( [x, y, z] )``\n\n        Returns\n        -------\n        np.ndarray\n            A point with respect to the scene's coordinate system.\n            The shape of the array will be similar to the shape of the input.\n\n        Examples\n        --------\n\n        .. code-block:: pycon\n\n            >>> from manim import Axes\n            >>> import numpy as np\n            >>> ax = Axes()\n            >>> np.around(ax.coords_to_point(1, 0, 0), 2)\n            array([0.86, 0.  , 0.  ])\n            >>> np.around(ax @ (1, 0, 0), 2)\n            array([0.86, 0.  , 0.  ])\n            >>> np.around(ax.coords_to_point([[0, 1], [1, 1], [1, 0]]), 2)\n            array([[0.  , 0.75, 0.  ],\n                   [0.86, 0.75, 0.  ],\n                   [0.86, 0.  , 0.  ]])\n            >>> np.around(\n            ...     ax.coords_to_point([0, 1, 1], [1, 1, 0]), 2\n            ... )  # Transposed version of the above\n            array([[0.  , 0.86, 0.86],\n                   [0.75, 0.75, 0.  ],\n                   [0.  , 0.  , 0.  ]])\n            >>> np.around(ax.coords_to_point([1, 0, 0]), 2)\n            array([0.86, 0.  , 0.  ])\n            >>> np.around(ax.coords_to_point(np.array([1, 0])), 2)\n            array([0.86, 0.  , 0.  ])\n\n        .. manim:: CoordsToPointExample\n            :save_last_frame:\n\n            class CoordsToPointExample(Scene):\n                def construct(self):\n                    ax = Axes().add_coordinates()\n\n                    # a dot with respect to the axes\n                    dot_axes = Dot(ax.coords_to_point(2, 2), color=GREEN)\n                    lines = ax.get_lines_to_point(ax.c2p(2,2))\n\n                    # a dot with respect to the scene\n                    # the default plane corresponds to the coordinates of the scene.\n                    plane = NumberPlane()\n                    dot_scene = Dot((2,2,0), color=RED)\n\n                    self.add(plane, dot_scene, ax, dot_axes, lines)\n        \"\"\"\n        coords = np.asarray(coords)\n        origin = self.x_axis.number_to_point(\n            self._origin_shift([self.x_axis.x_min, self.x_axis.x_max]),\n        )\n\n        # Is coords in the format ([[x1 y1 z1] [x2 y2 z2] ...])? (True)\n        # Or is coords in the format (x, y, z) or ([x1 x2 ...], [y1 y2 ...], [z1 z2 ...])? (False)\n        # The latter is preferred.\n        are_coordinates_transposed = False\n\n        # If coords is in the format ([[x1 y1 z1] [x2 y2 z2] ...]):\n        if coords.ndim == 3:\n            # Extract from original tuple: now coords looks like [[x y z]] or [[x1 y1 z1] [x2 y2 z2] ...].\n            coords = coords[0]\n            # If there's a single coord (coords = [[x y z]]), extract it so that\n            # coords = [x y z] and coords_to_point returns a single point.\n            if coords.shape[0] == 1:\n                coords = coords[0]\n            # Else, if coords looks more like [[x1 y1 z1] [x2 y2 z2] ...], transform them (by\n            # transposing) into the format [[x1 x2 ...] [y1 y2 ...] [z1 z2 ...]] for later processing.\n            else:\n                coords = coords.T\n                are_coordinates_transposed = True\n        # If coords is in the format ([x, y, z]) -- a single flat list/array passed as one argument:\n        elif coords.ndim == 2 and coords.shape[0] == 1:\n            # Extract the single list so [x, y, z] is treated like c2p(x, y, z).\n            coords = coords[0]\n        # Otherwise, coords already looked like (x, y, z) or ([x1 x2 ...], [y1 y2 ...], [z1 z2 ...]),\n        # so no further processing is needed.\n\n        # Now coords should either look like [x y z] or [[x1 x2 ...] [y1 y2 ...] [z1 z2 ...]],\n        # so it can be iterated directly. Each element is either a float representing a single\n        # coordinate, or a float ndarray of coordinates corresponding to a single axis.\n        # Although \"points\" and \"nums\" are in plural, there might be a single point or number.\n        points = self.x_axis.number_to_point(coords[0])\n        other_axes = self.axes.submobjects[1:]\n        for axis, nums in zip(other_axes, coords[1:], strict=False):\n            points += axis.number_to_point(nums) - origin\n\n        # Return points as is, except if coords originally looked like\n        # ([x1 x2 ...], [y1 y2 ...], [z1 z2 ...]), which is determined by the conditions below. In\n        # that case, the current implementation requires that the results have to be transposed.\n        if are_coordinates_transposed or points.ndim == 1:\n            return points\n        return points.T\n\n    def point_to_coords(self, point: Sequence[float]) -> np.ndarray:\n        \"\"\"Accepts a point from the scene and returns its coordinates with respect to the axes.\n\n        Parameters\n        ----------\n        point\n            The point, i.e. ``RIGHT`` or ``[0, 1, 0]``.\n            Also accepts a list of points as ``[RIGHT, [0, 1, 0]]``.\n\n        Returns\n        -------\n        np.ndarray[float]\n            The coordinates on the axes, i.e. ``[4.0, 7.0]``.\n            Or a list of coordinates if `point` is a list of points.\n\n        Examples\n        --------\n\n        .. code-block:: pycon\n\n            >>> from manim import Axes, RIGHT\n            >>> import numpy as np\n            >>> ax = Axes(x_range=[0, 10, 2])\n            >>> np.around(ax.point_to_coords(RIGHT), 2)\n            array([5.83, 0.  ])\n            >>> np.around(ax.point_to_coords([[0, 0, 1], [1, 0, 0]]), 2)\n            array([[5.  , 0.  ],\n                   [5.83, 0.  ]])\n\n\n        .. manim:: PointToCoordsExample\n            :save_last_frame:\n\n            class PointToCoordsExample(Scene):\n                def construct(self):\n                    ax = Axes(x_range=[0, 10, 2]).add_coordinates()\n                    circ = Circle(radius=0.5).shift(UR * 2)\n\n                    # get the coordinates of the circle with respect to the axes\n                    coords = np.around(ax.point_to_coords(circ.get_right()), decimals=2)\n\n                    label = (\n                        Matrix([[coords[0]], [coords[1]]]).scale(0.75).next_to(circ, RIGHT)\n                    )\n\n                    self.add(ax, circ, label, Dot(circ.get_right()))\n        \"\"\"\n        point = np.asarray(point)\n        result = np.asarray([axis.point_to_number(point) for axis in self.get_axes()])\n        if point.ndim == 2:\n            return result.T\n        return result\n\n    def get_axes(self) -> VGroup:\n        \"\"\"Gets the axes.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            A pair of axes.\n        \"\"\"\n        return self.axes\n\n    def get_axis_labels(\n        self,\n        x_label: float | str | Mobject = \"x\",\n        y_label: float | str | Mobject = \"y\",\n    ) -> VGroup:\n        \"\"\"Defines labels for the x-axis and y-axis of the graph.\n\n        For increased control over the position of the labels,\n        use :meth:`~.CoordinateSystem.get_x_axis_label` and\n        :meth:`~.CoordinateSystem.get_y_axis_label`.\n\n        Parameters\n        ----------\n        x_label\n            The label for the x_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        y_label\n            The label for the y_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            A :class:`~.VGroup` of the labels for the x_axis and y_axis.\n\n\n        .. seealso::\n            :meth:`~.CoordinateSystem.get_x_axis_label`\n            :meth:`~.CoordinateSystem.get_y_axis_label`\n\n        Examples\n        --------\n        .. manim:: GetAxisLabelsExample\n            :save_last_frame:\n\n            class GetAxisLabelsExample(Scene):\n                def construct(self):\n                    ax = Axes()\n                    labels = ax.get_axis_labels(\n                        Tex(\"x-axis\").scale(0.7), Text(\"y-axis\").scale(0.45)\n                    )\n                    self.add(ax, labels)\n        \"\"\"\n        self.axis_labels = VGroup(\n            self.get_x_axis_label(x_label),\n            self.get_y_axis_label(y_label),\n        )\n        return self.axis_labels\n\n    def plot_line_graph(\n        self,\n        x_values: Iterable[float],\n        y_values: Iterable[float],\n        z_values: Iterable[float] | None = None,\n        line_color: ParsableManimColor = PURE_YELLOW,\n        add_vertex_dots: bool = True,\n        vertex_dot_radius: float = DEFAULT_DOT_RADIUS,\n        vertex_dot_style: dict[str, Any] | None = None,\n        **kwargs: Any,\n    ) -> VDict:\n        \"\"\"Draws a line graph.\n\n        The graph connects the vertices formed from zipping\n        ``x_values``, ``y_values`` and ``z_values``. Also adds :class:`Dots <.Dot>` at the\n        vertices if ``add_vertex_dots`` is set to ``True``.\n\n        Parameters\n        ----------\n        x_values\n            Iterable of values along the x-axis.\n        y_values\n            Iterable of values along the y-axis.\n        z_values\n            Iterable of values (zeros if z_values is None) along the z-axis.\n        line_color\n            Color for the line graph.\n        add_vertex_dots\n            Whether or not to add :class:`~.Dot` at each vertex.\n        vertex_dot_radius\n            Radius for the :class:`~.Dot` at each vertex.\n        vertex_dot_style\n            Style arguments to be passed into :class:`~.Dot` at each vertex.\n        kwargs\n            Additional arguments to be passed into :class:`~.VMobject`.\n\n        Returns\n        -------\n        :class:`~.VDict`\n            A VDict containing both the line and dots (if specified). The line can be accessed with: ``line_graph[\"line_graph\"]``.\n            The dots can be accessed with: ``line_graph[\"vertex_dots\"]``.\n\n        Examples\n        --------\n        .. manim:: LineGraphExample\n            :save_last_frame:\n\n            class LineGraphExample(Scene):\n                def construct(self):\n                    plane = NumberPlane(\n                        x_range = (0, 7),\n                        y_range = (0, 5),\n                        x_length = 7,\n                        axis_config={\"include_numbers\": True},\n                    )\n                    plane.center()\n                    line_graph = plane.plot_line_graph(\n                        x_values = [0, 1.5, 2, 2.8, 4, 6.25],\n                        y_values = [1, 3, 2.25, 4, 2.5, 1.75],\n                        line_color=GOLD_E,\n                        vertex_dot_style=dict(stroke_width=3,  fill_color=PURPLE),\n                        stroke_width = 4,\n                    )\n                    self.add(plane, line_graph)\n        \"\"\"\n        x_values, y_values = map(np.array, (x_values, y_values))\n        if z_values is None:\n            z_values = np.zeros(x_values.shape)\n\n        line_graph = VDict()\n        graph = VGroup(color=line_color, **kwargs)\n\n        vertices = [\n            self.coords_to_point(x, y, z)\n            for x, y, z in zip(x_values, y_values, z_values, strict=True)\n        ]\n        graph.set_points_as_corners(vertices)\n        line_graph[\"line_graph\"] = graph\n\n        if add_vertex_dots:\n            vertex_dot_style = vertex_dot_style or {}\n            vertex_dots = VGroup(\n                *(\n                    Dot(point=vertex, radius=vertex_dot_radius, **vertex_dot_style)\n                    for vertex in vertices\n                )\n            )\n            line_graph[\"vertex_dots\"] = vertex_dots\n\n        return line_graph\n\n    @staticmethod\n    def _origin_shift(axis_range: Sequence[float]) -> float:\n        \"\"\"Determines how to shift graph mobjects to compensate when 0 is not on the axis.\n\n        Parameters\n        ----------\n        axis_range\n            The range of the axis : ``(x_min, x_max, x_step)``.\n        \"\"\"\n        if axis_range[0] > 0:\n            # min greater than 0\n            return axis_range[0]\n        if axis_range[1] < 0:\n            # max less than 0\n            return axis_range[1]\n        else:\n            return 0\n\n\nclass ThreeDAxes(Axes):\n    \"\"\"A 3-dimensional set of axes.\n\n    Parameters\n    ----------\n    x_range\n        The ``[x_min, x_max, x_step]`` values of the x-axis.\n    y_range\n        The ``[y_min, y_max, y_step]`` values of the y-axis.\n    z_range\n        The ``[z_min, z_max, z_step]`` values of the z-axis.\n    x_length\n        The length of the x-axis.\n    y_length\n        The length of the y-axis.\n    z_length\n        The length of the z-axis.\n    z_axis_config\n        Arguments to be passed to :class:`~.NumberLine` that influence the z-axis.\n    z_normal\n        The direction of the normal.\n    num_axis_pieces\n        The number of pieces used to construct the axes.\n    light_source\n        The direction of the light source.\n    depth\n        Currently non-functional.\n    gloss\n        Currently non-functional.\n    kwargs\n        Additional arguments to be passed to :class:`Axes`.\n    \"\"\"\n\n    def __init__(\n        self,\n        x_range: Sequence[float] | None = (-6, 6, 1),\n        y_range: Sequence[float] | None = (-5, 5, 1),\n        z_range: Sequence[float] | None = (-4, 4, 1),\n        x_length: float | None = config.frame_height + 2.5,\n        y_length: float | None = config.frame_height + 2.5,\n        z_length: float | None = config.frame_height - 1.5,\n        z_axis_config: dict[str, Any] | None = None,\n        z_normal: Vector3DLike = DOWN,\n        num_axis_pieces: int = 20,\n        light_source: Point3DLike = 9 * DOWN + 7 * LEFT + 10 * OUT,\n        # opengl stuff (?)\n        depth: Any = None,\n        gloss: float = 0.5,\n        **kwargs: dict[str, Any],\n    ):\n        super().__init__(\n            x_range=x_range,\n            x_length=x_length,\n            y_range=y_range,\n            y_length=y_length,\n            **kwargs,\n        )\n\n        self.z_range = z_range\n        self.z_length = z_length\n\n        self.z_axis_config: dict[str, Any] = {}\n        self._update_default_configs((self.z_axis_config,), (z_axis_config,))\n        self.z_axis_config = merge_dicts_recursively(\n            self.axis_config,\n            self.z_axis_config,\n        )\n\n        self.z_normal = z_normal\n        self.num_axis_pieces = num_axis_pieces\n\n        self.light_source = np.array(light_source)\n\n        self.dimension = 3\n\n        if self.z_axis_config.get(\"scaling\") is None or isinstance(\n            self.z_axis_config.get(\"scaling\"), LinearBase\n        ):\n            self.z_axis_config[\"exclude_origin_tick\"] = True\n        else:\n            self.z_axis_config[\"exclude_origin_tick\"] = False\n\n        z_axis = self._create_axis(self.z_range, self.z_axis_config, self.z_length)\n\n        # [ax.x_min, ax.x_max] used to account for LogBase() scaling\n        # where ax.x_range[0] != ax.x_min\n        z_origin = self._origin_shift([z_axis.x_min, z_axis.x_max])\n\n        z_axis.rotate_about_number(z_origin, -PI / 2, UP)\n        z_axis.rotate_about_number(z_origin, angle_of_vector(self.z_normal))\n        z_axis.shift(-z_axis.number_to_point(z_origin))\n        z_axis.shift(\n            self.x_axis.number_to_point(\n                self._origin_shift([self.x_axis.x_min, self.x_axis.x_max]),\n            ),\n        )\n\n        self.axes.add(z_axis)\n        self.add(z_axis)\n        self.z_axis = z_axis\n\n        if config.renderer == RendererType.CAIRO:\n            self._add_3d_pieces()\n            self._set_axis_shading()\n\n    def _add_3d_pieces(self) -> None:\n        for axis in self.axes:\n            axis.pieces = VGroup(*axis.get_pieces(self.num_axis_pieces))\n            axis.add(axis.pieces)\n            axis.set_stroke(width=0, family=False)\n            axis.set_shade_in_3d(True)\n\n    def _set_axis_shading(self) -> None:\n        def make_func(axis):\n            vect = self.light_source\n            return lambda: (\n                axis.get_edge_center(-vect),\n                axis.get_edge_center(vect),\n            )\n\n        for axis in self:\n            for submob in axis.family_members_with_points():\n                submob.get_gradient_start_and_end_points = make_func(axis)\n                submob.get_unit_normal = lambda a: np.ones(3)\n                submob.set_sheen(0.2)\n\n    def get_y_axis_label(\n        self,\n        label: float | str | VMobject,\n        edge: Vector3DLike = UR,\n        direction: Vector3DLike = UR,\n        buff: float = SMALL_BUFF,\n        rotation: float = PI / 2,\n        rotation_axis: Vector3DLike = OUT,\n        **kwargs: dict[str, Any],\n    ) -> Mobject:\n        \"\"\"Generate a y-axis label.\n\n        Parameters\n        ----------\n        label\n            The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        edge\n            The edge of the y-axis to which the label will be added, by default ``UR``.\n        direction\n            Allows for further positioning of the label from an edge, by default ``UR``.\n        buff\n            The distance of the label from the line, by default ``SMALL_BUFF``.\n        rotation\n            The angle at which to rotate the label, by default ``PI/2``.\n        rotation_axis\n            The axis about which to rotate the label, by default ``OUT``.\n\n        Returns\n        -------\n        :class:`~.Mobject`\n            The positioned label.\n\n        Examples\n        --------\n        .. manim:: GetYAxisLabelExample\n            :save_last_frame:\n\n            class GetYAxisLabelExample(ThreeDScene):\n                def construct(self):\n                    ax = ThreeDAxes()\n                    lab = ax.get_y_axis_label(Tex(\"$y$-label\"))\n                    self.set_camera_orientation(phi=2*PI/5, theta=PI/5)\n                    self.add(ax, lab)\n        \"\"\"\n        positioned_label = self._get_axis_label(\n            label, self.get_y_axis(), edge, direction, buff=buff, **kwargs\n        )\n        positioned_label.rotate(rotation, axis=rotation_axis)\n        return positioned_label\n\n    def get_z_axis_label(\n        self,\n        label: float | str | VMobject,\n        edge: Vector3DLike = OUT,\n        direction: Vector3DLike = RIGHT,\n        buff: float = SMALL_BUFF,\n        rotation: float = PI / 2,\n        rotation_axis: Vector3DLike = RIGHT,\n        **kwargs: Any,\n    ) -> Mobject:\n        \"\"\"Generate a z-axis label.\n\n        Parameters\n        ----------\n        label\n            The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        edge\n            The edge of the z-axis to which the label will be added, by default ``OUT``.\n        direction\n            Allows for further positioning of the label from an edge, by default ``RIGHT``.\n        buff\n            The distance of the label from the line, by default ``SMALL_BUFF``.\n        rotation\n            The angle at which to rotate the label, by default ``PI/2``.\n        rotation_axis\n            The axis about which to rotate the label, by default ``RIGHT``.\n\n        Returns\n        -------\n        :class:`~.Mobject`\n            The positioned label.\n\n        Examples\n        --------\n        .. manim:: GetZAxisLabelExample\n            :save_last_frame:\n\n            class GetZAxisLabelExample(ThreeDScene):\n                def construct(self):\n                    ax = ThreeDAxes()\n                    lab = ax.get_z_axis_label(Tex(\"$z$-label\"))\n                    self.set_camera_orientation(phi=2*PI/5, theta=PI/5)\n                    self.add(ax, lab)\n        \"\"\"\n        positioned_label = self._get_axis_label(\n            label, self.get_z_axis(), edge, direction, buff=buff, **kwargs\n        )\n        positioned_label.rotate(rotation, axis=rotation_axis)\n        return positioned_label\n\n    def get_axis_labels(\n        self,\n        x_label: float | str | VMobject = \"x\",\n        y_label: float | str | VMobject = \"y\",\n        z_label: float | str | VMobject = \"z\",\n    ) -> VGroup:\n        \"\"\"Defines labels for the x_axis and y_axis of the graph.\n\n        For increased control over the position of the labels,\n        use :meth:`~.CoordinateSystem.get_x_axis_label`,\n        :meth:`~.ThreeDAxes.get_y_axis_label`, and\n        :meth:`~.ThreeDAxes.get_z_axis_label`.\n\n        Parameters\n        ----------\n        x_label\n            The label for the x_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        y_label\n            The label for the y_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n        z_label\n            The label for the z_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            A :class:`~.VGroup` of the labels for the x_axis, y_axis, and z_axis.\n\n\n        .. seealso::\n            :meth:`~.CoordinateSystem.get_x_axis_label`\n            :meth:`~.ThreeDAxes.get_y_axis_label`\n            :meth:`~.ThreeDAxes.get_z_axis_label`\n\n        Examples\n        --------\n        .. manim:: GetAxisLabelsExample\n            :save_last_frame:\n\n            class GetAxisLabelsExample(ThreeDScene):\n                def construct(self):\n                    self.set_camera_orientation(phi=2*PI/5, theta=PI/5)\n                    axes = ThreeDAxes()\n                    labels = axes.get_axis_labels(\n                        Text(\"x-axis\").scale(0.7), Text(\"y-axis\").scale(0.45), Text(\"z-axis\").scale(0.45)\n                    )\n                    self.add(axes, labels)\n        \"\"\"\n        self.axis_labels = VGroup(\n            self.get_x_axis_label(x_label),\n            self.get_y_axis_label(y_label),\n            self.get_z_axis_label(z_label),\n        )\n        return self.axis_labels\n\n\nclass NumberPlane(Axes):\n    \"\"\"Creates a cartesian plane with background lines.\n\n    Parameters\n    ----------\n    x_range\n        The ``[x_min, x_max, x_step]`` values of the plane in the horizontal direction.\n    y_range\n        The ``[y_min, y_max, y_step]`` values of the plane in the vertical direction.\n    x_length\n        The width of the plane.\n    y_length\n        The height of the plane.\n    background_line_style\n        Arguments that influence the construction of the background lines of the plane.\n    faded_line_style\n        Similar to :attr:`background_line_style`, affects the construction of the scene's background lines.\n    faded_line_ratio\n        Determines the number of boxes within the background lines: :code:`2` = 4 boxes, :code:`3` = 9 boxes.\n    make_smooth_after_applying_functions\n        Currently non-functional.\n    kwargs\n        Additional arguments to be passed to :class:`Axes`.\n\n\n    .. note::\n        If :attr:`x_length` or :attr:`y_length` are not defined, they are automatically calculated such that\n        one unit on each axis is one Manim unit long.\n\n    Examples\n    --------\n    .. manim:: NumberPlaneExample\n        :save_last_frame:\n\n        class NumberPlaneExample(Scene):\n            def construct(self):\n                number_plane = NumberPlane(\n                    background_line_style={\n                        \"stroke_color\": TEAL,\n                        \"stroke_width\": 4,\n                        \"stroke_opacity\": 0.6\n                    }\n                )\n                self.add(number_plane)\n\n    .. manim:: NumberPlaneScaled\n        :save_last_frame:\n\n        class NumberPlaneScaled(Scene):\n            def construct(self):\n                number_plane = NumberPlane(\n                    x_range=(-4, 11, 1),\n                    y_range=(-3, 3, 1),\n                    x_length=5,\n                    y_length=2,\n                ).move_to(LEFT*3)\n\n                number_plane_scaled_y = NumberPlane(\n                    x_range=(-4, 11, 1),\n                    x_length=5,\n                    y_length=4,\n                ).move_to(RIGHT*3)\n\n                self.add(number_plane)\n                self.add(number_plane_scaled_y)\n    \"\"\"\n\n    def __init__(\n        self,\n        x_range: Sequence[float] | None = (\n            -config[\"frame_x_radius\"],\n            config[\"frame_x_radius\"],\n            1,\n        ),\n        y_range: Sequence[float] | None = (\n            -config[\"frame_y_radius\"],\n            config[\"frame_y_radius\"],\n            1,\n        ),\n        x_length: float | None = None,\n        y_length: float | None = None,\n        background_line_style: dict[str, Any] | None = None,\n        faded_line_style: dict[str, Any] | None = None,\n        faded_line_ratio: int = 1,\n        make_smooth_after_applying_functions: bool = True,\n        **kwargs: dict[str, Any],\n    ):\n        # configs\n        self.axis_config: dict[str, Any] = {\n            \"stroke_width\": 2,\n            \"include_ticks\": False,\n            \"include_tip\": False,\n            \"line_to_number_buff\": SMALL_BUFF,\n            \"label_direction\": DR,\n            \"font_size\": 24,\n        }\n        self.y_axis_config: dict[str, Any] = {\"label_direction\": DR}\n        self.background_line_style: dict[str, Any] = {\n            \"stroke_color\": BLUE_D,\n            \"stroke_width\": 2,\n            \"stroke_opacity\": 1,\n        }\n\n        self._update_default_configs(\n            (self.axis_config, self.y_axis_config, self.background_line_style),\n            (\n                kwargs.pop(\"axis_config\", None),\n                kwargs.pop(\"y_axis_config\", None),\n                background_line_style,\n            ),\n        )\n\n        # Defaults to a faded version of line_config\n        self.faded_line_style = faded_line_style\n        self.faded_line_ratio = faded_line_ratio\n        self.make_smooth_after_applying_functions = make_smooth_after_applying_functions\n\n        # init\n        super().__init__(\n            x_range=x_range,\n            y_range=y_range,\n            x_length=x_length,\n            y_length=y_length,\n            axis_config=self.axis_config,\n            y_axis_config=self.y_axis_config,\n            **kwargs,\n        )\n\n        self._init_background_lines()\n\n    def _init_background_lines(self) -> None:\n        \"\"\"Will init all the lines of NumberPlanes (faded or not)\"\"\"\n        if self.faded_line_style is None:\n            style = dict(self.background_line_style)\n            # For anything numerical, like stroke_width\n            # and stroke_opacity, chop it in half\n            for key in style:\n                if isinstance(style[key], numbers.Number):\n                    style[key] *= 0.5\n            self.faded_line_style = style\n\n        self.background_lines, self.faded_lines = self._get_lines()\n\n        self.background_lines.set_style(\n            **self.background_line_style,\n        )\n        self.faded_lines.set_style(\n            **self.faded_line_style,\n        )\n        self.add_to_back(\n            self.faded_lines,\n            self.background_lines,\n        )\n\n    def _get_lines(self) -> tuple[VGroup, VGroup]:\n        \"\"\"Generate all the lines, faded and not faded.\n         Two sets of lines are generated: one parallel to the X-axis, and parallel to the Y-axis.\n\n        Returns\n        -------\n        Tuple[:class:`~.VGroup`, :class:`~.VGroup`]\n            The first (i.e the non faded lines) and second (i.e the faded lines) sets of lines, respectively.\n        \"\"\"\n        x_axis = self.get_x_axis()\n        y_axis = self.get_y_axis()\n\n        x_lines1, x_lines2 = self._get_lines_parallel_to_axis(\n            x_axis,\n            y_axis,\n            self.y_axis.x_range[2],\n            self.faded_line_ratio,\n        )\n\n        y_lines1, y_lines2 = self._get_lines_parallel_to_axis(\n            y_axis,\n            x_axis,\n            self.x_axis.x_range[2],\n            self.faded_line_ratio,\n        )\n\n        # TODO this was added so that we can run tests on NumberPlane\n        # In the future these attributes will be tacked onto self.background_lines\n        self.x_lines = x_lines1\n        self.y_lines = y_lines1\n        lines1 = VGroup(*x_lines1, *y_lines1)\n        lines2 = VGroup(*x_lines2, *y_lines2)\n\n        return lines1, lines2\n\n    def _get_lines_parallel_to_axis(\n        self,\n        axis_parallel_to: NumberLine,\n        axis_perpendicular_to: NumberLine,\n        freq: float,\n        ratio_faded_lines: int,\n    ) -> tuple[VGroup, VGroup]:\n        \"\"\"Generate a set of lines parallel to an axis.\n\n        Parameters\n        ----------\n        axis_parallel_to\n            The axis with which the lines will be parallel.\n        axis_perpendicular_to\n            The axis with which the lines will be perpendicular.\n        ratio_faded_lines\n            The ratio between the space between faded lines and the space between non-faded lines.\n        freq\n            Frequency of non-faded lines (number of non-faded lines per graph unit).\n\n        Returns\n        -------\n        Tuple[:class:`~.VGroup`, :class:`~.VGroup`]\n            The first (i.e the non-faded lines parallel to `axis_parallel_to`) and second\n             (i.e the faded lines parallel to `axis_parallel_to`) sets of lines, respectively.\n        \"\"\"\n        line = Line(axis_parallel_to.get_start(), axis_parallel_to.get_end())\n        if ratio_faded_lines == 0:  # don't show faded lines\n            ratio_faded_lines = 1  # i.e. set ratio to 1\n        step = (1 / ratio_faded_lines) * freq\n        lines1 = VGroup()\n        lines2 = VGroup()\n        unit_vector_axis_perp_to = axis_perpendicular_to.get_unit_vector()\n\n        # need to unpack all three values\n        x_min, x_max, _ = axis_perpendicular_to.x_range\n\n        # account for different axis scalings (logarithmic), where\n        # negative values do not exist and [-2 , 4] should output lines\n        # similar to [0, 6]\n        if axis_perpendicular_to.x_min > 0 and x_min < 0:\n            x_min, x_max = (0, np.abs(x_min) + np.abs(x_max))\n\n        # min/max used in case range does not include 0. i.e. if (2,6):\n        # the range becomes (0,4), not (0,6).\n        ranges = (\n            [0],\n            np.arange(step, min(x_max - x_min, x_max), step),\n            np.arange(-step, max(x_min - x_max, x_min), -step),\n        )\n\n        for inputs in ranges:\n            for k, x in enumerate(inputs):\n                new_line = line.copy()\n                new_line.shift(unit_vector_axis_perp_to * x)\n                if (k + 1) % ratio_faded_lines == 0:\n                    lines1.add(new_line)\n                else:\n                    lines2.add(new_line)\n        return lines1, lines2\n\n    def get_vector(self, coords: Sequence[ManimFloat], **kwargs: Any) -> Arrow:\n        kwargs[\"buff\"] = 0\n        return Arrow(\n            self.coords_to_point(0, 0), self.coords_to_point(*coords), **kwargs\n        )\n\n    def prepare_for_nonlinear_transform(self, num_inserted_curves: int = 50) -> Self:\n        for mob in self.family_members_with_points():\n            num_curves = mob.get_num_curves()\n            if num_inserted_curves > num_curves:\n                mob.insert_n_curves(num_inserted_curves - num_curves)\n        return self\n\n\nclass PolarPlane(Axes):\n    r\"\"\"Creates a polar plane with background lines.\n\n    Parameters\n    ----------\n    azimuth_step\n        The number of divisions in the azimuth (also known as the `angular coordinate` or `polar angle`). If ``None`` is specified then it will use the default\n        specified by ``azimuth_units``:\n\n        - ``\"PI radians\"`` or ``\"TAU radians\"``: 20\n        - ``\"degrees\"``: 36\n        - ``\"gradians\"``: 40\n        - ``None``: 1\n\n        A non-integer value will result in a partial division at the end of the circle.\n\n    size\n        The diameter of the plane.\n\n    radius_step\n        The distance between faded radius lines.\n\n    radius_max\n        The maximum value of the radius.\n\n    azimuth_units\n        Specifies a default labelling system for the azimuth. Choices are:\n\n        - ``\"PI radians\"``: Fractional labels in the interval :math:`\\left[0, 2\\pi\\right]` with :math:`\\pi` as a constant.\n        - ``\"TAU radians\"``: Fractional labels in the interval :math:`\\left[0, \\tau\\right]` (where :math:`\\tau = 2\\pi`) with :math:`\\tau` as a constant.\n        - ``\"degrees\"``: Decimal labels in the interval :math:`\\left[0, 360\\right]` with a degree (:math:`^{\\circ}`) symbol.\n        - ``\"gradians\"``: Decimal labels in the interval :math:`\\left[0, 400\\right]` with a superscript \"g\" (:math:`^{g}`).\n        - ``None``: Decimal labels in the interval :math:`\\left[0, 1\\right]`.\n\n    azimuth_compact_fraction\n        If the ``azimuth_units`` choice has fractional labels, choose whether to\n        combine the constant in a compact form :math:`\\tfrac{xu}{y}` as opposed to\n        :math:`\\tfrac{x}{y}u`, where :math:`u` is the constant.\n\n    azimuth_offset\n        The angle offset of the azimuth, expressed in radians.\n\n    azimuth_direction\n        The direction of the azimuth.\n\n        - ``\"CW\"``: Clockwise.\n        - ``\"CCW\"``: Anti-clockwise.\n\n    azimuth_label_buff\n        The buffer for the azimuth labels.\n\n    azimuth_label_font_size\n        The font size of the azimuth labels.\n\n    radius_config\n        The axis config for the radius.\n\n    Examples\n    --------\n    .. manim:: PolarPlaneExample\n        :ref_classes: PolarPlane\n        :save_last_frame:\n\n        class PolarPlaneExample(Scene):\n            def construct(self):\n                polarplane_pi = PolarPlane(\n                    azimuth_units=\"PI radians\",\n                    size=6,\n                    azimuth_label_font_size=33.6,\n                    radius_config={\"font_size\": 33.6},\n                ).add_coordinates()\n                self.add(polarplane_pi)\n    \"\"\"\n\n    def __init__(\n        self,\n        radius_max: float = config[\"frame_y_radius\"],\n        size: float | None = None,\n        radius_step: float = 1,\n        azimuth_step: float | None = None,\n        azimuth_units: str = \"PI radians\",\n        azimuth_compact_fraction: bool = True,\n        azimuth_offset: float = 0,\n        azimuth_direction: str = \"CCW\",\n        azimuth_label_buff: float = SMALL_BUFF,\n        azimuth_label_font_size: float = 24,\n        radius_config: dict[str, Any] | None = None,\n        background_line_style: dict[str, Any] | None = None,\n        faded_line_style: dict[str, Any] | None = None,\n        faded_line_ratio: int = 1,\n        make_smooth_after_applying_functions: bool = True,\n        **kwargs: Any,\n    ):\n        # error catching\n        if azimuth_units in [\"PI radians\", \"TAU radians\", \"degrees\", \"gradians\", None]:\n            self.azimuth_units = azimuth_units\n        else:\n            raise ValueError(\n                \"Invalid azimuth units. Expected one of: PI radians, TAU radians, degrees, gradians or None.\",\n            )\n\n        if azimuth_direction in [\"CW\", \"CCW\"]:\n            self.azimuth_direction = azimuth_direction\n        else:\n            raise ValueError(\"Invalid azimuth units. Expected one of: CW, CCW.\")\n\n        # configs\n        self.radius_config = {\n            \"stroke_width\": 2,\n            \"include_ticks\": False,\n            \"include_tip\": False,\n            \"line_to_number_buff\": SMALL_BUFF,\n            \"label_direction\": DL,\n            \"font_size\": 24,\n        }\n\n        self.background_line_style = {\n            \"stroke_color\": BLUE_D,\n            \"stroke_width\": 2,\n            \"stroke_opacity\": 1,\n        }\n\n        self.azimuth_step = (\n            (\n                {\n                    \"PI radians\": 20,\n                    \"TAU radians\": 20,\n                    \"degrees\": 36,\n                    \"gradians\": 40,\n                    None: 1,\n                }[azimuth_units]\n            )\n            if azimuth_step is None\n            else azimuth_step\n        )\n\n        self._update_default_configs(\n            (self.radius_config, self.background_line_style),\n            (radius_config, background_line_style),\n        )\n\n        # Defaults to a faded version of line_config\n        self.faded_line_style = faded_line_style\n        self.faded_line_ratio = faded_line_ratio\n        self.make_smooth_after_applying_functions = make_smooth_after_applying_functions\n        self.azimuth_offset = azimuth_offset\n        self.azimuth_label_buff = azimuth_label_buff\n        self.azimuth_label_font_size = azimuth_label_font_size\n        self.azimuth_compact_fraction = azimuth_compact_fraction\n\n        # init\n\n        super().__init__(\n            x_range=np.array((-radius_max, radius_max, radius_step)),\n            y_range=np.array((-radius_max, radius_max, radius_step)),\n            x_length=size,\n            y_length=size,\n            axis_config=self.radius_config,\n            **kwargs,\n        )\n\n        self._init_background_lines()\n\n    def _init_background_lines(self) -> None:\n        \"\"\"Will init all the lines of NumberPlanes (faded or not)\"\"\"\n        if self.faded_line_style is None:\n            style = dict(self.background_line_style)\n            # For anything numerical, like stroke_width\n            # and stroke_opacity, chop it in half\n            for key in style:\n                if isinstance(style[key], numbers.Number):\n                    style[key] *= 0.5\n            self.faded_line_style = style\n\n        self.background_lines, self.faded_lines = self._get_lines()\n        self.background_lines.set_style(\n            **self.background_line_style,\n        )\n        self.faded_lines.set_style(\n            **self.faded_line_style,\n        )\n        self.add_to_back(\n            self.faded_lines,\n            self.background_lines,\n        )\n\n    def _get_lines(self) -> tuple[VGroup, VGroup]:\n        \"\"\"Generate all the lines and circles, faded and not faded.\n\n        Returns\n        -------\n        Tuple[:class:`~.VGroup`, :class:`~.VGroup`]\n            The first (i.e the non faded lines and circles) and second (i.e the faded lines and circles) sets of lines and circles, respectively.\n        \"\"\"\n        center = self.get_origin()\n        ratio_faded_lines = self.faded_line_ratio\n        offset = self.azimuth_offset\n\n        if ratio_faded_lines == 0:  # don't show faded lines\n            ratio_faded_lines = 1  # i.e. set ratio to 1\n        rstep = (1 / ratio_faded_lines) * self.x_axis.x_range[2]\n        astep = (1 / ratio_faded_lines) * (TAU * (1 / self.azimuth_step))\n        rlines1 = VGroup()\n        rlines2 = VGroup()\n        alines1 = VGroup()\n        alines2 = VGroup()\n\n        rinput = np.arange(0, self.x_axis.x_range[1] + rstep, rstep)\n        ainput = np.arange(0, TAU, astep)\n\n        unit_vector = self.x_axis.get_unit_vector()[0]\n\n        for k, x in enumerate(rinput):\n            new_circle = Circle(radius=x * unit_vector)\n            if k % ratio_faded_lines == 0:\n                alines1.add(new_circle)\n            else:\n                alines2.add(new_circle)\n\n        line = Line(center, self.get_x_axis().get_end())\n\n        for k, x in enumerate(ainput):\n            new_line = line.copy()\n            new_line.rotate(x + offset, about_point=center)\n            if k % ratio_faded_lines == 0:\n                rlines1.add(new_line)\n            else:\n                rlines2.add(new_line)\n\n        lines1 = VGroup(*rlines1, *alines1)\n        lines2 = VGroup(*rlines2, *alines2)\n        return lines1, lines2\n\n    def get_axes(self) -> VGroup:\n        \"\"\"Gets the axes.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            A pair of axes.\n        \"\"\"\n        return self.axes\n\n    def get_vector(self, coords: Sequence[ManimFloat], **kwargs: Any) -> Arrow:\n        kwargs[\"buff\"] = 0\n        return Arrow(\n            self.coords_to_point(0, 0), self.coords_to_point(*coords), **kwargs\n        )\n\n    def prepare_for_nonlinear_transform(self, num_inserted_curves: int = 50) -> Self:\n        for mob in self.family_members_with_points():\n            num_curves = mob.get_num_curves()\n            if num_inserted_curves > num_curves:\n                mob.insert_n_curves(num_inserted_curves - num_curves)\n        return self\n\n    def get_coordinate_labels(\n        self,\n        r_values: Iterable[float] | None = None,\n        a_values: Iterable[float] | None = None,\n        **kwargs: Any,\n    ) -> VDict:\n        \"\"\"Gets labels for the coordinates\n\n        Parameters\n        ----------\n        r_values\n            Iterable of values along the radius, by default None.\n        a_values\n            Iterable of values along the azimuth, by default None.\n\n        Returns\n        -------\n        VDict\n            Labels for the radius and azimuth values.\n        \"\"\"\n        if r_values is None:\n            r_values = [r for r in self.get_x_axis().get_tick_range() if r >= 0]\n        if a_values is None:\n            a_values = np.arange(0, 1, 1 / self.azimuth_step)\n        r_mobs = self.get_x_axis().add_numbers(r_values)\n        if self.azimuth_direction == \"CCW\":\n            d = 1\n        elif self.azimuth_direction == \"CW\":\n            d = -1\n        else:\n            raise ValueError(\"Invalid azimuth direction. Expected one of: CW, CCW\")\n        a_points = [\n            {\n                \"label\": i,\n                \"point\": np.array(\n                    [\n                        self.get_right()[0]\n                        * np.cos(d * (i * TAU) + self.azimuth_offset),\n                        self.get_right()[0]\n                        * np.sin(d * (i * TAU) + self.azimuth_offset),\n                        0,\n                    ],\n                ),\n            }\n            for i in a_values\n        ]\n        a_tex = []\n        if self.azimuth_units == \"PI radians\" or self.azimuth_units == \"TAU radians\":\n            a_tex = [\n                self.get_radian_label(\n                    i[\"label\"],\n                    font_size=self.azimuth_label_font_size,\n                ).next_to(\n                    i[\"point\"],\n                    direction=i[\"point\"],\n                    aligned_edge=i[\"point\"],\n                    buff=self.azimuth_label_buff,\n                )\n                for i in a_points\n            ]\n        elif self.azimuth_units == \"degrees\":\n            a_tex = [\n                MathTex(\n                    f\"{360 * i['label']:g}\" + r\"^{\\circ}\",\n                    font_size=self.azimuth_label_font_size,\n                ).next_to(\n                    i[\"point\"],\n                    direction=i[\"point\"],\n                    aligned_edge=i[\"point\"],\n                    buff=self.azimuth_label_buff,\n                )\n                for i in a_points\n            ]\n        elif self.azimuth_units == \"gradians\":\n            a_tex = [\n                MathTex(\n                    f\"{400 * i['label']:g}\" + r\"^{g}\",\n                    font_size=self.azimuth_label_font_size,\n                ).next_to(\n                    i[\"point\"],\n                    direction=i[\"point\"],\n                    aligned_edge=i[\"point\"],\n                    buff=self.azimuth_label_buff,\n                )\n                for i in a_points\n            ]\n        elif self.azimuth_units is None:\n            a_tex = [\n                MathTex(\n                    f\"{i['label']:g}\",\n                    font_size=self.azimuth_label_font_size,\n                ).next_to(\n                    i[\"point\"],\n                    direction=i[\"point\"],\n                    aligned_edge=i[\"point\"],\n                    buff=self.azimuth_label_buff,\n                )\n                for i in a_points\n            ]\n        a_mobs = VGroup(*a_tex)\n        self.coordinate_labels = VGroup(r_mobs, a_mobs)\n        return self.coordinate_labels\n\n    def add_coordinates(\n        self,\n        r_values: Iterable[float] | None = None,\n        a_values: Iterable[float] | None = None,\n    ) -> Self:\n        \"\"\"Adds the coordinates.\n\n        Parameters\n        ----------\n        r_values\n            Iterable of values along the radius, by default None.\n        a_values\n            Iterable of values along the azimuth, by default None.\n        \"\"\"\n        self.add(self.get_coordinate_labels(r_values, a_values))\n        return self\n\n    def get_radian_label(\n        self, number: float, font_size: float = 24, **kwargs: Any\n    ) -> MathTex:\n        constant_label = {\"PI radians\": r\"\\pi\", \"TAU radians\": r\"\\tau\"}[\n            self.azimuth_units\n        ]\n        division = number * {\"PI radians\": 2, \"TAU radians\": 1}[self.azimuth_units]\n        frac = fr.Fraction(division).limit_denominator(max_denominator=100)\n        if frac.numerator == 0 & frac.denominator == 0:\n            string = r\"0\"\n        elif frac.numerator == 1 and frac.denominator == 1:\n            string = constant_label\n        elif frac.numerator == 1:\n            if self.azimuth_compact_fraction:\n                string = (\n                    r\"\\tfrac{\" + constant_label + r\"}{\" + str(frac.denominator) + \"}\"\n                )\n            else:\n                string = r\"\\tfrac{1}{\" + str(frac.denominator) + \"}\" + constant_label\n        elif frac.denominator == 1:\n            string = str(frac.numerator) + constant_label\n\n        else:\n            if self.azimuth_compact_fraction:\n                string = (\n                    r\"\\tfrac{\"\n                    + str(frac.numerator)\n                    + constant_label\n                    + r\"}{\"\n                    + str(frac.denominator)\n                    + r\"}\"\n                )\n            else:\n                string = (\n                    r\"\\tfrac{\"\n                    + str(frac.numerator)\n                    + r\"}{\"\n                    + str(frac.denominator)\n                    + r\"}\"\n                    + constant_label\n                )\n\n        return MathTex(string, font_size=font_size, **kwargs)\n\n\nclass ComplexPlane(NumberPlane):\n    \"\"\"A :class:`~.NumberPlane` specialized for use with complex numbers.\n\n    Examples\n    --------\n    .. manim:: ComplexPlaneExample\n        :save_last_frame:\n        :ref_classes: Dot MathTex\n\n        class ComplexPlaneExample(Scene):\n            def construct(self):\n                plane = ComplexPlane().add_coordinates()\n                self.add(plane)\n                d1 = Dot(plane.n2p(2 + 1j), color=YELLOW)\n                d2 = Dot(plane.n2p(-3 - 2j), color=YELLOW)\n                label1 = MathTex(\"2+i\").next_to(d1, UR, 0.1)\n                label2 = MathTex(\"-3-2i\").next_to(d2, UR, 0.1)\n                self.add(\n                    d1,\n                    label1,\n                    d2,\n                    label2,\n                )\n\n    \"\"\"\n\n    def __init__(self, **kwargs: Any):\n        super().__init__(\n            **kwargs,\n        )\n\n    def number_to_point(self, number: float | complex) -> np.ndarray:\n        \"\"\"Accepts a float/complex number and returns the equivalent point on the plane.\n\n        Parameters\n        ----------\n        number\n            The number. Can be a float or a complex number.\n\n        Returns\n        -------\n        np.ndarray\n            The point on the plane.\n        \"\"\"\n        number = complex(number)\n        return self.coords_to_point(number.real, number.imag)\n\n    def n2p(self, number: float | complex) -> np.ndarray:\n        \"\"\"Abbreviation for :meth:`number_to_point`.\"\"\"\n        return self.number_to_point(number)\n\n    def point_to_number(self, point: Point3DLike) -> complex:\n        \"\"\"Accepts a point and returns a complex number equivalent to that point on the plane.\n\n        Parameters\n        ----------\n        point\n            The point in manim's coordinate-system\n\n        Returns\n        -------\n        complex\n            A complex number consisting of real and imaginary components.\n        \"\"\"\n        x, y = self.point_to_coords(point)\n        return complex(x, y)\n\n    def p2n(self, point: Point3DLike) -> complex:\n        \"\"\"Abbreviation for :meth:`point_to_number`.\"\"\"\n        return self.point_to_number(point)\n\n    def _get_default_coordinate_values(self) -> list[float | complex]:\n        \"\"\"Generate a list containing the numerical values of the plane's labels.\n\n        Returns\n        -------\n        List[float | complex]\n            A list of floats representing the x-axis and complex numbers representing the y-axis.\n        \"\"\"\n        x_numbers = self.get_x_axis().get_tick_range()\n        y_numbers = self.get_y_axis().get_tick_range()\n        y_numbers = [complex(0, y) for y in y_numbers if y != 0]\n        return [*x_numbers, *y_numbers]\n\n    def get_coordinate_labels(\n        self, *numbers: Iterable[float | complex], **kwargs: Any\n    ) -> VGroup:\n        \"\"\"Generates the :class:`~.DecimalNumber` mobjects for the coordinates of the plane.\n\n        Parameters\n        ----------\n        numbers\n            An iterable of floats/complex numbers. Floats are positioned along the x-axis, complex numbers along the y-axis.\n        kwargs\n            Additional arguments to be passed to :meth:`~.NumberLine.get_number_mobject`, i.e. :class:`~.DecimalNumber`.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            A :class:`~.VGroup` containing the positioned label mobjects.\n        \"\"\"\n        # TODO: Make this work the same as coord_sys.add_coordinates()\n        if len(numbers) == 0:\n            numbers = self._get_default_coordinate_values()\n\n        self.coordinate_labels = VGroup()\n        for number in numbers:\n            z = complex(number)\n            if abs(z.imag) > abs(z.real):\n                axis = self.get_y_axis()\n                value = z.imag\n                kwargs[\"unit\"] = \"i\"\n            else:\n                axis = self.get_x_axis()\n                value = z.real\n            number_mob = axis.get_number_mobject(value, **kwargs)\n            self.coordinate_labels.add(number_mob)\n        return self.coordinate_labels\n\n    def add_coordinates(\n        self, *numbers: Iterable[float | complex], **kwargs: Any\n    ) -> Self:\n        \"\"\"Adds the labels produced from :meth:`~.NumberPlane.get_coordinate_labels` to the plane.\n\n        Parameters\n        ----------\n        numbers\n            An iterable of floats/complex numbers. Floats are positioned along the x-axis, complex numbers along the y-axis.\n        kwargs\n            Additional arguments to be passed to :meth:`~.NumberLine.get_number_mobject`, i.e. :class:`~.DecimalNumber`.\n        \"\"\"\n        self.add(self.get_coordinate_labels(*numbers, **kwargs))\n        return self\n"
  },
  {
    "path": "manim/mobject/graphing/functions.py",
    "content": "\"\"\"Mobjects representing function graphs.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"ParametricFunction\", \"FunctionGraph\", \"ImplicitFunction\"]\n\n\nfrom collections.abc import Callable, Iterable, Sequence\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\nfrom isosurfaces import plot_isoline\n\nfrom manim import config\nfrom manim.mobject.graphing.scale import LinearBase, _ScaleBase\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.types.vectorized_mobject import VMobject\n\nif TYPE_CHECKING:\n    from typing import Any, Self\n\n    from manim.typing import Point3D, Point3DLike\n    from manim.utils.color import ParsableManimColor\n\nfrom manim.utils.color import PURE_YELLOW\n\n\nclass ParametricFunction(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A parametric curve.\n\n    Parameters\n    ----------\n    function\n        The function to be plotted in the form of ``(lambda t: (x(t), y(t), z(t)))``\n    t_range\n        Determines the length that the function spans in the form of (t_min, t_max, step=0.01). By default ``[0, 1]``\n    scaling\n        Scaling class applied to the points of the function. Default of :class:`~.LinearBase`.\n    use_smoothing\n        Whether to interpolate between the points of the function after they have been created.\n        (Will have odd behaviour with a low number of points)\n    use_vectorized\n        Whether to pass in the generated t value array to the function as ``[t_0, t_1, ...]``.\n        Only use this if your function supports it. Output should be a numpy array\n        of shape ``[[x_0, x_1, ...], [y_0, y_1, ...], [z_0, z_1, ...]]`` but ``z`` can\n        also be 0 if the Axes is 2D\n    discontinuities\n        Values of t at which the function experiences discontinuity.\n    dt\n        The left and right tolerance for the discontinuities.\n\n\n    Examples\n    --------\n    .. manim:: PlotParametricFunction\n        :save_last_frame:\n\n        class PlotParametricFunction(Scene):\n            def func(self, t):\n                return (np.sin(2 * t), np.sin(3 * t), 0)\n\n            def construct(self):\n                func = ParametricFunction(self.func, t_range = (0, TAU), fill_opacity=0).set_color(RED)\n                self.add(func.scale(3))\n\n    .. manim:: ThreeDParametricSpring\n        :save_last_frame:\n\n        class ThreeDParametricSpring(ThreeDScene):\n            def construct(self):\n                curve1 = ParametricFunction(\n                    lambda u: (\n                        1.2 * np.cos(u),\n                        1.2 * np.sin(u),\n                        u * 0.05\n                    ), color=RED, t_range = (-3*TAU, 5*TAU, 0.01)\n                ).set_shade_in_3d(True)\n                axes = ThreeDAxes()\n                self.add(axes, curve1)\n                self.set_camera_orientation(phi=80 * DEGREES, theta=-60 * DEGREES)\n                self.wait()\n\n    .. attention::\n        If your function has discontinuities, you'll have to specify the location\n        of the discontinuities manually. See the following example for guidance.\n\n    .. manim:: DiscontinuousExample\n        :save_last_frame:\n\n        class DiscontinuousExample(Scene):\n            def construct(self):\n                ax1 = NumberPlane((-3, 3), (-4, 4))\n                ax2 = NumberPlane((-3, 3), (-4, 4))\n                VGroup(ax1, ax2).arrange()\n                discontinuous_function = lambda x: (x ** 2 - 2) / (x ** 2 - 4)\n                incorrect = ax1.plot(discontinuous_function, color=RED)\n                correct = ax2.plot(\n                    discontinuous_function,\n                    discontinuities=[-2, 2],  # discontinuous points\n                    dt=0.1,  # left and right tolerance of discontinuity\n                    color=GREEN,\n                )\n                self.add(ax1, ax2, incorrect, correct)\n    \"\"\"\n\n    def __init__(\n        self,\n        function: Callable[[float], Point3DLike],\n        t_range: tuple[float, float] | tuple[float, float, float] = (0, 1),\n        scaling: _ScaleBase = LinearBase(),\n        dt: float = 1e-8,\n        discontinuities: Iterable[float] | None = None,\n        use_smoothing: bool = True,\n        use_vectorized: bool = False,\n        **kwargs: Any,\n    ):\n        def internal_parametric_function(t: float) -> Point3D:\n            \"\"\"Wrap ``function``'s output inside a NumPy array.\"\"\"\n            return np.asarray(function(t))\n\n        self.function = internal_parametric_function\n        if len(t_range) == 2:\n            t_range = (*t_range, 0.01)\n\n        self.scaling = scaling\n\n        self.dt = dt\n        self.discontinuities = discontinuities\n        self.use_smoothing = use_smoothing\n        self.use_vectorized = use_vectorized\n        self.t_min, self.t_max, self.t_step = t_range\n\n        super().__init__(**kwargs)\n\n    def get_function(self) -> Callable[[float], Point3D]:\n        return self.function\n\n    def get_point_from_function(self, t: float) -> Point3D:\n        return self.function(t)\n\n    def generate_points(self) -> Self:\n        if self.discontinuities is not None:\n            discontinuities = filter(\n                lambda t: self.t_min <= t <= self.t_max,\n                self.discontinuities,\n            )\n            discontinuities_array = np.array(list(discontinuities))\n            boundary_times = np.array(\n                [\n                    self.t_min,\n                    self.t_max,\n                    *(discontinuities_array - self.dt),\n                    *(discontinuities_array + self.dt),\n                ],\n            )\n            boundary_times.sort()\n        else:\n            boundary_times = [self.t_min, self.t_max]\n\n        for t1, t2 in zip(boundary_times[0::2], boundary_times[1::2], strict=True):\n            t_range = np.array(\n                [\n                    *self.scaling.function(np.arange(t1, t2, self.t_step)),\n                    self.scaling.function(t2),\n                ],\n            )\n\n            if self.use_vectorized:\n                x, y, z = self.function(t_range)\n                if not isinstance(z, np.ndarray):\n                    z = np.zeros_like(x)\n                points = np.stack([x, y, z], axis=1)\n            else:\n                points = np.array([self.function(t) for t in t_range])\n\n            self.start_new_path(points[0])\n            self.add_points_as_corners(points[1:])\n        if self.use_smoothing:\n            # TODO: not in line with upstream, approx_smooth does not exist\n            self.make_smooth()\n        return self\n\n    def init_points(self) -> None:\n        self.generate_points()\n\n\nclass FunctionGraph(ParametricFunction):\n    \"\"\"A :class:`ParametricFunction` that spans the length of the scene by default.\n\n    Examples\n    --------\n    .. manim:: ExampleFunctionGraph\n        :save_last_frame:\n\n        class ExampleFunctionGraph(Scene):\n            def construct(self):\n                cos_func = FunctionGraph(\n                    lambda t: np.cos(t) + 0.5 * np.cos(7 * t) + (1 / 7) * np.cos(14 * t),\n                    color=RED,\n                )\n\n                sin_func_1 = FunctionGraph(\n                    lambda t: np.sin(t) + 0.5 * np.sin(7 * t) + (1 / 7) * np.sin(14 * t),\n                    color=BLUE,\n                )\n\n                sin_func_2 = FunctionGraph(\n                    lambda t: np.sin(t) + 0.5 * np.sin(7 * t) + (1 / 7) * np.sin(14 * t),\n                    x_range=[-4, 4],\n                    color=GREEN,\n                ).move_to([0, 1, 0])\n\n                self.add(cos_func, sin_func_1, sin_func_2)\n    \"\"\"\n\n    def __init__(\n        self,\n        function: Callable[[float], Any],\n        x_range: tuple[float, float] | tuple[float, float, float] | None = None,\n        color: ParsableManimColor = PURE_YELLOW,\n        **kwargs: Any,\n    ) -> None:\n        if x_range is None:\n            x_range = (-config[\"frame_x_radius\"], config[\"frame_x_radius\"])\n\n        self.x_range = x_range\n        self.parametric_function: Callable[[float], Point3D] = lambda t: np.array(\n            [t, function(t), 0]\n        )\n        self.function = function  # type: ignore[assignment]\n        super().__init__(self.parametric_function, self.x_range, color=color, **kwargs)\n\n    def get_function(self) -> Callable[[float], Any]:\n        return self.function\n\n    def get_point_from_function(self, x: float) -> Point3D:\n        return self.parametric_function(x)\n\n\nclass ImplicitFunction(VMobject, metaclass=ConvertToOpenGL):\n    def __init__(\n        self,\n        func: Callable[[float, float], float],\n        x_range: Sequence[float] | None = None,\n        y_range: Sequence[float] | None = None,\n        min_depth: int = 5,\n        max_quads: int = 1500,\n        use_smoothing: bool = True,\n        **kwargs: Any,\n    ):\n        \"\"\"An implicit function.\n\n        Parameters\n        ----------\n        func\n            The implicit function in the form ``f(x, y) = 0``.\n        x_range\n            The x min and max of the function.\n        y_range\n            The y min and max of the function.\n        min_depth\n            The minimum depth of the function to calculate.\n        max_quads\n            The maximum number of quads to use.\n        use_smoothing\n            Whether or not to smoothen the curves.\n        kwargs\n            Additional parameters to pass into :class:`VMobject`\n\n\n        .. note::\n            A small ``min_depth`` :math:`d` means that some small details might\n            be ignored if they don't cross an edge of one of the\n            :math:`4^d` uniform quads.\n\n            The value of ``max_quads`` strongly corresponds to the\n            quality of the curve, but a higher number of quads\n            may take longer to render.\n\n        Examples\n        --------\n        .. manim:: ImplicitFunctionExample\n            :save_last_frame:\n\n            class ImplicitFunctionExample(Scene):\n                def construct(self):\n                    graph = ImplicitFunction(\n                        lambda x, y: x * y ** 2 - x ** 2 * y - 2,\n                        color=YELLOW\n                    )\n                    self.add(NumberPlane(), graph)\n        \"\"\"\n        self.function = func\n        self.min_depth = min_depth\n        self.max_quads = max_quads\n        self.use_smoothing = use_smoothing\n        self.x_range = x_range or [\n            -config.frame_width / 2,\n            config.frame_width / 2,\n        ]\n        self.y_range = y_range or [\n            -config.frame_height / 2,\n            config.frame_height / 2,\n        ]\n\n        super().__init__(**kwargs)\n\n    def generate_points(self) -> Self:\n        p_min, p_max = (\n            np.array([self.x_range[0], self.y_range[0]]),\n            np.array([self.x_range[1], self.y_range[1]]),\n        )\n        curves = plot_isoline(\n            fn=lambda u: self.function(u[0], u[1]),\n            pmin=p_min,\n            pmax=p_max,\n            min_depth=self.min_depth,\n            max_quads=self.max_quads,\n        )  # returns a list of lists of 2D points\n        curves = [\n            np.pad(curve, [(0, 0), (0, 1)]) for curve in curves if curve != []\n        ]  # add z coord as 0\n        for curve in curves:\n            self.start_new_path(curve[0])\n            self.add_points_as_corners(curve[1:])\n        if self.use_smoothing:\n            self.make_smooth()\n        return self\n\n    def init_points(self) -> None:\n        self.generate_points()\n"
  },
  {
    "path": "manim/mobject/graphing/number_line.py",
    "content": "\"\"\"Mobject representing a number line.\"\"\"\n\nfrom __future__ import annotations\n\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject\n\n__all__ = [\"NumberLine\", \"UnitInterval\"]\n\n\nfrom collections.abc import Callable, Iterable, Sequence\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from typing import Any, Self\n\n    from manim.mobject.geometry.tips import ArrowTip\n    from manim.typing import Point3D, Point3DLike, Vector3D\n\nimport numpy as np\n\nfrom manim import config\nfrom manim.constants import *\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.graphing.scale import LinearBase, _ScaleBase\nfrom manim.mobject.text.numbers import DecimalNumber, Integer\nfrom manim.mobject.text.tex_mobject import MathTex, Tex\nfrom manim.mobject.text.text_mobject import Text\nfrom manim.mobject.types.vectorized_mobject import VGroup, VMobject\nfrom manim.utils.bezier import interpolate\nfrom manim.utils.config_ops import merge_dicts_recursively\nfrom manim.utils.space_ops import normalize\n\n\nclass NumberLine(Line):\n    \"\"\"Creates a number line with tick marks.\n\n    Parameters\n    ----------\n    x_range\n        The ``[x_min, x_max, x_step]`` values to create the line.\n    length\n        The length of the number line.\n    unit_size\n        The distance between each tick of the line. Overwritten by :attr:`length`, if specified.\n    include_ticks\n        Whether to include ticks on the number line.\n    tick_size\n        The length of each tick mark.\n    numbers_with_elongated_ticks\n        An iterable of specific values with elongated ticks.\n    longer_tick_multiple\n        Influences how many times larger elongated ticks are than regular ticks (2 = 2x).\n    rotation\n        The angle (in radians) at which the line is rotated.\n    stroke_width\n        The thickness of the line.\n    include_tip\n        Whether to add a tip to the end of the line.\n    tip_width\n        The width of the tip.\n    tip_height\n        The height of the tip.\n    tip_shape\n        The mobject class used to construct the tip, or ``None`` (the\n        default) for the default arrow tip. Passed classes have to inherit\n        from :class:`.ArrowTip`.\n    include_numbers\n        Whether to add numbers to the tick marks. The number of decimal places is determined\n        by the step size, this default can be overridden by ``decimal_number_config``.\n    scaling\n        The way the ``x_range`` is value is scaled, i.e. :class:`~.LogBase` for a logarithmic numberline. Defaults to :class:`~.LinearBase`.\n    font_size\n        The size of the label mobjects. Defaults to 36.\n    label_direction\n        The specific position to which label mobjects are added on the line.\n    label_constructor\n        Determines the mobject class that will be used to construct the labels of the number line.\n    line_to_number_buff\n        The distance between the line and the label mobject.\n    decimal_number_config\n        Arguments that can be passed to :class:`~.numbers.DecimalNumber` to influence number mobjects.\n    numbers_to_exclude\n        An explicit iterable of numbers to not be added to the number line.\n    numbers_to_include\n        An explicit iterable of numbers to add to the number line\n    kwargs\n        Additional arguments to be passed to :class:`~.Line`.\n\n\n    .. note::\n\n        Number ranges that include both negative and positive values will be generated\n        from the 0 point, and may not include a tick at the min / max\n        values as the tick locations are dependent on the step size.\n\n    Examples\n    --------\n    .. manim:: NumberLineExample\n        :save_last_frame:\n\n        class NumberLineExample(Scene):\n            def construct(self):\n                l0 = NumberLine(\n                    x_range=[-10, 10, 2],\n                    length=10,\n                    color=BLUE,\n                    include_numbers=True,\n                    label_direction=UP,\n                )\n\n                l1 = NumberLine(\n                    x_range=[-10, 10, 2],\n                    unit_size=0.5,\n                    numbers_with_elongated_ticks=[-2, 4],\n                    include_numbers=True,\n                    font_size=24,\n                )\n                num6 = l1.numbers[8]\n                num6.set_color(RED)\n\n                l2 = NumberLine(\n                    x_range=[-2.5, 2.5 + 0.5, 0.5],\n                    length=12,\n                    decimal_number_config={\"num_decimal_places\": 2},\n                    include_numbers=True,\n                )\n\n                l3 = NumberLine(\n                    x_range=[-5, 5 + 1, 1],\n                    length=6,\n                    include_tip=True,\n                    include_numbers=True,\n                    rotation=10 * DEGREES,\n                )\n\n                line_group = VGroup(l0, l1, l2, l3).arrange(DOWN, buff=1)\n                self.add(line_group)\n    \"\"\"\n\n    def __init__(\n        self,\n        x_range: Sequence[float] | None = None,  # must be first\n        length: float | None = None,\n        unit_size: float = 1,\n        # ticks\n        include_ticks: bool = True,\n        tick_size: float = 0.1,\n        numbers_with_elongated_ticks: Iterable[float] | None = None,\n        longer_tick_multiple: int = 2,\n        exclude_origin_tick: bool = False,\n        # visuals\n        rotation: float = 0,\n        stroke_width: float = 2.0,\n        # tip\n        include_tip: bool = False,\n        tip_width: float = DEFAULT_ARROW_TIP_LENGTH,\n        tip_height: float = DEFAULT_ARROW_TIP_LENGTH,\n        tip_shape: type[ArrowTip] | None = None,\n        # numbers/labels\n        include_numbers: bool = False,\n        font_size: float = 36,\n        label_direction: Point3DLike = DOWN,\n        label_constructor: type[MathTex] = MathTex,\n        scaling: _ScaleBase = LinearBase(),\n        line_to_number_buff: float = MED_SMALL_BUFF,\n        decimal_number_config: dict | None = None,\n        numbers_to_exclude: Iterable[float] | None = None,\n        numbers_to_include: Iterable[float] | None = None,\n        **kwargs: Any,\n    ):\n        # avoid mutable arguments in defaults\n        if numbers_to_exclude is None:\n            numbers_to_exclude = []\n        if numbers_with_elongated_ticks is None:\n            numbers_with_elongated_ticks = []\n\n        if x_range is None:\n            x_range = [\n                round(-config[\"frame_x_radius\"]),\n                round(config[\"frame_x_radius\"]),\n                1,\n            ]\n        elif len(x_range) == 2:\n            # adds x_step if not specified. not sure how to feel about this. a user can't know default without peeking at source code\n            x_range = [*x_range, 1]\n\n        if decimal_number_config is None:\n            decimal_number_config = {\n                \"num_decimal_places\": self._decimal_places_from_step(x_range[2]),\n            }\n\n        # turn into a NumPy array to scale by just applying the function\n        self.x_range = np.array(x_range, dtype=float)\n        self.x_min: float\n        self.x_max: float\n        self.x_step: float\n        self.x_min, self.x_max, self.x_step = scaling.function(self.x_range)\n        self.length = length\n        self.unit_size = unit_size\n        # ticks\n        self.include_ticks = include_ticks\n        self.tick_size = tick_size\n        self.numbers_with_elongated_ticks = numbers_with_elongated_ticks\n        self.longer_tick_multiple = longer_tick_multiple\n        self.exclude_origin_tick = exclude_origin_tick\n        # visuals\n        self.rotation = rotation\n        # tip\n        self.include_tip = include_tip\n        self.tip_width = tip_width\n        self.tip_height = tip_height\n        # numbers\n        self.font_size = font_size\n        self.include_numbers = include_numbers\n        self.label_direction = label_direction\n        self.label_constructor = label_constructor\n        self.line_to_number_buff = line_to_number_buff\n        self.decimal_number_config = decimal_number_config\n        self.numbers_to_exclude = numbers_to_exclude\n        self.numbers_to_include = numbers_to_include\n\n        self.scaling = scaling\n        super().__init__(\n            self.x_range[0] * RIGHT,\n            self.x_range[1] * RIGHT,\n            stroke_width=stroke_width,\n            **kwargs,\n        )\n\n        if self.length:\n            self.set_length(self.length)\n            self.unit_size = self.get_unit_size()\n        else:\n            self.scale(self.unit_size)\n\n        self.center()\n\n        if self.include_tip:\n            self.add_tip(\n                tip_length=self.tip_height,\n                tip_width=self.tip_width,\n                tip_shape=tip_shape,\n            )\n            self.tip.set_stroke(self.stroke_color, self.stroke_width)\n\n        if self.include_ticks:\n            self.add_ticks()\n\n        self.rotate(self.rotation)\n        if self.include_numbers or self.numbers_to_include is not None:\n            if self.scaling.custom_labels:\n                tick_range = self.get_tick_range()\n\n                custom_labels = self.scaling.get_custom_labels(\n                    tick_range,\n                    unit_decimal_places=decimal_number_config[\"num_decimal_places\"],\n                )\n\n                self.add_labels(\n                    dict(\n                        zip(\n                            tick_range,\n                            custom_labels,\n                            strict=True,\n                        )\n                    ),\n                )\n\n            else:\n                self.add_numbers(\n                    x_values=self.numbers_to_include,\n                    excluding=self.numbers_to_exclude,\n                    font_size=self.font_size,\n                )\n\n    def rotate_about_zero(\n        self, angle: float, axis: Vector3D = OUT, **kwargs: Any\n    ) -> Self:\n        return self.rotate_about_number(0, angle, axis, **kwargs)\n\n    def rotate_about_number(\n        self, number: float, angle: float, axis: Vector3D = OUT, **kwargs: Any\n    ) -> Self:\n        return self.rotate(angle, axis, about_point=self.n2p(number), **kwargs)\n\n    def add_ticks(self) -> None:\n        \"\"\"Adds ticks to the number line. Ticks can be accessed after creation\n        via ``self.ticks``.\n        \"\"\"\n        ticks = VGroup()\n        elongated_tick_size = self.tick_size * self.longer_tick_multiple\n        elongated_tick_offsets = (\n            np.array(self.numbers_with_elongated_ticks) - self.x_min\n        )\n        for x in self.get_tick_range():\n            size = self.tick_size\n            if np.any(np.isclose(x - self.x_min, elongated_tick_offsets)):\n                size = elongated_tick_size\n            ticks.add(self.get_tick(x, size))\n        self.add(ticks)\n        self.ticks = ticks\n\n    def get_tick(self, x: float, size: float | None = None) -> Line:\n        \"\"\"Generates a tick and positions it along the number line.\n\n        Parameters\n        ----------\n        x\n            The position of the tick.\n        size\n            The factor by which the tick is scaled.\n\n        Returns\n        -------\n        :class:`~.Line`\n            A positioned tick.\n        \"\"\"\n        if size is None:\n            size = self.tick_size\n        result = Line(size * DOWN, size * UP)\n        result.rotate(self.get_angle())\n        result.move_to(self.number_to_point(x))\n        result.match_style(self)\n        return result\n\n    def get_tick_marks(self) -> VGroup:\n        return self.ticks\n\n    def get_tick_range(self) -> np.ndarray:\n        \"\"\"Generates the range of values on which labels are plotted based on the\n        ``x_range`` attribute of the number line.\n\n        Returns\n        -------\n        np.ndarray\n            A numpy array of floats represnting values along the number line.\n        \"\"\"\n        x_min, x_max, x_step = self.x_range\n        if not self.include_tip:\n            x_max += 1e-6\n\n        # Handle cases where min and max are both positive or both negative\n        if x_min < x_max < 0 or x_max > x_min > 0:\n            tick_range = np.arange(x_min, x_max, x_step)\n        else:\n            start_point = 0\n            if self.exclude_origin_tick:\n                start_point += x_step\n\n            x_min_segment = np.arange(start_point, np.abs(x_min) + 1e-6, x_step) * -1\n            x_max_segment = np.arange(start_point, x_max, x_step)\n\n            tick_range = np.unique(np.concatenate((x_min_segment, x_max_segment)))\n\n        return self.scaling.function(tick_range)\n\n    def number_to_point(self, number: float | np.ndarray) -> np.ndarray:\n        \"\"\"Accepts a value along the number line and returns a point with\n        respect to the scene.\n        Equivalent to `NumberLine @ number`\n\n        Parameters\n        ----------\n        number\n            The value to be transformed into a coordinate. Or a list of values.\n\n        Returns\n        -------\n        np.ndarray\n            A point with respect to the scene's coordinate system. Or a list of points.\n\n        Examples\n        --------\n\n            >>> from manim import NumberLine\n            >>> number_line = NumberLine()\n            >>> number_line.number_to_point(0)\n            array([0., 0., 0.])\n            >>> number_line.number_to_point(1)\n            array([1., 0., 0.])\n            >>> number_line @ 1\n            array([1., 0., 0.])\n            >>> number_line.number_to_point([1, 2, 3])\n            array([[1., 0., 0.],\n                   [2., 0., 0.],\n                   [3., 0., 0.]])\n        \"\"\"\n        number = np.asarray(number)\n        scalar = number.ndim == 0\n        number = self.scaling.inverse_function(number)\n        alphas = (number - self.x_range[0]) / (self.x_range[1] - self.x_range[0])\n        alphas = float(alphas) if scalar else np.vstack(alphas)\n        val = interpolate(self.get_start(), self.get_end(), alphas)\n        return val\n\n    def point_to_number(self, point: Sequence[float]) -> float:\n        \"\"\"Accepts a point with respect to the scene and returns\n        a float along the number line.\n\n        Parameters\n        ----------\n        point\n            A sequence of values consisting of ``(x_coord, y_coord, z_coord)``.\n\n        Returns\n        -------\n        float\n            A float representing a value along the number line.\n\n        Examples\n        --------\n\n            >>> from manim import NumberLine\n            >>> number_line = NumberLine()\n            >>> number_line.point_to_number((0, 0, 0))\n            np.float64(0.0)\n            >>> number_line.point_to_number((1, 0, 0))\n            np.float64(1.0)\n            >>> number_line.point_to_number([[0.5, 0, 0], [1, 0, 0], [1.5, 0, 0]])\n            array([0.5, 1. , 1.5])\n\n        \"\"\"\n        point = np.asarray(point)\n        start, end = self.get_start_and_end()\n        unit_vect = normalize(end - start)\n        proportion: float = np.dot(point - start, unit_vect) / np.dot(\n            end - start, unit_vect\n        )\n        return interpolate(self.x_min, self.x_max, proportion)\n\n    def n2p(self, number: float | np.ndarray) -> Point3D:\n        \"\"\"Abbreviation for :meth:`~.NumberLine.number_to_point`.\"\"\"\n        return self.number_to_point(number)\n\n    def p2n(self, point: Point3DLike) -> float:\n        \"\"\"Abbreviation for :meth:`~.NumberLine.point_to_number`.\"\"\"\n        return self.point_to_number(point)\n\n    def get_unit_size(self) -> float:\n        val: float = self.get_length() / (self.x_range[1] - self.x_range[0])\n        return val\n\n    def get_unit_vector(self) -> Vector3D:\n        return super().get_unit_vector() * self.unit_size\n\n    def get_number_mobject(\n        self,\n        x: float,\n        direction: Vector3D | None = None,\n        buff: float | None = None,\n        font_size: float | None = None,\n        label_constructor: type[MathTex] | None = None,\n        **number_config: dict[str, Any],\n    ) -> VMobject:\n        \"\"\"Generates a positioned :class:`~.DecimalNumber` mobject\n        generated according to ``label_constructor``.\n\n        Parameters\n        ----------\n        x\n            The x-value at which the mobject should be positioned.\n        direction\n            Determines the direction at which the label is positioned next to the line.\n        buff\n            The distance of the label from the line.\n        font_size\n            The font size of the label mobject.\n        label_constructor\n            The :class:`~.VMobject` class that will be used to construct the label.\n            Defaults to the ``label_constructor`` attribute of the number line\n            if not specified.\n\n        Returns\n        -------\n        :class:`~.DecimalNumber`\n            The positioned mobject.\n        \"\"\"\n        number_config_merged = merge_dicts_recursively(\n            self.decimal_number_config,\n            number_config,\n        )\n        if direction is None:\n            direction = self.label_direction\n        if buff is None:\n            buff = self.line_to_number_buff\n        if font_size is None:\n            font_size = self.font_size\n        if label_constructor is None:\n            label_constructor = self.label_constructor\n\n        num_mob = DecimalNumber(\n            x,\n            font_size=font_size,\n            mob_class=label_constructor,\n            **number_config_merged,\n        )\n\n        num_mob.next_to(self.number_to_point(x), direction=direction, buff=buff)\n        if x < 0 and self.label_direction[0] == 0:\n            # Align without the minus sign\n            num_mob.shift(num_mob[0].width * LEFT / 2)\n        return num_mob\n\n    def get_number_mobjects(self, *numbers: float, **kwargs: Any) -> VGroup:\n        if len(numbers) == 0:\n            numbers = self.default_numbers_to_display()\n        return VGroup([self.get_number_mobject(number, **kwargs) for number in numbers])\n\n    def get_labels(self) -> VGroup:\n        return self.get_number_mobjects()\n\n    def add_numbers(\n        self,\n        x_values: Iterable[float] | None = None,\n        excluding: Iterable[float] | None = None,\n        font_size: float | None = None,\n        label_constructor: type[MathTex] | None = None,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Adds :class:`~.DecimalNumber` mobjects representing their position\n        at each tick of the number line. The numbers can be accessed after creation\n        via ``self.numbers``.\n\n        Parameters\n        ----------\n        x_values\n            An iterable of the values used to position and create the labels.\n            Defaults to the output produced by :meth:`~.NumberLine.get_tick_range`\n        excluding\n            A list of values to exclude from :attr:`x_values`.\n        font_size\n            The font size of the labels. Defaults to the ``font_size`` attribute\n            of the number line.\n        label_constructor\n            The :class:`~.VMobject` class that will be used to construct the label.\n            Defaults to the ``label_constructor`` attribute of the number line\n            if not specified.\n        \"\"\"\n        if x_values is None:\n            x_values = self.get_tick_range()\n\n        if excluding is None:\n            excluding = self.numbers_to_exclude\n\n        if font_size is None:\n            font_size = self.font_size\n\n        if label_constructor is None:\n            label_constructor = self.label_constructor\n\n        numbers = VGroup()\n        for x in x_values:\n            if x in excluding:\n                continue\n            numbers.add(\n                self.get_number_mobject(\n                    x,\n                    font_size=font_size,\n                    label_constructor=label_constructor,\n                    **kwargs,\n                )\n            )\n        self.add(numbers)\n        self.numbers = numbers\n        return self\n\n    def add_labels(\n        self,\n        dict_values: dict[float, str | float | VMobject],\n        direction: Point3DLike | None = None,\n        buff: float | None = None,\n        font_size: float | None = None,\n        label_constructor: type[MathTex] | None = None,\n    ) -> Self:\n        \"\"\"Adds specifically positioned labels to the :class:`~.NumberLine` using a ``dict``.\n        The labels can be accessed after creation via ``self.labels``.\n\n        Parameters\n        ----------\n        dict_values\n            A dictionary consisting of the position along the number line and the mobject to be added:\n            ``{1: Tex(\"Monday\"), 3: Tex(\"Tuesday\")}``. :attr:`label_constructor` will be used\n            to construct the labels if the value is not a mobject (``str`` or ``float``).\n        direction\n            Determines the direction at which the label is positioned next to the line.\n        buff\n            The distance of the label from the line.\n        font_size\n            The font size of the mobject to be positioned.\n        label_constructor\n            The :class:`~.VMobject` class that will be used to construct the label.\n            Defaults to the ``label_constructor`` attribute of the number line\n            if not specified.\n\n        Raises\n        ------\n        AttributeError\n            If the label does not have a ``font_size`` attribute, an ``AttributeError`` is raised.\n        \"\"\"\n        direction = self.label_direction if direction is None else direction\n        buff = self.line_to_number_buff if buff is None else buff\n        font_size = self.font_size if font_size is None else font_size\n        if label_constructor is None:\n            label_constructor = self.label_constructor\n\n        labels = VGroup()\n        for x, label in dict_values.items():\n            # TODO: remove this check and ability to call\n            # this method via CoordinateSystem.add_coordinates()\n            # must be explicitly called\n            if isinstance(label, str) and label_constructor is MathTex:\n                label = Tex(label)\n            else:\n                label = self._create_label_tex(label, label_constructor)\n\n            if hasattr(label, \"font_size\"):\n                assert isinstance(label, (MathTex, Tex, Text, Integer)), label\n                label.font_size = font_size\n            else:\n                raise AttributeError(f\"{label} is not compatible with add_labels.\")\n            label.next_to(self.number_to_point(x), direction=direction, buff=buff)\n            labels.add(label)\n\n        self.labels = labels\n        self.add(labels)\n        return self\n\n    def _create_label_tex(\n        self,\n        label_tex: str | float | VMobject,\n        label_constructor: Callable | None = None,\n        **kwargs: Any,\n    ) -> VMobject:\n        \"\"\"Checks if the label is a :class:`~.VMobject`, otherwise, creates a\n        label by passing ``label_tex`` to ``label_constructor``.\n\n        Parameters\n        ----------\n        label_tex\n            The label for which a mobject should be created. If the label already\n            is a mobject, no new mobject is created.\n        label_constructor\n            Optional. A class or function returning a mobject when\n            passing ``label_tex`` as an argument. If ``None`` is passed\n            (the default), the label constructor from the :attr:`.label_constructor`\n            attribute is used.\n\n        Returns\n        -------\n        :class:`~.VMobject`\n            The label.\n        \"\"\"\n        if isinstance(label_tex, (VMobject, OpenGLVMobject)):\n            return label_tex\n        if label_constructor is None:\n            label_constructor = self.label_constructor\n        if isinstance(label_tex, str):\n            return label_constructor(label_tex, **kwargs)\n        return label_constructor(str(label_tex), **kwargs)\n\n    @staticmethod\n    def _decimal_places_from_step(step: float) -> int:\n        step_str = str(step)\n        if \".\" not in step_str:\n            return 0\n        return len(step_str.split(\".\")[-1])\n\n    def __matmul__(self, other: float) -> Point3D:\n        return self.n2p(other)\n\n    def __rmatmul__(self, other: Point3DLike | Mobject) -> float:\n        if isinstance(other, Mobject):\n            other = other.get_center()\n        return self.p2n(other)\n\n\nclass UnitInterval(NumberLine):\n    def __init__(\n        self,\n        unit_size: float = 10,\n        numbers_with_elongated_ticks: list[float] | None = None,\n        decimal_number_config: dict[str, Any] | None = None,\n        **kwargs: Any,\n    ):\n        numbers_with_elongated_ticks = (\n            [0, 1]\n            if numbers_with_elongated_ticks is None\n            else numbers_with_elongated_ticks\n        )\n\n        decimal_number_config = (\n            {\n                \"num_decimal_places\": 1,\n            }\n            if decimal_number_config is None\n            else decimal_number_config\n        )\n\n        super().__init__(\n            x_range=(0, 1, 0.1),\n            unit_size=unit_size,\n            numbers_with_elongated_ticks=numbers_with_elongated_ticks,\n            decimal_number_config=decimal_number_config,\n            **kwargs,\n        )\n"
  },
  {
    "path": "manim/mobject/graphing/probability.py",
    "content": "\"\"\"Mobjects representing objects from probability theory and statistics.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"SampleSpace\", \"BarChart\"]\n\n\nfrom collections.abc import Iterable, MutableSequence, Sequence\nfrom typing import Any\n\nimport numpy as np\n\nfrom manim import config, logger\nfrom manim.constants import *\nfrom manim.mobject.geometry.polygram import Rectangle\nfrom manim.mobject.graphing.coordinate_systems import Axes\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject\nfrom manim.mobject.svg.brace import Brace\nfrom manim.mobject.text.tex_mobject import MathTex, Tex\nfrom manim.mobject.types.vectorized_mobject import VGroup, VMobject\nfrom manim.typing import Vector3D\nfrom manim.utils.color import (\n    BLUE_E,\n    DARK_GREY,\n    GREEN_E,\n    LIGHT_GREY,\n    MAROON_B,\n    YELLOW,\n    ParsableManimColor,\n    color_gradient,\n)\nfrom manim.utils.iterables import tuplify\n\nEPSILON = 0.0001\n\n\nclass SampleSpace(Rectangle):\n    \"\"\"A mobject representing a twodimensional rectangular\n    sampling space.\n\n    Examples\n    --------\n    .. manim:: ExampleSampleSpace\n        :save_last_frame:\n\n        class ExampleSampleSpace(Scene):\n            def construct(self):\n                poly1 = SampleSpace(stroke_width=15, fill_opacity=1)\n                poly2 = SampleSpace(width=5, height=3, stroke_width=5, fill_opacity=0.5)\n                poly3 = SampleSpace(width=2, height=2, stroke_width=5, fill_opacity=0.1)\n                poly3.divide_vertically(p_list=np.array([0.37, 0.13, 0.5]), colors=[BLACK, WHITE, GRAY], vect=RIGHT)\n                poly_group = VGroup(poly1, poly2, poly3).arrange()\n                self.add(poly_group)\n    \"\"\"\n\n    def __init__(\n        self,\n        height: float = 3,\n        width: float = 3,\n        fill_color: ParsableManimColor = DARK_GREY,\n        fill_opacity: float = 1,\n        stroke_width: float = 0.5,\n        stroke_color: ParsableManimColor = LIGHT_GREY,\n        default_label_scale_val: float = 1,\n    ):\n        super().__init__(\n            height=height,\n            width=width,\n            fill_color=fill_color,\n            fill_opacity=fill_opacity,\n            stroke_width=stroke_width,\n            stroke_color=stroke_color,\n        )\n        self.default_label_scale_val = default_label_scale_val\n\n    def add_title(\n        self, title: str = \"Sample space\", buff: float = MED_SMALL_BUFF\n    ) -> None:\n        # TODO, should this really exist in SampleSpaceScene\n        title_mob = Tex(title)\n        if title_mob.width > self.width:\n            title_mob.width = self.width\n        title_mob.next_to(self, UP, buff=buff)\n        self.title = title_mob\n        self.add(title_mob)\n\n    def add_label(self, label: str) -> None:\n        self.label = label\n\n    def complete_p_list(self, p_list: float | Iterable[float]) -> list[float]:\n        p_list_tuplified: tuple[float] = tuplify(p_list)\n        new_p_list = list(p_list_tuplified)\n        remainder = 1.0 - sum(new_p_list)\n        if abs(remainder) > EPSILON:\n            new_p_list.append(remainder)\n        return new_p_list\n\n    def get_division_along_dimension(\n        self,\n        p_list: float | Iterable[float],\n        dim: int,\n        colors: Sequence[ParsableManimColor],\n        vect: Vector3D,\n    ) -> VGroup:\n        p_list_complete = self.complete_p_list(p_list)\n        colors_in_gradient = color_gradient(colors, len(p_list_complete))\n\n        last_point = self.get_edge_center(-vect)\n        parts = VGroup()\n        for factor, color in zip(p_list_complete, colors_in_gradient, strict=True):\n            part = SampleSpace()\n            part.set_fill(color, 1)\n            part.replace(self, stretch=True)\n            part.stretch(factor, dim)\n            part.move_to(last_point, -vect)\n            last_point = part.get_edge_center(vect)\n            parts.add(part)\n        return parts\n\n    def get_horizontal_division(\n        self,\n        p_list: float | Iterable[float],\n        colors: Sequence[ParsableManimColor] = [GREEN_E, BLUE_E],\n        vect: Vector3D = DOWN,\n    ) -> VGroup:\n        return self.get_division_along_dimension(p_list, 1, colors, vect)\n\n    def get_vertical_division(\n        self,\n        p_list: float | Iterable[float],\n        colors: Sequence[ParsableManimColor] = [MAROON_B, YELLOW],\n        vect: Vector3D = RIGHT,\n    ) -> VGroup:\n        return self.get_division_along_dimension(p_list, 0, colors, vect)\n\n    def divide_horizontally(self, *args: Any, **kwargs: Any) -> None:\n        self.horizontal_parts = self.get_horizontal_division(*args, **kwargs)\n        self.add(self.horizontal_parts)\n\n    def divide_vertically(self, *args: Any, **kwargs: Any) -> None:\n        self.vertical_parts = self.get_vertical_division(*args, **kwargs)\n        self.add(self.vertical_parts)\n\n    def get_subdivision_braces_and_labels(\n        self,\n        parts: VGroup,\n        labels: list[str | VMobject | OpenGLVMobject],\n        direction: Vector3D,\n        buff: float = SMALL_BUFF,\n        min_num_quads: int = 1,\n    ) -> VGroup:\n        label_mobs = VGroup()\n        braces = VGroup()\n        for label, part in zip(labels, parts, strict=False):\n            brace = Brace(part, direction, min_num_quads=min_num_quads, buff=buff)\n            if isinstance(label, (VMobject, OpenGLVMobject)):\n                label_mob = label\n            else:\n                label_mob = MathTex(label)\n                label_mob.scale(self.default_label_scale_val)\n            label_mob.next_to(brace, direction, buff)\n\n            braces.add(brace)\n            assert isinstance(label_mob, VMobject)\n            label_mobs.add(label_mob)\n        parts.braces = braces  # type: ignore[attr-defined]\n        parts.labels = label_mobs  # type: ignore[attr-defined]\n        parts.label_kwargs = {  # type: ignore[attr-defined]\n            \"labels\": label_mobs.copy(),\n            \"direction\": direction,\n            \"buff\": buff,\n        }\n        return VGroup(parts.braces, parts.labels)\n\n    def get_side_braces_and_labels(\n        self,\n        labels: list[str | VMobject | OpenGLVMobject],\n        direction: Vector3D = LEFT,\n        **kwargs: Any,\n    ) -> VGroup:\n        assert hasattr(self, \"horizontal_parts\")\n        parts = self.horizontal_parts\n        return self.get_subdivision_braces_and_labels(\n            parts, labels, direction, **kwargs\n        )\n\n    def get_top_braces_and_labels(\n        self, labels: list[str | VMobject | OpenGLVMobject], **kwargs: Any\n    ) -> VGroup:\n        assert hasattr(self, \"vertical_parts\")\n        parts = self.vertical_parts\n        return self.get_subdivision_braces_and_labels(parts, labels, UP, **kwargs)\n\n    def get_bottom_braces_and_labels(\n        self, labels: list[str | VMobject | OpenGLVMobject], **kwargs: Any\n    ) -> VGroup:\n        assert hasattr(self, \"vertical_parts\")\n        parts = self.vertical_parts\n        return self.get_subdivision_braces_and_labels(parts, labels, DOWN, **kwargs)\n\n    def add_braces_and_labels(self) -> None:\n        for attr in \"horizontal_parts\", \"vertical_parts\":\n            if not hasattr(self, attr):\n                continue\n            parts = getattr(self, attr)\n            for subattr in \"braces\", \"labels\":\n                if hasattr(parts, subattr):\n                    self.add(getattr(parts, subattr))\n\n    def __getitem__(self, index: int) -> VMobject:\n        if hasattr(self, \"horizontal_parts\"):\n            return self.horizontal_parts[index]\n        elif hasattr(self, \"vertical_parts\"):\n            return self.vertical_parts[index]\n        return self.split()[index]\n\n\nclass BarChart(Axes):\n    \"\"\"Creates a bar chart. Inherits from :class:`~.Axes`, so it shares its methods\n    and attributes. Each axis inherits from :class:`~.NumberLine`, so pass in ``x_axis_config``/``y_axis_config``\n    to control their attributes.\n\n    Parameters\n    ----------\n    values\n        A sequence of values that determines the height of each bar. Accepts negative values.\n    bar_names\n        A sequence of names for each bar. Does not have to match the length of ``values``.\n    y_range\n        The y_axis range of values. If ``None``, the range will be calculated based on the\n        min/max of ``values`` and the step will be calculated based on ``y_length``.\n    x_length\n        The length of the x-axis. If ``None``, it is automatically calculated based on\n        the number of values and the width of the screen.\n    y_length\n        The length of the y-axis.\n    bar_colors\n        The color for the bars. Accepts a sequence of colors (can contain just one item).\n        If the length of``bar_colors`` does not match that of ``values``,\n        intermediate colors will be automatically determined.\n    bar_width\n        The length of a bar. Must be between 0 and 1.\n    bar_fill_opacity\n        The fill opacity of the bars.\n    bar_stroke_width\n        The stroke width of the bars.\n\n    Examples\n    --------\n    .. manim:: BarChartExample\n        :save_last_frame:\n\n        class BarChartExample(Scene):\n            def construct(self):\n                chart = BarChart(\n                    values=[-5, 40, -10, 20, -3],\n                    bar_names=[\"one\", \"two\", \"three\", \"four\", \"five\"],\n                    y_range=[-20, 50, 10],\n                    y_length=6,\n                    x_length=10,\n                    x_axis_config={\"font_size\": 36},\n                )\n\n                c_bar_lbls = chart.get_bar_labels(font_size=48)\n\n                self.add(chart, c_bar_lbls)\n    \"\"\"\n\n    def __init__(\n        self,\n        values: MutableSequence[float],\n        bar_names: Sequence[str] | None = None,\n        y_range: Sequence[float] | None = None,\n        x_length: float | None = None,\n        y_length: float | None = None,\n        bar_colors: Iterable[str] = [\n            \"#003f5c\",\n            \"#58508d\",\n            \"#bc5090\",\n            \"#ff6361\",\n            \"#ffa600\",\n        ],\n        bar_width: float = 0.6,\n        bar_fill_opacity: float = 0.7,\n        bar_stroke_width: float = 3,\n        **kwargs: Any,\n    ):\n        if isinstance(bar_colors, str):\n            logger.warning(\n                \"Passing a string to `bar_colors` has been deprecated since v0.15.2 and will be removed after v0.17.0, the parameter must be a list.  \"\n            )\n            bar_colors = list(bar_colors)\n\n        y_length = y_length if y_length is not None else config.frame_height - 4\n\n        self.values = values\n        self.bar_names = bar_names\n        self.bar_colors = bar_colors\n        self.bar_width = bar_width\n        self.bar_fill_opacity = bar_fill_opacity\n        self.bar_stroke_width = bar_stroke_width\n\n        x_range = [0, len(self.values), 1]\n\n        if y_range is None:\n            y_range = [\n                min(0, min(self.values)),\n                max(0, max(self.values)),\n                round(max(self.values) / y_length, 2),\n            ]\n\n        elif len(y_range) == 2:\n            y_range = [*y_range, round(max(self.values) / y_length, 2)]\n\n        if x_length is None:\n            x_length = min(len(self.values), config.frame_width - 2)\n\n        x_axis_config = {\"font_size\": 24, \"label_constructor\": Tex}\n        self._update_default_configs(\n            (x_axis_config,), (kwargs.pop(\"x_axis_config\", None),)\n        )\n\n        self.bars: VGroup = VGroup()\n        self.x_labels: VGroup | None = None\n        self.bar_labels: VGroup | None = None\n\n        super().__init__(\n            x_range=x_range,\n            y_range=y_range,\n            x_length=x_length,\n            y_length=y_length,\n            x_axis_config=x_axis_config,\n            tips=kwargs.pop(\"tips\", False),\n            **kwargs,\n        )\n\n        self._add_bars()\n\n        if self.bar_names is not None:\n            self._add_x_axis_labels()\n\n        self.y_axis.add_numbers()\n\n    def _update_colors(self) -> None:\n        \"\"\"Initialize the colors of the bars of the chart.\n\n        Sets the color of ``self.bars`` via ``self.bar_colors``.\n\n        Primarily used when the bars are initialized with ``self._add_bars``\n        or updated via ``self.change_bar_values``.\n        \"\"\"\n        self.bars.set_color_by_gradient(*self.bar_colors)\n\n    def _add_x_axis_labels(self) -> None:\n        \"\"\"Essentially :meth`:~.NumberLine.add_labels`, but differs in that\n        the direction of the label with respect to the x_axis changes to UP or DOWN\n        depending on the value.\n\n        UP for negative values and DOWN for positive values.\n        \"\"\"\n        assert isinstance(self.bar_names, list)\n        val_range = np.arange(\n            0.5, len(self.bar_names), 1\n        )  # 0.5 shifted so that labels are centered, not on ticks\n\n        labels = VGroup()\n\n        for i, (value, bar_name) in enumerate(\n            zip(val_range, self.bar_names, strict=True)\n        ):\n            # to accommodate negative bars, the label may need to be\n            # below or above the x_axis depending on the value of the bar\n            direction = UP if self.values[i] < 0 else DOWN\n            bar_name_label: MathTex = self.x_axis.label_constructor(bar_name)\n\n            bar_name_label.font_size = self.x_axis.font_size\n            bar_name_label.next_to(\n                self.x_axis.number_to_point(value),\n                direction=direction,\n                buff=self.x_axis.line_to_number_buff,\n            )\n\n            labels.add(bar_name_label)\n\n        self.x_axis.labels = labels\n        self.x_axis.add(labels)\n\n    def _create_bar(self, bar_number: int, value: float) -> Rectangle:\n        \"\"\"Creates a positioned bar on the chart.\n\n        Parameters\n        ----------\n        bar_number\n            Determines the x-position of the bar.\n        value\n            The value that determines the height of the bar.\n\n        Returns\n        -------\n        Rectangle\n            A positioned rectangle representing a bar on the chart.\n        \"\"\"\n        # bar measurements relative to the axis\n\n        # distance from between the y-axis and the top of the bar\n        bar_h = abs(self.c2p(0, value)[1] - self.c2p(0, 0)[1])\n        # width of the bar\n        bar_w = self.c2p(self.bar_width, 0)[0] - self.c2p(0, 0)[0]\n\n        bar = Rectangle(\n            height=bar_h,\n            width=bar_w,\n            stroke_width=self.bar_stroke_width,\n            fill_opacity=self.bar_fill_opacity,\n        )\n\n        pos = UP if (value >= 0) else DOWN\n        bar.next_to(self.c2p(bar_number + 0.5, 0), pos, buff=0)\n        return bar\n\n    def _add_bars(self) -> None:\n        for i, value in enumerate(self.values):\n            tmp_bar = self._create_bar(bar_number=i, value=value)\n            self.bars.add(tmp_bar)\n\n        self._update_colors()\n        self.add_to_back(self.bars)\n\n    def get_bar_labels(\n        self,\n        color: ParsableManimColor | None = None,\n        font_size: float = 24,\n        buff: float = MED_SMALL_BUFF,\n        label_constructor: type[MathTex] = Tex,\n    ) -> VGroup:\n        \"\"\"Annotates each bar with its corresponding value. Use ``self.bar_labels`` to access the\n        labels after creation.\n\n        Parameters\n        ----------\n        color\n            The color of each label. By default ``None`` and is based on the parent's bar color.\n        font_size\n            The font size of each label.\n        buff\n            The distance from each label to its bar. By default 0.4.\n        label_constructor\n            The Mobject class to construct the labels, by default :class:`~.Tex`.\n\n        Examples\n        --------\n        .. manim:: GetBarLabelsExample\n            :save_last_frame:\n\n            class GetBarLabelsExample(Scene):\n                def construct(self):\n                    chart = BarChart(values=[10, 9, 8, 7, 6, 5, 4, 3, 2, 1], y_range=[0, 10, 1])\n\n                    c_bar_lbls = chart.get_bar_labels(\n                        color=WHITE, label_constructor=MathTex, font_size=36\n                    )\n\n                    self.add(chart, c_bar_lbls)\n        \"\"\"\n        bar_labels = VGroup()\n        for bar, value in zip(self.bars, self.values, strict=False):\n            bar_lbl: MathTex = label_constructor(str(value))\n\n            if color is None:\n                bar_lbl.set_color(bar.get_fill_color())\n            else:\n                bar_lbl.set_color(color)\n\n            bar_lbl.font_size = font_size\n\n            pos = UP if (value >= 0) else DOWN\n            bar_lbl.next_to(bar, pos, buff=buff)\n            bar_labels.add(bar_lbl)\n\n        return bar_labels\n\n    def change_bar_values(\n        self, values: Iterable[float], update_colors: bool = True\n    ) -> None:\n        \"\"\"Updates the height of the bars of the chart.\n\n        Parameters\n        ----------\n        values\n            The values that will be used to update the height of the bars.\n            Does not have to match the number of bars.\n        update_colors\n            Whether to re-initalize the colors of the bars based on ``self.bar_colors``.\n\n        Examples\n        --------\n        .. manim:: ChangeBarValuesExample\n            :save_last_frame:\n\n            class ChangeBarValuesExample(Scene):\n                def construct(self):\n                    values=[-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10]\n\n                    chart = BarChart(\n                        values,\n                        y_range=[-10, 10, 2],\n                        y_axis_config={\"font_size\": 24},\n                    )\n                    self.add(chart)\n\n                    chart.change_bar_values(list(reversed(values)))\n                    self.add(chart.get_bar_labels(font_size=24))\n        \"\"\"\n        for i, (bar, value) in enumerate(zip(self.bars, values, strict=False)):\n            chart_val = self.values[i]\n\n            if chart_val > 0:\n                bar_lim = bar.get_bottom()\n                aligned_edge = DOWN\n            else:\n                bar_lim = bar.get_top()\n                aligned_edge = UP\n\n            # check if the bar has height\n            if chart_val != 0:\n                quotient = value / chart_val\n                if quotient < 0:\n                    aligned_edge = UP if chart_val > 0 else DOWN\n\n                    # if the bar is already positive, then we now want to move it\n                    # so that it is negative. So, we move the top edge of the bar\n                    # to the location of the previous bottom\n\n                    # if already negative, then we move the bottom edge of the bar\n                    # to the location of the previous top\n\n                bar.stretch_to_fit_height(abs(quotient) * bar.height)\n\n            else:\n                # create a new bar since the current one has a height of zero (doesn't exist)\n                temp_bar = self._create_bar(i, value)\n                self.bars.remove(bar)\n                self.bars.insert(i, temp_bar)\n\n            bar.move_to(bar_lim, aligned_edge)\n\n        if update_colors:\n            self._update_colors()\n\n        self.values[: len(list(values))] = values\n"
  },
  {
    "path": "manim/mobject/graphing/scale.py",
    "content": "from __future__ import annotations\n\nimport math\nfrom collections.abc import Iterable\nfrom typing import TYPE_CHECKING, Any, overload\n\nimport numpy as np\n\n__all__ = [\"LogBase\", \"LinearBase\"]\n\nfrom manim.mobject.text.numbers import Integer\n\nif TYPE_CHECKING:\n    from collections.abc import Callable\n\n    from manim.mobject.types.vectorized_mobject import VMobject\n\n\nclass _ScaleBase:\n    \"\"\"Scale baseclass for graphing/functions.\n\n    Parameters\n    ----------\n    custom_labels\n        Whether to create custom labels when plotted on a :class:`~.NumberLine`.\n    \"\"\"\n\n    def __init__(self, custom_labels: bool = False):\n        self.custom_labels = custom_labels\n\n    @overload\n    def function(self, value: float) -> float: ...\n\n    @overload\n    def function(self, value: np.ndarray) -> np.ndarray: ...\n\n    def function(self, value: float) -> float:\n        \"\"\"The function that will be used to scale the values.\n\n        Parameters\n        ----------\n        value\n            The number/``np.ndarray`` to be scaled.\n\n        Returns\n        -------\n        float\n            The value after it has undergone the scaling.\n\n        Raises\n        ------\n        NotImplementedError\n            Must be subclassed.\n        \"\"\"\n        raise NotImplementedError\n\n    def inverse_function(self, value: float) -> float:\n        \"\"\"The inverse of ``function``. Used for plotting on a particular axis.\n\n        Raises\n        ------\n        NotImplementedError\n            Must be subclassed.\n        \"\"\"\n        raise NotImplementedError\n\n    def get_custom_labels(\n        self,\n        val_range: Iterable[float],\n        **kw_args: Any,\n    ) -> Iterable[VMobject]:\n        \"\"\"Custom instructions for generating labels along an axis.\n\n        Parameters\n        ----------\n        val_range\n            The position of labels. Also used for defining the content of the labels.\n\n        Returns\n        -------\n        Dict\n            A list consisting of the labels.\n            Can be passed to :meth:`~.NumberLine.add_labels() along with ``val_range``.\n\n        Raises\n        ------\n        NotImplementedError\n            Can be subclassed, optional.\n        \"\"\"\n        raise NotImplementedError\n\n\nclass LinearBase(_ScaleBase):\n    def __init__(self, scale_factor: float = 1.0):\n        \"\"\"The default scaling class.\n\n        Parameters\n        ----------\n        scale_factor\n            The slope of the linear function, by default 1.0\n        \"\"\"\n        super().__init__()\n        self.scale_factor = scale_factor\n\n    def function(self, value: float) -> float:\n        \"\"\"Multiplies the value by the scale factor.\n\n        Parameters\n        ----------\n        value\n            Value to be multiplied by the scale factor.\n        \"\"\"\n        return self.scale_factor * value\n\n    def inverse_function(self, value: float) -> float:\n        \"\"\"Inverse of function. Divides the value by the scale factor.\n\n        Parameters\n        ----------\n        value\n            value to be divided by the scale factor.\n        \"\"\"\n        return value / self.scale_factor\n\n\nclass LogBase(_ScaleBase):\n    def __init__(self, base: float = 10, custom_labels: bool = True):\n        \"\"\"Scale for logarithmic graphs/functions.\n\n        Parameters\n        ----------\n        base\n            The base of the log, by default 10.\n        custom_labels\n            For use with :class:`~.Axes`:\n            Whether or not to include ``LaTeX`` axis labels, by default True.\n\n        Examples\n        --------\n        .. code-block:: python\n\n            func = ParametricFunction(lambda x: x, scaling=LogBase(base=2))\n\n        \"\"\"\n        super().__init__()\n        self.base = base\n        self.custom_labels = custom_labels\n\n    def function(self, value: float) -> float:\n        \"\"\"Scales the value to fit it to a logarithmic scale.``self.function(5)==10**5``\"\"\"\n        return_value: float = self.base**value\n        return return_value\n\n    def inverse_function(self, value: float) -> float:\n        \"\"\"Inverse of ``function``. The value must be greater than 0\"\"\"\n        if isinstance(value, np.ndarray):\n            condition = value.any() <= 0\n\n            func: Callable[[float, float], float]\n\n            def func(value: float, base: float) -> float:\n                return_value: float = np.log(value) / np.log(base)\n                return return_value\n        else:\n            condition = value <= 0\n            func = math.log\n\n        if condition:\n            raise ValueError(\n                \"log(0) is undefined. Make sure the value is in the domain of the function\"\n            )\n        value = func(value, self.base)\n        return value\n\n    def get_custom_labels(\n        self,\n        val_range: Iterable[float],\n        unit_decimal_places: int = 0,\n        **base_config: Any,\n    ) -> list[Integer]:\n        \"\"\"Produces custom :class:`~.Integer` labels in the form of ``10^2``.\n\n        Parameters\n        ----------\n        val_range\n            The iterable of values used to create the labels. Determines the exponent.\n        unit_decimal_places\n            The number of decimal places to include in the exponent\n        base_config\n            Additional arguments to be passed to :class:`~.Integer`.\n        \"\"\"\n        # uses `format` syntax to control the number of decimal places.\n        tex_labels: list[Integer] = [\n            Integer(\n                self.base,\n                unit=\"^{%s}\" % (f\"{self.inverse_function(i):.{unit_decimal_places}f}\"),  # noqa: UP031\n                **base_config,\n            )\n            for i in val_range\n        ]\n        return tex_labels\n"
  },
  {
    "path": "manim/mobject/logo.py",
    "content": "\"\"\"Utilities for Manim's logo and banner.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"ManimBanner\"]\n\nfrom typing import Any\n\nimport svgelements as se\n\nfrom manim.animation.updaters.update import UpdateFromAlphaFunc\nfrom manim.mobject.geometry.arc import Circle\nfrom manim.mobject.geometry.polygram import Square, Triangle\nfrom manim.mobject.mobject import Mobject\nfrom manim.typing import Vector3D\n\nfrom .. import constants as cst\nfrom ..animation.animation import override_animation\nfrom ..animation.composition import AnimationGroup, Succession\nfrom ..animation.creation import Create, SpiralIn\nfrom ..animation.fading import FadeIn\nfrom ..mobject.svg.svg_mobject import VMobjectFromSVGPath\nfrom ..mobject.types.vectorized_mobject import VGroup\nfrom ..utils.rate_functions import ease_in_out_cubic, smooth\n\nMANIM_SVG_PATHS: list[se.Path] = [\n    se.Path(  # double stroke letter M\n        \"M4.64259-2.092154L2.739726-6.625156C2.660025-6.824408 2.650062-6.824408 \"\n        \"2.381071-6.824408H.52802C.348692-6.824408 .199253-6.824408 .199253-6.645\"\n        \"081C.199253-6.475716 .37858-6.475716 .428394-6.475716C.547945-6.475716 .\"\n        \"816936-6.455791 1.036115-6.37609V-1.05604C1.036115-.846824 1.036115-.408\"\n        \"468 .358655-.348692C.169365-.328767 .169365-.18929 .169365-.179328C.1693\"\n        \"65 0 .328767 0 .508095 0H2.052304C2.231631 0 2.381071 0 2.381071-.179328\"\n        \"C2.381071-.268991 2.30137-.33873 2.221669-.348692C1.454545-.408468 1.454\"\n        \"545-.826899 1.454545-1.05604V-6.017435L1.464508-6.027397L3.895392-.20921\"\n        \"5C3.975093-.029888 4.044832 0 4.104608 0C4.224159 0 4.254047-.079701 4.3\"\n        \"03861-.199253L6.744707-6.027397L6.75467-6.017435V-1.05604C6.75467-.84682\"\n        \"4 6.75467-.408468 6.07721-.348692C5.88792-.328767 5.88792-.18929 5.88792\"\n        \"-.179328C5.88792 0 6.047323 0 6.22665 0H8.886675C9.066002 0 9.215442 0 9\"\n        \".215442-.179328C9.215442-.268991 9.135741-.33873 9.05604-.348692C8.28891\"\n        \"7-.408468 8.288917-.826899 8.288917-1.05604V-5.768369C8.288917-5.977584 \"\n        \"8.288917-6.41594 8.966376-6.475716C9.066002-6.485679 9.155666-6.535492 9\"\n        \".155666-6.645081C9.155666-6.824408 9.006227-6.824408 8.826899-6.824408H6\"\n        \".90411C6.645081-6.824408 6.625156-6.824408 6.535492-6.615193L4.64259-2.0\"\n        \"92154ZM4.343711-1.912827C4.423412-1.743462 4.433375-1.733499 4.552927-1.\"\n        \"693649L4.11457-.637609H4.094645L1.823163-6.057285C1.77335-6.1868 1.69364\"\n        \"9-6.356164 1.554172-6.475716H2.420922L4.343711-1.912827ZM1.334994-.34869\"\n        \"2H1.165629C1.185554-.37858 1.205479-.408468 1.225405-.428394C1.235367-.4\"\n        \"38356 1.235367-.448319 1.24533-.458281L1.334994-.348692ZM7.103362-6.4757\"\n        \"16H8.159402C7.940224-6.22665 7.940224-5.967621 7.940224-5.788294V-1.0361\"\n        \"15C7.940224-.856787 7.940224-.597758 8.169365-.348692H6.884184C7.103362-\"\n        \".597758 7.103362-.856787 7.103362-1.036115V-6.475716Z\"\n    ),\n    se.Path(  # letter a\n        \"M1.464508-4.024907C1.464508-4.234122 1.743462-4.393524 2.092154-4.393524\"\n        \"C2.669988-4.393524 2.929016-4.124533 2.929016-3.516812V-2.789539C1.77335\"\n        \"-2.440847 .249066-2.042341 .249066-.916563C.249066-.308842 .71731 .13947\"\n        \"7 1.354919 .139477C1.92279 .139477 2.381071-.059776 2.929016-.557908C3.0\"\n        \"38605-.049813 3.257783 .139477 3.745953 .139477C4.174346 .139477 4.48318\"\n        \"8-.019925 4.861768-.428394L4.712329-.637609L4.612702-.537983C4.582814-.5\"\n        \"08095 4.552927-.498132 4.503113-.498132C4.363636-.498132 4.293898-.58779\"\n        \"6 4.293898-.747198V-3.347447C4.293898-4.184309 3.536737-4.712329 2.32129\"\n        \"5-4.712329C1.195517-4.712329 .438356-4.204234 .438356-3.457036C.438356-3\"\n        \".048568 .67746-2.799502 1.085928-2.799502C1.484433-2.799502 1.763387-3.0\"\n        \"38605 1.763387-3.377335C1.763387-3.676214 1.464508-3.88543 1.464508-4.02\"\n        \"4907ZM2.919054-.996264C2.650062-.687422 2.450809-.56787 2.211706-.56787C\"\n        \"1.912827-.56787 1.703611-.836862 1.703611-1.235367C1.703611-1.8132 2.122\"\n        \"042-2.231631 2.919054-2.440847V-.996264Z\"\n    ),\n    se.Path(  # letter n\n        \"M2.948941-4.044832C3.297634-4.044832 3.466999-3.775841 3.466999-3.217933\"\n        \"V-.806974C3.466999-.438356 3.337484-.278954 2.998755-.239103V0H5.339975V\"\n        \"-.239103C4.951432-.268991 4.851806-.388543 4.851806-.806974V-3.307597C4.\"\n        \"851806-4.164384 4.323786-4.712329 3.506849-4.712329C2.909091-4.712329 2.\"\n        \"450809-4.433375 2.082192-3.845579V-4.592777H.179328V-4.353674C.617684-4.\"\n        \"283935 .707347-4.184309 .707347-3.765878V-.836862C.707347-.418431 .62764\"\n        \"6-.328767 .179328-.239103V0H2.580324V-.239103C2.211706-.288917 2.092154-\"\n        \".438356 2.092154-.806974V-3.466999C2.092154-3.576588 2.530511-4.044832 2\"\n        \".948941-4.044832Z\"\n    ),\n    se.Path(  # letter i\n        \"M2.15193-4.592777H.239103V-4.353674C.67746-4.26401 .767123-4.174346 .767\"\n        \"123-3.765878V-.836862C.767123-.428394 .697385-.348692 .239103-.239103V0H\"\n        \"2.6401V-.239103C2.291407-.288917 2.15193-.428394 2.15193-.806974V-4.5927\"\n        \"77ZM1.454545-6.884184C1.026152-6.884184 .67746-6.535492 .67746-6.117061C\"\n        \".67746-5.668742 1.006227-5.339975 1.444583-5.339975S2.221669-5.668742 2.\"\n        \"221669-6.107098C2.221669-6.535492 1.882939-6.884184 1.454545-6.884184Z\"\n    ),\n    se.Path(  # letter m\n        \"M2.929016-4.044832C3.317559-4.044832 3.466999-3.815691 3.466999-3.217933\"\n        \"V-.806974C3.466999-.398506 3.35741-.268991 2.988792-.239103V0H5.32005V-.\"\n        \"239103C4.971357-.278954 4.851806-.428394 4.851806-.806974V-3.466999C4.85\"\n        \"1806-3.576588 5.310087-4.044832 5.69863-4.044832C6.07721-4.044832 6.2266\"\n        \"5-3.805729 6.22665-3.217933V-.806974C6.22665-.388543 6.117061-.268991 5.\"\n        \"738481-.239103V0H8.109589V-.239103C7.721046-.259029 7.611457-.37858 7.61\"\n        \"1457-.806974V-3.307597C7.611457-4.164384 7.083437-4.712329 6.266501-4.71\"\n        \"2329C5.69863-4.712329 5.32005-4.483188 4.801993-3.845579C4.503113-4.4732\"\n        \"25 4.154421-4.712329 3.526775-4.712329S2.440847-4.443337 2.062267-3.8455\"\n        \"79V-4.592777H.179328V-4.353674C.617684-4.293898 .707347-4.174346 .707347\"\n        \"-3.765878V-.836862C.707347-.428394 .617684-.318804 .179328-.239103V0H2.5\"\n        \"50436V-.239103C2.201743-.288917 2.092154-.428394 2.092154-.806974V-3.466\"\n        \"999C2.092154-3.58655 2.530511-4.044832 2.929016-4.044832Z\"\n    ),\n]\n\n\nclass ManimBanner(VGroup):\n    r\"\"\"Convenience class representing Manim's banner.\n\n    Can be animated using custom methods.\n\n    Parameters\n    ----------\n    dark_theme\n        If ``True`` (the default), the dark theme version of the logo\n        (with light text font) will be rendered. Otherwise, if ``False``,\n        the light theme version (with dark text font) is used.\n\n    Examples\n    --------\n    .. manim:: DarkThemeBanner\n\n        class DarkThemeBanner(Scene):\n            def construct(self):\n                banner = ManimBanner()\n                self.play(banner.create())\n                self.play(banner.expand())\n                self.wait()\n                self.play(Unwrite(banner))\n\n    .. manim:: LightThemeBanner\n\n        class LightThemeBanner(Scene):\n            def construct(self):\n                self.camera.background_color = \"#ece6e2\"\n                banner = ManimBanner(dark_theme=False)\n                self.play(banner.create())\n                self.play(banner.expand())\n                self.wait()\n                self.play(Unwrite(banner))\n\n    \"\"\"\n\n    def __init__(self, dark_theme: bool = True):\n        super().__init__()\n\n        logo_green = \"#81b29a\"\n        logo_blue = \"#454866\"\n        logo_red = \"#e07a5f\"\n        m_height_over_anim_height = 0.75748\n\n        self.font_color = \"#ece6e2\" if dark_theme else \"#343434\"\n        self.scale_factor = 1.0\n\n        self.M = VMobjectFromSVGPath(MANIM_SVG_PATHS[0]).flip(cst.RIGHT).center()\n        self.M.set(stroke_width=0).scale(\n            7 * cst.DEFAULT_FONT_SIZE * cst.SCALE_FACTOR_PER_FONT_POINT\n        )\n        self.M.set_fill(color=self.font_color, opacity=1).shift(\n            2.25 * cst.LEFT + 1.5 * cst.UP\n        )\n\n        self.circle = Circle(color=logo_green, fill_opacity=1).shift(cst.LEFT)\n        self.square = Square(color=logo_blue, fill_opacity=1).shift(cst.UP)\n        self.triangle = Triangle(color=logo_red, fill_opacity=1).shift(cst.RIGHT)\n        self.shapes = VGroup(self.triangle, self.square, self.circle)\n        self.add(self.shapes, self.M)\n        self.move_to(cst.ORIGIN)\n\n        anim = VGroup()\n        for ind, path in enumerate(MANIM_SVG_PATHS[1:]):\n            tex = VMobjectFromSVGPath(path).flip(cst.RIGHT).center()\n            tex.set(stroke_width=0).scale(\n                cst.DEFAULT_FONT_SIZE * cst.SCALE_FACTOR_PER_FONT_POINT\n            )\n            if ind > 0:\n                tex.next_to(anim, buff=0.01)\n            tex.align_to(self.M, cst.DOWN)\n            anim.add(tex)\n        anim.set_fill(color=self.font_color, opacity=1)\n        anim.height = m_height_over_anim_height * self.M.height\n\n        # Note: \"anim\" is only shown in the expanded state\n        # and thus not yet added to the submobjects of self.\n        self.anim = anim\n\n    def scale(self, scale_factor: float, **kwargs: Any) -> ManimBanner:\n        \"\"\"Scale the banner by the specified scale factor.\n\n        Parameters\n        ----------\n        scale_factor\n            The factor used for scaling the banner.\n\n        Returns\n        -------\n        :class:`~.ManimBanner`\n            The scaled banner.\n        \"\"\"\n        self.scale_factor *= scale_factor\n        # Note: self.anim is only added to self after expand()\n        if self.anim not in self.submobjects:\n            self.anim.scale(scale_factor, **kwargs)\n        return super().scale(scale_factor, **kwargs)\n\n    @override_animation(Create)\n    def create(self, run_time: float = 2) -> AnimationGroup:\n        \"\"\"The creation animation for Manim's logo.\n\n        Parameters\n        ----------\n        run_time\n            The run time of the animation.\n\n        Returns\n        -------\n        :class:`~.AnimationGroup`\n            An animation to be used in a :meth:`.Scene.play` call.\n        \"\"\"\n        return AnimationGroup(\n            SpiralIn(self.shapes, run_time=run_time),\n            FadeIn(self.M, run_time=run_time / 2),\n            lag_ratio=0.1,\n        )\n\n    def expand(self, run_time: float = 1.5, direction: str = \"center\") -> Succession:\n        \"\"\"An animation that expands Manim's logo into its banner.\n\n        The returned animation transforms the banner from its initial\n        state (representing Manim's logo with just the icons) to its\n        expanded state (showing the full name together with the icons).\n\n        See the class documentation for how to use this.\n\n        .. note::\n\n            Before calling this method, the text \"anim\" is not a\n            submobject of the banner object. After the expansion,\n            it is added as a submobject so subsequent animations\n            to the banner object apply to the text \"anim\" as well.\n\n        Parameters\n        ----------\n        run_time\n            The run time of the animation.\n        direction\n            The direction in which the logo is expanded.\n\n        Returns\n        -------\n        :class:`~.Succession`\n            An animation to be used in a :meth:`.Scene.play` call.\n\n        Examples\n        --------\n        .. manim:: ExpandDirections\n\n            class ExpandDirections(Scene):\n                def construct(self):\n                    banners = [ManimBanner().scale(0.5).shift(UP*x) for x in [-2, 0, 2]]\n                    self.play(\n                        banners[0].expand(direction=\"right\"),\n                        banners[1].expand(direction=\"center\"),\n                        banners[2].expand(direction=\"left\"),\n                    )\n\n        \"\"\"\n        if direction not in [\"left\", \"right\", \"center\"]:\n            raise ValueError(\"direction must be 'left', 'right' or 'center'.\")\n\n        m_shape_offset = 6.25 * self.scale_factor\n        shape_sliding_overshoot = self.scale_factor * 0.8\n        m_anim_buff = 0.06\n        self.anim.next_to(self.M, buff=m_anim_buff).align_to(self.M, cst.DOWN)\n        self.anim.set_opacity(0)\n        self.shapes.save_state()\n        m_clone = self.anim[-1].copy()\n        self.add(m_clone)\n        m_clone.move_to(self.shapes)\n\n        self.M.save_state()\n        left_group = VGroup(self.M, self.anim, m_clone)\n\n        def shift(vector: Vector3D) -> None:\n            self.shapes.restore()\n            left_group.align_to(self.M.saved_state, cst.LEFT)\n            if direction == \"right\":\n                self.shapes.shift(vector)\n            elif direction == \"center\":\n                self.shapes.shift(vector / 2)\n                left_group.shift(-vector / 2)\n            elif direction == \"left\":\n                left_group.shift(-vector)\n\n        def slide_and_uncover(mob: Mobject, alpha: float) -> None:\n            shift(alpha * (m_shape_offset + shape_sliding_overshoot) * cst.RIGHT)\n\n            # Add letters when they are covered\n            for letter in mob.anim:\n                if mob.square.get_center()[0] > letter.get_center()[0]:\n                    letter.set_opacity(1)\n                    self.add_to_back(letter)\n\n            # Finish animation\n            if alpha == 1:\n                self.remove(*[self.anim])\n                self.add_to_back(self.anim)\n                mob.shapes.set_z_index(0)\n                mob.shapes.save_state()\n                mob.M.save_state()\n\n        def slide_back(mob: Mobject, alpha: float) -> None:\n            if alpha == 0:\n                m_clone.set_opacity(1)\n                m_clone.move_to(mob.anim[-1])\n                mob.anim.set_opacity(1)\n\n            shift(alpha * shape_sliding_overshoot * cst.LEFT)\n\n            if alpha == 1:\n                mob.remove(m_clone)\n                mob.add_to_back(mob.shapes)\n\n        return Succession(\n            UpdateFromAlphaFunc(\n                self,\n                slide_and_uncover,\n                run_time=run_time * 2 / 3,\n                rate_func=ease_in_out_cubic,\n            ),\n            UpdateFromAlphaFunc(\n                self,\n                slide_back,\n                run_time=run_time * 1 / 3,\n                rate_func=smooth,\n            ),\n        )\n"
  },
  {
    "path": "manim/mobject/matrix.py",
    "content": "r\"\"\"Mobjects representing matrices.\n\nExamples\n--------\n\n.. manim:: MatrixExamples\n    :save_last_frame:\n\n    class MatrixExamples(Scene):\n        def construct(self):\n            m0 = Matrix([[\"\\\\pi\", 0], [-1, 1]])\n            m1 = IntegerMatrix([[1.5, 0.], [12, -1.3]],\n                left_bracket=\"(\",\n                right_bracket=\")\")\n            m2 = DecimalMatrix(\n                [[3.456, 2.122], [33.2244, 12.33]],\n                element_to_mobject_config={\"num_decimal_places\": 2},\n                left_bracket=r\"\\{\",\n                right_bracket=r\"\\}\")\n            m3 = MobjectMatrix(\n                [[Circle().scale(0.3), Square().scale(0.3)],\n                [MathTex(\"\\\\pi\").scale(2), Star().scale(0.3)]],\n                left_bracket=\"\\\\langle\",\n                right_bracket=\"\\\\rangle\")\n            g = Group(m0, m1, m2, m3).arrange_in_grid(buff=2)\n            self.add(g)\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"Matrix\",\n    \"DecimalMatrix\",\n    \"IntegerMatrix\",\n    \"MobjectMatrix\",\n    \"matrix_to_tex_string\",\n    \"matrix_to_mobject\",\n    \"get_det_text\",\n]\n\n\nimport itertools as it\nfrom collections.abc import Callable, Iterable\nfrom typing import Any, Self\n\nimport numpy as np\n\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.text.numbers import DecimalNumber, Integer\nfrom manim.mobject.text.tex_mobject import MathTex, Tex\nfrom manim.typing import Vector2DLike, Vector3DLike\n\nfrom ..constants import *\nfrom ..mobject.types.vectorized_mobject import VGroup, VMobject\n\n# TO DO : The following two functions are not used in this file.\n#         Not sure if we should keep it or not.\n\n\ndef matrix_to_tex_string(matrix: np.ndarray) -> str:\n    matrix = np.array(matrix).astype(\"str\")\n    if matrix.ndim == 1:\n        matrix = matrix.reshape((matrix.size, 1))\n    n_rows, n_cols = matrix.shape\n    prefix = \"\\\\left[ \\\\begin{array}{%s}\" % (\"c\" * n_cols)\n    suffix = \"\\\\end{array} \\\\right]\"\n    rows = [\" & \".join(row) for row in matrix]\n    return prefix + \" \\\\\\\\ \".join(rows) + suffix\n\n\ndef matrix_to_mobject(matrix: np.ndarray) -> MathTex:\n    return MathTex(matrix_to_tex_string(matrix))\n\n\nclass Matrix(VMobject, metaclass=ConvertToOpenGL):\n    r\"\"\"A mobject that displays a matrix on the screen.\n\n    Parameters\n    ----------\n    matrix\n        A numpy 2d array or list of lists.\n    v_buff\n        Vertical distance between elements, by default 0.8.\n    h_buff\n        Horizontal distance between elements, by default 1.3.\n    bracket_h_buff\n        Distance of the brackets from the matrix, by default ``MED_SMALL_BUFF``.\n    bracket_v_buff\n        Height of the brackets, by default ``MED_SMALL_BUFF``.\n    add_background_rectangles_to_entries\n        ``True`` if should add backgraound rectangles to entries, by default ``False``.\n    include_background_rectangle\n        ``True`` if should include background rectangle, by default ``False``.\n    element_to_mobject\n        The mobject class used to construct the elements, by default :class:`~.MathTex`.\n    element_to_mobject_config\n        Additional arguments to be passed to the constructor in ``element_to_mobject``,\n        by default ``{}``.\n    element_alignment_corner\n        The corner to which elements are aligned, by default ``DR``.\n    left_bracket\n        The left bracket type, by default ``\"[\"``.\n    right_bracket\n        The right bracket type, by default ``\"]\"``.\n    stretch_brackets\n        ``True`` if should stretch the brackets to fit the height of matrix contents, by default ``True``.\n    bracket_config\n        Additional arguments to be passed to :class:`~.MathTex` when constructing\n        the brackets.\n\n    Examples\n    --------\n    The first example shows a variety of uses of this module while the second example\n    exlpains the use of the options `add_background_rectangles_to_entries` and\n    `include_background_rectangle`.\n\n    .. manim:: MatrixExamples\n        :save_last_frame:\n\n        class MatrixExamples(Scene):\n            def construct(self):\n                m0 = Matrix([[2, r\"\\pi\"], [-1, 1]])\n                m1 = Matrix([[2, 0, 4], [-1, 1, 5]],\n                    v_buff=1.3,\n                    h_buff=0.8,\n                    bracket_h_buff=SMALL_BUFF,\n                    bracket_v_buff=SMALL_BUFF,\n                    left_bracket=r\"\\{\",\n                    right_bracket=r\"\\}\")\n                m1.add(SurroundingRectangle(m1.get_columns()[1]))\n                m2 = Matrix([[2, 1], [-1, 3]],\n                    element_alignment_corner=UL,\n                    left_bracket=\"(\",\n                    right_bracket=\")\")\n                m3 = Matrix([[2, 1], [-1, 3]],\n                    left_bracket=r\"\\langle\",\n                    right_bracket=r\"\\rangle\")\n                m4 = Matrix([[2, 1], [-1, 3]],\n                ).set_column_colors(RED, GREEN)\n                m5 = Matrix([[2, 1], [-1, 3]],\n                ).set_row_colors(RED, GREEN)\n                g = Group(\n                    m0,m1,m2,m3,m4,m5\n                ).arrange_in_grid(buff=2)\n                self.add(g)\n\n    .. manim:: BackgroundRectanglesExample\n        :save_last_frame:\n\n        class BackgroundRectanglesExample(Scene):\n            def construct(self):\n                background= Rectangle().scale(3.2)\n                background.set_fill(opacity=.5)\n                background.set_color([TEAL, RED, YELLOW])\n                self.add(background)\n                m0 = Matrix([[12, -30], [-1, 15]],\n                    add_background_rectangles_to_entries=True)\n                m1 = Matrix([[2, 0], [-1, 1]],\n                    include_background_rectangle=True)\n                m2 = Matrix([[12, -30], [-1, 15]])\n                g = Group(m0, m1, m2).arrange(buff=2)\n                self.add(g)\n    \"\"\"\n\n    def __init__(\n        self,\n        matrix: Iterable[Iterable[Any] | Vector2DLike],\n        v_buff: float = 0.8,\n        h_buff: float = 1.3,\n        bracket_h_buff: float = MED_SMALL_BUFF,\n        bracket_v_buff: float = MED_SMALL_BUFF,\n        add_background_rectangles_to_entries: bool = False,\n        include_background_rectangle: bool = False,\n        element_to_mobject: type[VMobject] | Callable[..., VMobject] = MathTex,\n        element_to_mobject_config: dict[str, Any] = {},\n        element_alignment_corner: Vector3DLike = DR,\n        left_bracket: str = \"[\",\n        right_bracket: str = \"]\",\n        stretch_brackets: bool = True,\n        bracket_config: dict = {},\n        **kwargs: Any,\n    ):\n        self.v_buff = v_buff\n        self.h_buff = h_buff\n        self.bracket_h_buff = bracket_h_buff\n        self.bracket_v_buff = bracket_v_buff\n        self.add_background_rectangles_to_entries = add_background_rectangles_to_entries\n        self.include_background_rectangle = include_background_rectangle\n        self.element_to_mobject = element_to_mobject\n        self.element_to_mobject_config = element_to_mobject_config\n        self.element_alignment_corner = element_alignment_corner\n        self.left_bracket = left_bracket\n        self.right_bracket = right_bracket\n        self.stretch_brackets = stretch_brackets\n        super().__init__(**kwargs)\n        mob_matrix = self._matrix_to_mob_matrix(matrix)\n        self._organize_mob_matrix(mob_matrix)\n        self.elements = VGroup(*it.chain(*mob_matrix))\n        self.add(self.elements)\n        self._add_brackets(self.left_bracket, self.right_bracket, **bracket_config)\n        self.center()\n        self.mob_matrix = mob_matrix\n        if self.add_background_rectangles_to_entries:\n            for mob in self.elements:\n                mob.add_background_rectangle()\n        if self.include_background_rectangle:\n            self.add_background_rectangle()\n\n    def _matrix_to_mob_matrix(\n        self, matrix: Iterable[Iterable[Any]]\n    ) -> list[list[VMobject]]:\n        return [\n            [\n                self.element_to_mobject(item, **self.element_to_mobject_config)\n                for item in row\n            ]\n            for row in matrix\n        ]\n\n    def _organize_mob_matrix(self, matrix: list[list[VMobject]]) -> Self:\n        for i, row in enumerate(matrix):\n            for j, _ in enumerate(row):\n                mob = matrix[i][j]\n                mob.move_to(\n                    i * self.v_buff * DOWN + j * self.h_buff * RIGHT,\n                    self.element_alignment_corner,\n                )\n        return self\n\n    def _add_brackets(self, left: str = \"[\", right: str = \"]\", **kwargs: Any) -> Self:\n        \"\"\"Adds the brackets to the Matrix mobject.\n\n        See Latex document for various bracket types.\n\n        Parameters\n        ----------\n        left\n            the left bracket, by default \"[\"\n        right\n            the right bracket, by default \"]\"\n\n        Returns\n        -------\n        :class:`Matrix`\n            The current matrix object (self).\n        \"\"\"\n        # Height per row of LaTeX array with default settings\n        BRACKET_HEIGHT = 0.5977\n\n        n = int((self.height) / BRACKET_HEIGHT) + 1\n        empty_tex_array = \"\".join(\n            [\n                r\"\\begin{array}{c}\",\n                *n * [r\"\\quad \\\\\"],\n                r\"\\end{array}\",\n            ]\n        )\n        tex_left = \"\".join(\n            [\n                r\"\\left\" + left,\n                empty_tex_array,\n                r\"\\right.\",\n            ]\n        )\n        tex_right = \"\".join(\n            [\n                r\"\\left.\",\n                empty_tex_array,\n                r\"\\right\" + right,\n            ]\n        )\n        l_bracket = MathTex(tex_left, **kwargs)\n        r_bracket = MathTex(tex_right, **kwargs)\n\n        bracket_pair = VGroup(l_bracket, r_bracket)\n        if self.stretch_brackets:\n            bracket_pair.stretch_to_fit_height(self.height + 2 * self.bracket_v_buff)\n        l_bracket.next_to(self, LEFT, self.bracket_h_buff)\n        r_bracket.next_to(self, RIGHT, self.bracket_h_buff)\n        self.brackets = bracket_pair\n        self.add(l_bracket, r_bracket)\n        return self\n\n    def get_columns(self) -> VGroup:\n        r\"\"\"Return columns of the matrix as VGroups.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            The VGroup contains a nested VGroup for each column of the matrix.\n\n        Examples\n        --------\n\n        .. manim:: GetColumnsExample\n            :save_last_frame:\n\n            class GetColumnsExample(Scene):\n                def construct(self):\n                    m0 = Matrix([[r\"\\pi\", 3], [1, 5]])\n                    m0.add(SurroundingRectangle(m0.get_columns()[1]))\n                    self.add(m0)\n        \"\"\"\n        return VGroup(\n            *(\n                VGroup(*(row[i] for row in self.mob_matrix))\n                for i in range(len(self.mob_matrix[0]))\n            )\n        )\n\n    def set_column_colors(self, *colors: str) -> Self:\n        r\"\"\"Set individual colors for each columns of the matrix.\n\n        Parameters\n        ----------\n        colors\n            The list of colors; each color specified corresponds to a column.\n\n        Returns\n        -------\n        :class:`Matrix`\n            The current matrix object (self).\n\n        Examples\n        --------\n\n        .. manim:: SetColumnColorsExample\n            :save_last_frame:\n\n            class SetColumnColorsExample(Scene):\n                def construct(self):\n                    m0 = Matrix([[\"\\\\pi\", 1], [-1, 3]],\n                    ).set_column_colors([RED,BLUE], GREEN)\n                    self.add(m0)\n        \"\"\"\n        columns = self.get_columns()\n        for color, column in zip(colors, columns, strict=False):\n            column.set_color(color)\n        return self\n\n    def get_rows(self) -> VGroup:\n        r\"\"\"Return rows of the matrix as VGroups.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            The VGroup contains a nested VGroup for each row of the matrix.\n\n        Examples\n        --------\n\n        .. manim:: GetRowsExample\n            :save_last_frame:\n\n            class GetRowsExample(Scene):\n                def construct(self):\n                    m0 = Matrix([[\"\\\\pi\", 3], [1, 5]])\n                    m0.add(SurroundingRectangle(m0.get_rows()[1]))\n                    self.add(m0)\n        \"\"\"\n        return VGroup(*(VGroup(*row) for row in self.mob_matrix))\n\n    def set_row_colors(self, *colors: str) -> Self:\n        r\"\"\"Set individual colors for each row of the matrix.\n\n        Parameters\n        ----------\n        colors\n            The list of colors; each color specified corresponds to a row.\n\n        Returns\n        -------\n        :class:`Matrix`\n            The current matrix object (self).\n\n        Examples\n        --------\n\n        .. manim:: SetRowColorsExample\n            :save_last_frame:\n\n            class SetRowColorsExample(Scene):\n                def construct(self):\n                    m0 = Matrix([[\"\\\\pi\", 1], [-1, 3]],\n                    ).set_row_colors([RED,BLUE], GREEN)\n                    self.add(m0)\n        \"\"\"\n        rows = self.get_rows()\n        for color, row in zip(colors, rows, strict=False):\n            row.set_color(color)\n        return self\n\n    def add_background_to_entries(self) -> Self:\n        \"\"\"Add a black background rectangle to the matrix,\n        see above for an example.\n\n        Returns\n        -------\n        :class:`Matrix`\n            The current matrix object (self).\n        \"\"\"\n        for mob in self.get_entries():\n            mob.add_background_rectangle()\n        return self\n\n    def get_mob_matrix(self) -> list[list[VMobject]]:\n        \"\"\"Return the underlying mob matrix mobjects.\n\n        Returns\n        --------\n        List[:class:`~.VGroup`]\n            Each VGroup contains a row of the matrix.\n        \"\"\"\n        return self.mob_matrix\n\n    def get_entries(self) -> VGroup:\n        \"\"\"Return the individual entries of the matrix.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            VGroup containing entries of the matrix.\n\n        Examples\n        --------\n\n        .. manim:: GetEntriesExample\n            :save_last_frame:\n\n            class GetEntriesExample(Scene):\n                def construct(self):\n                    m0 = Matrix([[2, 3], [1, 5]])\n                    ent = m0.get_entries()\n                    colors = [BLUE, GREEN, YELLOW, RED]\n                    for k in range(len(colors)):\n                        ent[k].set_color(colors[k])\n                    self.add(m0)\n        \"\"\"\n        return self.elements\n\n    def get_brackets(self) -> VGroup:\n        r\"\"\"Return the bracket mobjects.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            A VGroup containing the left and right bracket.\n\n        Examples\n        --------\n\n        .. manim:: GetBracketsExample\n            :save_last_frame:\n\n            class GetBracketsExample(Scene):\n                def construct(self):\n                    m0 = Matrix([[\"\\\\pi\", 3], [1, 5]])\n                    bra = m0.get_brackets()\n                    colors = [BLUE, GREEN]\n                    for k in range(len(colors)):\n                        bra[k].set_color(colors[k])\n                    self.add(m0)\n        \"\"\"\n        return self.brackets\n\n\nclass DecimalMatrix(Matrix):\n    r\"\"\"A mobject that displays a matrix with decimal entries on the screen.\n\n    Examples\n    --------\n\n    .. manim:: DecimalMatrixExample\n        :save_last_frame:\n\n        class DecimalMatrixExample(Scene):\n            def construct(self):\n                m0 = DecimalMatrix(\n                    [[3.456, 2.122], [33.2244, 12]],\n                    element_to_mobject_config={\"num_decimal_places\": 2},\n                    left_bracket=\"\\\\{\",\n                    right_bracket=\"\\\\}\")\n                self.add(m0)\n    \"\"\"\n\n    def __init__(\n        self,\n        matrix: Iterable[Iterable[Any]],\n        element_to_mobject: type[VMobject] | Callable[..., VMobject] = DecimalNumber,\n        element_to_mobject_config: dict[str, Any] = {\"num_decimal_places\": 1},\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Will round/truncate the decimal places as per the provided config.\n\n        Parameters\n        ----------\n        matrix\n            A numpy 2d array or list of lists\n        element_to_mobject\n            Mobject to use, by default DecimalNumber\n        element_to_mobject_config\n            Config for the desired mobject, by default {\"num_decimal_places\": 1}\n        \"\"\"\n        super().__init__(\n            matrix,\n            element_to_mobject=element_to_mobject,\n            element_to_mobject_config=element_to_mobject_config,\n            **kwargs,\n        )\n\n\nclass IntegerMatrix(Matrix):\n    \"\"\"A mobject that displays a matrix with integer entries on the screen.\n\n    Examples\n    --------\n\n    .. manim:: IntegerMatrixExample\n        :save_last_frame:\n\n        class IntegerMatrixExample(Scene):\n            def construct(self):\n                m0 = IntegerMatrix(\n                    [[3.7, 2], [42.2, 12]],\n                    left_bracket=\"(\",\n                    right_bracket=\")\")\n                self.add(m0)\n    \"\"\"\n\n    def __init__(\n        self,\n        matrix: Iterable[Iterable[Any]],\n        element_to_mobject: type[VMobject] | Callable[..., VMobject] = Integer,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Will round if there are decimal entries in the matrix.\n\n        Parameters\n        ----------\n        matrix\n            A numpy 2d array or list of lists\n        element_to_mobject\n            Mobject to use, by default Integer\n        \"\"\"\n        super().__init__(matrix, element_to_mobject=element_to_mobject, **kwargs)\n\n\nclass MobjectMatrix(Matrix):\n    r\"\"\"A mobject that displays a matrix of mobject entries on the screen.\n\n    Examples\n    --------\n\n    .. manim:: MobjectMatrixExample\n        :save_last_frame:\n\n        class MobjectMatrixExample(Scene):\n            def construct(self):\n                a = Circle().scale(0.3)\n                b = Square().scale(0.3)\n                c = MathTex(\"\\\\pi\").scale(2)\n                d = Star().scale(0.3)\n                m0 = MobjectMatrix([[a, b], [c, d]])\n                self.add(m0)\n    \"\"\"\n\n    def __init__(\n        self,\n        matrix: Iterable[Iterable[Any]],\n        element_to_mobject: type[VMobject] | Callable[..., VMobject] = lambda m: m,\n        **kwargs: Any,\n    ):\n        super().__init__(matrix, element_to_mobject=element_to_mobject, **kwargs)\n\n\ndef get_det_text(\n    matrix: Matrix,\n    determinant: int | str | None = None,\n    background_rect: bool = False,\n    initial_scale_factor: float = 2,\n) -> VGroup:\n    r\"\"\"Helper function to create determinant.\n\n    Parameters\n    ----------\n    matrix\n        The matrix whose determinant is to be created\n\n    determinant\n        The value of the determinant of the matrix\n\n    background_rect\n        The background rectangle\n\n    initial_scale_factor\n        The scale of the text `det` w.r.t the matrix\n\n    Returns\n    --------\n    :class:`~.VGroup`\n        A VGroup containing the determinant\n\n    Examples\n    --------\n\n    .. manim:: DeterminantOfAMatrix\n        :save_last_frame:\n\n        class DeterminantOfAMatrix(Scene):\n            def construct(self):\n                matrix = Matrix([\n                    [2, 0],\n                    [-1, 1]\n                ])\n\n                # scaling down the `det` string\n                det = get_det_text(matrix,\n                            determinant=3,\n                            initial_scale_factor=1)\n\n                # must add the matrix\n                self.add(matrix)\n                self.add(det)\n    \"\"\"\n    parens = MathTex(\"(\", \")\")\n    parens.scale(initial_scale_factor)\n    parens.stretch_to_fit_height(matrix.height)\n    l_paren, r_paren = parens.split()\n    l_paren.next_to(matrix, LEFT, buff=0.1)\n    r_paren.next_to(matrix, RIGHT, buff=0.1)\n    det = Tex(\"det\")\n    det.scale(initial_scale_factor)\n    det.next_to(l_paren, LEFT, buff=0.1)\n    if background_rect:\n        det.add_background_rectangle()\n    det_text = VGroup(det, l_paren, r_paren)\n    if determinant is not None:\n        eq = MathTex(\"=\")\n        eq.next_to(r_paren, RIGHT, buff=0.1)\n        result = MathTex(str(determinant))\n        result.next_to(eq, RIGHT, buff=0.2)\n        det_text.add(eq, result)\n    return det_text\n"
  },
  {
    "path": "manim/mobject/mobject.py",
    "content": "\"\"\"Base classes for objects that can be displayed.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"Mobject\", \"Group\", \"override_animate\"]\n\n\nimport copy\nimport inspect\nimport itertools as it\nimport math\nimport operator as op\nimport random\nimport sys\nimport types\nimport warnings\nfrom collections.abc import Callable, Iterable, Iterator, Sequence\nfrom functools import partialmethod, reduce\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, Any, cast\n\nimport numpy as np\n\nfrom manim.data_structures import MethodWithArgs\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\n\nfrom .. import config, logger\nfrom ..constants import *\nfrom ..utils.color import (\n    BLACK,\n    PURE_YELLOW,\n    WHITE,\n    ManimColor,\n    ParsableManimColor,\n    color_gradient,\n    interpolate_color,\n)\nfrom ..utils.exceptions import MultiAnimationOverrideException\nfrom ..utils.iterables import list_update, remove_list_redundancies\nfrom ..utils.paths import straight_path\nfrom ..utils.space_ops import angle_between_vectors, normalize, rotation_matrix\n\nif TYPE_CHECKING:\n    from typing import Self, TypeAlias\n\n    from PIL import Image\n\n    from manim.mobject.types.point_cloud_mobject import Point\n    from manim.typing import (\n        FunctionOverride,\n        MappingFunction,\n        MatrixMN,\n        MultiMappingFunction,\n        PathFuncType,\n        Point3D,\n        Point3D_Array,\n        Point3DLike,\n        Point3DLike_Array,\n        Vector3D,\n        Vector3DLike,\n    )\n\n    from ..animation.animation import Animation\n    from ..camera.camera import Camera\n\n\n_TimeBasedUpdater: TypeAlias = Callable[[\"Mobject\", float], object]\n_NonTimeBasedUpdater: TypeAlias = Callable[[\"Mobject\"], object]\n_Updater: TypeAlias = _NonTimeBasedUpdater | _TimeBasedUpdater\n\n\nclass Mobject:\n    \"\"\"Mathematical Object: base class for objects that can be displayed on screen.\n\n    There is a compatibility layer that allows for\n    getting and setting generic attributes with ``get_*``\n    and ``set_*`` methods. See :meth:`set` for more details.\n\n    Attributes\n    ----------\n    submobjects : List[:class:`Mobject`]\n        The contained objects.\n    points : :class:`numpy.ndarray`\n        The points of the objects.\n\n        .. seealso::\n\n            :class:`~.VMobject`\n\n    \"\"\"\n\n    original_id: str\n    _original__init__: Callable[..., None]\n    animation_overrides: dict[\n        type[Animation],\n        FunctionOverride,\n    ] = {}\n\n    @classmethod\n    def __init_subclass__(cls, **kwargs: Any) -> None:\n        super().__init_subclass__(**kwargs)\n\n        cls.animation_overrides = {}\n        cls._add_intrinsic_animation_overrides()\n        cls._original__init__ = cls.__init__\n\n    def __init__(\n        self,\n        color: ParsableManimColor | list[ParsableManimColor] = WHITE,\n        name: str | None = None,\n        dim: int = 3,\n        target: Mobject | None = None,\n        z_index: float = 0,\n    ):\n        self.name = self.__class__.__name__ if name is None else name\n        self.dim = dim\n        self.target = target\n        self.z_index = z_index\n        self.point_hash = None\n        self.submobjects: list[Mobject] = []\n        self.updaters: list[_Updater] = []\n        self.updating_suspended = False\n        self.color = ManimColor.parse(color)\n\n        self.reset_points()\n        self.generate_points()\n        self.init_colors()\n\n    def _assert_valid_submobjects(self, submobjects: Iterable[Mobject]) -> Self:\n        \"\"\"Check that all submobjects are actually instances of\n        :class:`Mobject`, and that none of them is ``self`` (a\n        :class:`Mobject` cannot contain itself).\n\n        This is an auxiliary function called when adding Mobjects to the\n        :attr:`submobjects` list.\n\n        This function is intended to be overridden by subclasses such as\n        :class:`VMobject`, which should assert that only other VMobjects\n        may be added into it.\n\n        Parameters\n        ----------\n        submobjects\n            The list containing values to validate.\n\n        Returns\n        -------\n        :class:`Mobject`\n            The Mobject itself.\n\n        Raises\n        ------\n        TypeError\n            If any of the values in `submobjects` is not a :class:`Mobject`.\n        ValueError\n            If there was an attempt to add a :class:`Mobject` as its own\n            submobject.\n        \"\"\"\n        return self._assert_valid_submobjects_internal(submobjects, Mobject)\n\n    def _assert_valid_submobjects_internal(\n        self, submobjects: Iterable[Mobject], mob_class: type[Mobject]\n    ) -> Self:\n        for i, submob in enumerate(submobjects):\n            if not isinstance(submob, mob_class):\n                error_message = (\n                    f\"Only values of type {mob_class.__name__} can be added \"\n                    f\"as submobjects of {type(self).__name__}, but the value \"\n                    f\"{submob} (at index {i}) is of type \"\n                    f\"{type(submob).__name__}.\"\n                )\n                # Intended for subclasses such as VMobject, which\n                # cannot have regular Mobjects as submobjects\n                if isinstance(submob, Mobject):\n                    error_message += (\n                        \" You can try adding this value into a Group instead.\"\n                    )\n                raise TypeError(error_message)\n            if submob is self:\n                raise ValueError(\n                    f\"Cannot add {type(self).__name__} as a submobject of \"\n                    f\"itself (at index {i}).\"\n                )\n        return self\n\n    @classmethod\n    def animation_override_for(\n        cls,\n        animation_class: type[Animation],\n    ) -> FunctionOverride | None:\n        \"\"\"Returns the function defining a specific animation override for this class.\n\n        Parameters\n        ----------\n        animation_class\n            The animation class for which the override function should be returned.\n\n        Returns\n        -------\n        Optional[Callable[[Mobject, ...], Animation]]\n            The function returning the override animation or ``None`` if no such animation\n            override is defined.\n        \"\"\"\n        if animation_class in cls.animation_overrides:\n            return cls.animation_overrides[animation_class]\n\n        return None\n\n    @classmethod\n    def _add_intrinsic_animation_overrides(cls) -> None:\n        \"\"\"Initializes animation overrides marked with the :func:`~.override_animation`\n        decorator.\n        \"\"\"\n        for method_name in dir(cls):\n            # Ignore dunder methods\n            if method_name.startswith(\"__\"):\n                continue\n\n            method = getattr(cls, method_name)\n            if hasattr(method, \"_override_animation\"):\n                animation_class = method._override_animation\n                cls.add_animation_override(animation_class, method)\n\n    @classmethod\n    def add_animation_override(\n        cls,\n        animation_class: type[Animation],\n        override_func: FunctionOverride,\n    ) -> None:\n        \"\"\"Add an animation override.\n\n        This does not apply to subclasses.\n\n        Parameters\n        ----------\n        animation_class\n            The animation type to be overridden\n        override_func\n            The function returning an animation replacing the default animation. It gets\n            passed the parameters given to the animation constructor.\n\n        Raises\n        ------\n        MultiAnimationOverrideException\n            If the overridden animation was already overridden.\n        \"\"\"\n        if animation_class not in cls.animation_overrides:\n            cls.animation_overrides[animation_class] = override_func\n        else:\n            raise MultiAnimationOverrideException(\n                f\"The animation {animation_class.__name__} for \"\n                f\"{cls.__name__} is overridden by more than one method: \"\n                f\"{cls.animation_overrides[animation_class].__qualname__} and \"\n                f\"{override_func.__qualname__}.\",\n            )\n\n    @classmethod\n    def set_default(cls, **kwargs: Any) -> None:\n        \"\"\"Sets the default values of keyword arguments.\n\n        If this method is called without any additional keyword\n        arguments, the original default values of the initialization\n        method of this class are restored.\n\n        Parameters\n        ----------\n\n        kwargs\n            Passing any keyword argument will update the default\n            values of the keyword arguments of the initialization\n            function of this class.\n\n        Examples\n        --------\n\n        ::\n\n            >>> from manim import Square, GREEN\n            >>> Square.set_default(color=GREEN, fill_opacity=0.25)\n            >>> s = Square(); s.color, s.fill_opacity\n            (ManimColor('#83C167'), 0.25)\n            >>> Square.set_default()\n            >>> s = Square(); s.color, s.fill_opacity\n            (ManimColor('#FFFFFF'), 0.0)\n\n        .. manim:: ChangedDefaultTextcolor\n            :save_last_frame:\n\n            config.background_color = WHITE\n\n            class ChangedDefaultTextcolor(Scene):\n                def construct(self):\n                    Text.set_default(color=BLACK)\n                    self.add(Text(\"Changing default values is easy!\"))\n\n                    # we revert the colour back to the default to prevent a bug in the docs.\n                    Text.set_default(color=WHITE)\n\n        \"\"\"\n        if kwargs:\n            # Apparently mypy does not correctly understand `partialmethod`:\n            #   see https://github.com/python/mypy/issues/8619\n            cls.__init__ = partialmethod(cls.__init__, **kwargs)  # type: ignore[assignment]\n        else:\n            # error: Cannot assign to a method  [method-assign]\n            cls.__init__ = cls._original__init__\n\n    @property\n    def animate(self) -> _AnimationBuilder | Self:\n        \"\"\"Used to animate the application of any method of :code:`self`.\n\n        Any method called on :code:`animate` is converted to an animation of applying\n        that method on the mobject itself.\n\n        For example, :code:`square.set_fill(WHITE)` sets the fill color of a square,\n        while :code:`square.animate.set_fill(WHITE)` animates this action.\n\n        Multiple methods can be put in a single animation once via chaining:\n\n        ::\n\n            self.play(my_mobject.animate.shift(RIGHT).rotate(PI))\n\n        .. warning::\n\n            Passing multiple animations for the same :class:`Mobject` in one\n            call to :meth:`~.Scene.play` is discouraged and will most likely\n            not work properly. Instead of writing an animation like\n\n            ::\n\n                self.play(\n                    my_mobject.animate.shift(RIGHT), my_mobject.animate.rotate(PI)\n                )\n\n            make use of method chaining.\n\n        Keyword arguments that can be passed to :meth:`.Scene.play` can be passed\n        directly after accessing ``.animate``, like so::\n\n            self.play(my_mobject.animate(rate_func=linear).shift(RIGHT))\n\n        This is especially useful when animating simultaneous ``.animate`` calls that\n        you want to behave differently::\n\n            self.play(\n                mobject1.animate(run_time=2).rotate(PI),\n                mobject2.animate(rate_func=there_and_back).shift(RIGHT),\n            )\n\n        .. seealso::\n\n            :func:`override_animate`\n\n\n        Examples\n        --------\n\n        .. manim:: AnimateExample\n\n            class AnimateExample(Scene):\n                def construct(self):\n                    s = Square()\n                    self.play(Create(s))\n                    self.play(s.animate.shift(RIGHT))\n                    self.play(s.animate.scale(2))\n                    self.play(s.animate.rotate(PI / 2))\n                    self.play(Uncreate(s))\n\n\n        .. manim:: AnimateChainExample\n\n            class AnimateChainExample(Scene):\n                def construct(self):\n                    s = Square()\n                    self.play(Create(s))\n                    self.play(s.animate.shift(RIGHT).scale(2).rotate(PI / 2))\n                    self.play(Uncreate(s))\n\n        .. manim:: AnimateWithArgsExample\n\n            class AnimateWithArgsExample(Scene):\n                def construct(self):\n                    s = Square()\n                    c = Circle()\n\n                    VGroup(s, c).arrange(RIGHT, buff=2)\n                    self.add(s, c)\n\n                    self.play(\n                        s.animate(run_time=2).rotate(PI / 2),\n                        c.animate(rate_func=there_and_back).shift(RIGHT),\n                    )\n\n        .. warning::\n\n            ``.animate``\n             will interpolate the :class:`~.Mobject` between its points prior to\n             ``.animate`` and its points after applying ``.animate`` to it. This may\n             result in unexpected behavior when attempting to interpolate along paths,\n             or rotations (see :meth:`.rotate`).\n             If you want animations to consider the points between, consider using\n             :class:`~.ValueTracker` with updaters instead (see :meth:`.add_updater`).\n\n        \"\"\"\n        return _AnimationBuilder(self)\n\n    @property\n    def always(self) -> Self:\n        \"\"\"Call a method on a mobject every frame.\n\n        This is syntactic sugar for ``mob.add_updater(lambda m: m.method(*args, **kwargs), call_updater=True)``.\n        Note that this will call the method immediately. If this behavior is not\n        desired, you should use :meth:`add_updater` directly.\n\n        .. warning::\n\n            Chaining of methods is allowed, but each method will be added\n            as its own updater. If you are chaining methods, make sure they\n            do not interfere with each other or you may get unexpected results.\n\n        .. warning::\n\n            :attr:`always` is not compatible with :meth:`.ValueTracker.get_value`, because\n            the value will be computed once and then never updated again. Use :meth:`add_updater`\n            if you would like to use a :class:`~.ValueTracker` to update the value.\n\n        Example\n        -------\n\n            .. manim:: AlwaysExample\n\n                class AlwaysExample(Scene):\n                    def construct(self):\n                        sq = Square().to_edge(LEFT)\n                        t = Text(\"Hello World!\")\n                        t.always.next_to(sq, UP)\n                        self.add(sq, t)\n                        self.play(sq.animate.to_edge(RIGHT))\n        \"\"\"\n        # can't use typing.cast because Self is under TYPE_CHECKING\n        return _UpdaterBuilder(self)  # type: ignore[return-value]\n\n    def __deepcopy__(self, clone_from_id: dict[int, Mobject]) -> Self:\n        cls = self.__class__\n        result = cls.__new__(cls)\n        clone_from_id[id(self)] = result\n        for k, v in self.__dict__.items():\n            setattr(result, k, copy.deepcopy(v, clone_from_id))\n        result.original_id = str(id(self))\n        return result\n\n    def __repr__(self) -> str:\n        return str(self.name)\n\n    def reset_points(self) -> Self:\n        \"\"\"Sets :attr:`points` to be an empty array.\"\"\"\n        self.points = np.zeros((0, self.dim))\n        return self\n\n    def init_colors(self, propagate_colors: bool = True) -> object:\n        \"\"\"Initializes the colors.\n\n        Gets called upon creation. This is an empty method that can be implemented by\n        subclasses.\n        \"\"\"\n\n    def generate_points(self) -> object:\n        \"\"\"Initializes :attr:`points` and therefore the shape.\n\n        Gets called upon creation. This is an empty method that can be implemented by\n        subclasses.\n        \"\"\"\n\n    def add(self, *mobjects: Mobject) -> Self:\n        \"\"\"Add mobjects as submobjects.\n\n        The mobjects are added to :attr:`submobjects`.\n\n        Subclasses of mobject may implement ``+`` and ``+=`` dunder methods.\n\n        Parameters\n        ----------\n        mobjects\n            The mobjects to add.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        Raises\n        ------\n        :class:`ValueError`\n            When a mobject tries to add itself.\n        :class:`TypeError`\n            When trying to add an object that is not an instance of :class:`Mobject`.\n\n\n        Notes\n        -----\n        A mobject cannot contain itself, and it cannot contain a submobject\n        more than once.  If the parent mobject is displayed, the newly-added\n        submobjects will also be displayed (i.e. they are automatically added\n        to the parent Scene).\n\n        See Also\n        --------\n        :meth:`remove`\n        :meth:`add_to_back`\n\n        Examples\n        --------\n        ::\n\n            >>> outer = Mobject()\n            >>> inner = Mobject()\n            >>> outer = outer.add(inner)\n\n        Duplicates are not added again::\n\n            >>> outer = outer.add(inner)\n            >>> len(outer.submobjects)\n            1\n\n        Only Mobjects can be added::\n\n            >>> outer.add(3)\n            Traceback (most recent call last):\n            ...\n            TypeError: Only values of type Mobject can be added as submobjects of Mobject, but the value 3 (at index 0) is of type int.\n\n        Adding an object to itself raises an error::\n\n            >>> outer.add(outer)\n            Traceback (most recent call last):\n            ...\n            ValueError: Cannot add Mobject as a submobject of itself (at index 0).\n\n        A given mobject cannot be added as a submobject\n        twice to some parent::\n\n            >>> parent = Mobject(name=\"parent\")\n            >>> child = Mobject(name=\"child\")\n            >>> parent.add(child, child)\n            [...] WARNING  ...\n            parent\n            >>> parent.submobjects\n            [child]\n\n        \"\"\"\n        self._assert_valid_submobjects(mobjects)\n        unique_mobjects = remove_list_redundancies(mobjects)\n        if len(mobjects) != len(unique_mobjects):\n            logger.warning(\n                \"Attempted adding some Mobject as a child more than once, \"\n                \"this is not possible. Repetitions are ignored.\",\n            )\n\n        self.submobjects = list_update(self.submobjects, unique_mobjects)\n        return self\n\n    def insert(self, index: int, mobject: Mobject) -> None:\n        \"\"\"Inserts a mobject at a specific position into self.submobjects\n\n        Effectively just calls  ``self.submobjects.insert(index, mobject)``,\n        where ``self.submobjects`` is a list.\n\n        Highly adapted from ``Mobject.add``.\n\n        Parameters\n        ----------\n        index\n            The index at which\n        mobject\n            The mobject to be inserted.\n        \"\"\"\n        self._assert_valid_submobjects([mobject])\n        self.submobjects.insert(index, mobject)\n\n    def __add__(self, mobject: Mobject) -> Self:\n        raise NotImplementedError\n\n    def __iadd__(self, mobject: Mobject) -> Self:\n        raise NotImplementedError\n\n    def add_to_back(self, *mobjects: Mobject) -> Self:\n        \"\"\"Add all passed mobjects to the back of the submobjects.\n\n        If :attr:`submobjects` already contains the given mobjects, they just get moved\n        to the back instead.\n\n        Parameters\n        ----------\n        mobjects\n            The mobjects to add.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n\n        .. note::\n\n            Technically, this is done by adding (or moving) the mobjects to\n            the head of :attr:`submobjects`. The head of this list is rendered\n            first, which places the corresponding mobjects behind the\n            subsequent list members.\n\n        Raises\n        ------\n        :class:`ValueError`\n            When a mobject tries to add itself.\n        :class:`TypeError`\n            When trying to add an object that is not an instance of :class:`Mobject`.\n\n        Notes\n        -----\n        A mobject cannot contain itself, and it cannot contain a submobject\n        more than once.  If the parent mobject is displayed, the newly-added\n        submobjects will also be displayed (i.e. they are automatically added\n        to the parent Scene).\n\n        See Also\n        --------\n        :meth:`remove`\n        :meth:`add`\n\n        \"\"\"\n        self._assert_valid_submobjects(mobjects)\n        self.remove(*mobjects)\n        # dict.fromkeys() removes duplicates while maintaining order\n        self.submobjects = list(dict.fromkeys(mobjects)) + self.submobjects\n        return self\n\n    def remove(self, *mobjects: Mobject) -> Self:\n        \"\"\"Remove :attr:`submobjects`.\n\n        The mobjects are removed from :attr:`submobjects`, if they exist.\n\n        Subclasses of mobject may implement ``-`` and ``-=`` dunder methods.\n\n        Parameters\n        ----------\n        mobjects\n            The mobjects to remove.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        See Also\n        --------\n        :meth:`add`\n\n        \"\"\"\n        for mobject in mobjects:\n            if mobject in self.submobjects:\n                self.submobjects.remove(mobject)\n        return self\n\n    def __sub__(self, other: Mobject) -> Self:\n        raise NotImplementedError\n\n    def __isub__(self, other: Mobject) -> Self:\n        raise NotImplementedError\n\n    def set(self, **kwargs: Any) -> Self:\n        \"\"\"Sets attributes.\n\n        I.e. ``my_mobject.set(foo=1)`` applies ``my_mobject.foo = 1``.\n\n        This is a convenience to be used along with :attr:`animate` to\n        animate setting attributes.\n\n        In addition to this method, there is a compatibility\n        layer that allows ``get_*`` and ``set_*`` methods to\n        get and set generic attributes. For instance::\n\n            >>> mob = Mobject()\n            >>> mob.set_foo(0)\n            Mobject\n            >>> mob.get_foo()\n            0\n            >>> mob.foo\n            0\n\n        This compatibility layer does not interfere with any\n        ``get_*`` or ``set_*`` methods that are explicitly\n        defined.\n\n        .. warning::\n\n            This compatibility layer is for backwards compatibility\n            and is not guaranteed to stay around. Where applicable,\n            please prefer getting/setting attributes normally or with\n            the :meth:`set` method.\n\n        Parameters\n        ----------\n        **kwargs\n            The attributes and corresponding values to set.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        Examples\n        --------\n        ::\n\n            >>> mob = Mobject()\n            >>> mob.set(foo=0)\n            Mobject\n            >>> mob.foo\n            0\n        \"\"\"\n        for attr, value in kwargs.items():\n            setattr(self, attr, value)\n\n        return self\n\n    def __getattr__(self, attr: str) -> types.MethodType:\n        # Add automatic compatibility layer\n        # between properties and get_* and set_*\n        # methods.\n        #\n        # In python 3.9+ we could change this\n        # logic to use str.remove_prefix instead.\n\n        if attr.startswith(\"get_\"):\n            # Remove the \"get_\" prefix\n            to_get = attr[4:]\n\n            def getter(self: Mobject) -> Any:\n                warnings.warn(\n                    \"This method is not guaranteed to stay around. Please prefer \"\n                    \"getting the attribute normally.\",\n                    DeprecationWarning,\n                    stacklevel=2,\n                )\n\n                return getattr(self, to_get)\n\n            # Return a bound method\n            return types.MethodType(getter, self)\n\n        if attr.startswith(\"set_\"):\n            # Remove the \"set_\" prefix\n            to_set = attr[4:]\n\n            def setter(self: Mobject, value: Any) -> Mobject:\n                warnings.warn(\n                    \"This method is not guaranteed to stay around. Please prefer \"\n                    \"setting the attribute normally or with Mobject.set().\",\n                    DeprecationWarning,\n                    stacklevel=2,\n                )\n\n                setattr(self, to_set, value)\n\n                return self\n\n            # Return a bound method\n            return types.MethodType(setter, self)\n\n        # Unhandled attribute, therefore error\n        raise AttributeError(f\"{type(self).__name__} object has no attribute '{attr}'\")\n\n    @property\n    def width(self) -> float:\n        \"\"\"The width of the mobject.\n\n        Returns\n        -------\n        :class:`float`\n\n        Examples\n        --------\n        .. manim:: WidthExample\n\n            class WidthExample(Scene):\n                def construct(self):\n                    decimal = DecimalNumber().to_edge(UP)\n                    rect = Rectangle(color=BLUE)\n                    rect_copy = rect.copy().set_stroke(GRAY, opacity=0.5)\n\n                    decimal.add_updater(lambda d: d.set_value(rect.width))\n\n                    self.add(rect_copy, rect, decimal)\n                    self.play(rect.animate.set(width=7))\n                    self.wait()\n\n        See also\n        --------\n        :meth:`length_over_dim`\n\n        \"\"\"\n        # Get the length across the X dimension\n        return self.length_over_dim(0)\n\n    @width.setter\n    def width(self, value: float) -> None:\n        self.scale_to_fit_width(value)\n\n    @property\n    def height(self) -> float:\n        \"\"\"The height of the mobject.\n\n        Returns\n        -------\n        :class:`float`\n\n        Examples\n        --------\n        .. manim:: HeightExample\n\n            class HeightExample(Scene):\n                def construct(self):\n                    decimal = DecimalNumber().to_edge(UP)\n                    rect = Rectangle(color=BLUE)\n                    rect_copy = rect.copy().set_stroke(GRAY, opacity=0.5)\n\n                    decimal.add_updater(lambda d: d.set_value(rect.height))\n\n                    self.add(rect_copy, rect, decimal)\n                    self.play(rect.animate.set(height=5))\n                    self.wait()\n\n        See also\n        --------\n        :meth:`length_over_dim`\n\n        \"\"\"\n        # Get the length across the Y dimension\n        return self.length_over_dim(1)\n\n    @height.setter\n    def height(self, value: float) -> None:\n        self.scale_to_fit_height(value)\n\n    @property\n    def depth(self) -> float:\n        \"\"\"The depth of the mobject.\n\n        Returns\n        -------\n        :class:`float`\n\n        See also\n        --------\n        :meth:`length_over_dim`\n\n        \"\"\"\n        # Get the length across the Z dimension\n        return self.length_over_dim(2)\n\n    @depth.setter\n    def depth(self, value: float) -> None:\n        self.scale_to_fit_depth(value)\n\n    # Can't be staticmethod because of point_cloud_mobject.py\n    def get_array_attrs(self) -> list[str]:\n        return [\"points\"]\n\n    def apply_over_attr_arrays(self, func: MultiMappingFunction) -> Self:\n        for attr in self.get_array_attrs():\n            setattr(self, attr, func(getattr(self, attr)))\n        return self\n\n    # Displaying\n    def get_image(self, camera: Camera | None = None) -> Image.Image:\n        if camera is None:\n            camera = Camera()\n        camera.capture_mobject(self)\n        return camera.get_image()\n\n    def show(self, camera: Camera | None = None) -> None:\n        self.get_image(camera=camera).show()\n\n    def save_image(self, name: str | None = None) -> None:\n        \"\"\"Saves an image of only this :class:`Mobject` at its position to a png\n        file.\n        \"\"\"\n        self.get_image().save(\n            Path(config.get_dir(\"video_dir\")).joinpath((name or str(self)) + \".png\"),\n        )\n\n    def copy(self) -> Self:\n        \"\"\"Create and return an identical copy of the :class:`Mobject` including all\n        :attr:`submobjects`.\n\n        Returns\n        -------\n        :class:`Mobject`\n            The copy.\n\n        Note\n        ----\n        The clone is initially not visible in the Scene, even if the original was.\n        \"\"\"\n        return copy.deepcopy(self)\n\n    def generate_target(self, use_deepcopy: bool = False) -> Self:\n        self.target = None  # Prevent unbounded linear recursion\n        if use_deepcopy:\n            self.target = copy.deepcopy(self)\n        else:\n            self.target = self.copy()\n        return self.target\n\n    # Updating\n\n    def update(self, dt: float = 0, recursive: bool = True) -> Self:\n        \"\"\"Apply all updaters.\n\n        Does nothing if updating is suspended.\n\n        Parameters\n        ----------\n        dt\n            The parameter ``dt`` to pass to the update functions. Usually this is the\n            time in seconds since the last call of ``update``.\n        recursive\n            Whether to recursively update all submobjects.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        See Also\n        --------\n        :meth:`add_updater`\n        :meth:`get_updaters`\n\n        \"\"\"\n        if self.updating_suspended:\n            return self\n        for updater in self.updaters:\n            if \"dt\" in inspect.signature(updater).parameters:\n                time_based_updater = cast(_TimeBasedUpdater, updater)\n                time_based_updater(self, dt)\n            else:\n                non_time_based_updater = cast(_NonTimeBasedUpdater, updater)\n                non_time_based_updater(self)\n        if recursive:\n            for submob in self.submobjects:\n                submob.update(dt, recursive=recursive)\n        return self\n\n    def get_time_based_updaters(self) -> list[_TimeBasedUpdater]:\n        \"\"\"Return all updaters using the ``dt`` parameter.\n\n        The updaters use this parameter as the input for difference in time.\n\n        Returns\n        -------\n        List[:class:`Callable`]\n            The list of time based updaters.\n\n        See Also\n        --------\n        :meth:`get_updaters`\n        :meth:`has_time_based_updater`\n\n        \"\"\"\n        rv: list[_TimeBasedUpdater] = []\n        for updater in self.updaters:\n            if \"dt\" in inspect.signature(updater).parameters:\n                time_based_updater = cast(_TimeBasedUpdater, updater)\n                rv.append(time_based_updater)\n        return rv\n\n    def has_time_based_updater(self) -> bool:\n        \"\"\"Test if ``self`` has a time based updater.\n\n        Returns\n        -------\n        :class:`bool`\n            ``True`` if at least one updater uses the ``dt`` parameter, ``False``\n            otherwise.\n\n        See Also\n        --------\n        :meth:`get_time_based_updaters`\n\n        \"\"\"\n        return any(\n            \"dt\" in inspect.signature(updater).parameters for updater in self.updaters\n        )\n\n    def get_updaters(self) -> list[_Updater]:\n        \"\"\"Return all updaters.\n\n        Returns\n        -------\n        List[:class:`Callable`]\n            The list of updaters.\n\n        See Also\n        --------\n        :meth:`add_updater`\n        :meth:`get_time_based_updaters`\n\n        \"\"\"\n        return self.updaters\n\n    def get_family_updaters(self) -> list[_Updater]:\n        return list(it.chain(*(sm.get_updaters() for sm in self.get_family())))\n\n    def add_updater(\n        self,\n        update_function: _Updater,\n        index: int | None = None,\n        call_updater: bool = False,\n    ) -> Self:\n        \"\"\"Add an update function to this mobject.\n\n        Update functions, or updaters in short, are functions that are applied to the\n        Mobject in every frame.\n\n        Parameters\n        ----------\n        update_function\n            The update function to be added.\n            Whenever :meth:`update` is called, this update function gets called using\n            ``self`` as the first parameter.\n            The updater can have a second parameter ``dt``. If it uses this parameter,\n            it gets called using a second value ``dt``, usually representing the time\n            in seconds since the last call of :meth:`update`.\n        index\n            The index at which the new updater should be added in ``self.updaters``.\n            In case ``index`` is ``None`` the updater will be added at the end.\n        call_updater\n            Whether or not to call the updater initially. If ``True``, the updater will\n            be called using ``dt=0``.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        Examples\n        --------\n        .. manim:: NextToUpdater\n\n            class NextToUpdater(Scene):\n                def construct(self):\n                    def update_label(mobject):\n                        mobject.set_value(dot.get_center()[0])\n                        mobject.next_to(dot)\n\n                    dot = Dot(RIGHT*3)\n                    label = DecimalNumber()\n                    label.add_updater(update_label)\n                    self.add(dot, label)\n\n                    self.play(Rotating(dot, angle=TAU, about_point=ORIGIN, run_time=TAU, rate_func=linear))\n\n        .. manim:: DtUpdater\n\n            class DtUpdater(Scene):\n                def construct(self):\n                    square = Square()\n\n                    #Let the square rotate 90° per second\n                    square.add_updater(lambda mobject, dt: mobject.rotate(dt*90*DEGREES))\n                    self.add(square)\n                    self.wait(2)\n\n        See also\n        --------\n        :meth:`get_updaters`\n        :meth:`remove_updater`\n        :class:`~.UpdateFromFunc`\n        :class:`~.Rotating`\n        :meth:`rotate`\n        :attr:`~.Mobject.animate`\n        \"\"\"\n        if index is None:\n            self.updaters.append(update_function)\n        else:\n            self.updaters.insert(index, update_function)\n        if call_updater:\n            parameters = inspect.signature(update_function).parameters\n            if \"dt\" in parameters:\n                time_based_updater = cast(_TimeBasedUpdater, update_function)\n                time_based_updater(self, 0)\n            else:\n                non_time_based_updater = cast(_NonTimeBasedUpdater, update_function)\n                non_time_based_updater(self)\n\n        return self\n\n    def remove_updater(self, update_function: _Updater) -> Self:\n        \"\"\"Remove an updater.\n\n        If the same updater is applied multiple times, every instance gets removed.\n\n        Parameters\n        ----------\n        update_function\n            The update function to be removed.\n\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        See also\n        --------\n        :meth:`clear_updaters`\n        :meth:`add_updater`\n        :meth:`get_updaters`\n\n        \"\"\"\n        while update_function in self.updaters:\n            self.updaters.remove(update_function)\n        return self\n\n    def clear_updaters(self, recursive: bool = True) -> Self:\n        \"\"\"Remove every updater.\n\n        Parameters\n        ----------\n        recursive\n            Whether to recursively call ``clear_updaters`` on all submobjects.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        See also\n        --------\n        :meth:`remove_updater`\n        :meth:`add_updater`\n        :meth:`get_updaters`\n\n        \"\"\"\n        self.updaters = []\n        if recursive:\n            for submob in self.submobjects:\n                submob.clear_updaters()\n        return self\n\n    def match_updaters(self, mobject: Mobject) -> Self:\n        \"\"\"Match the updaters of the given mobject.\n\n        Parameters\n        ----------\n        mobject\n            The mobject whose updaters get matched.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        Note\n        ----\n        All updaters from submobjects are removed, but only updaters of the given\n        mobject are matched, not those of it's submobjects.\n\n        See also\n        --------\n        :meth:`add_updater`\n        :meth:`clear_updaters`\n\n        \"\"\"\n        self.clear_updaters()\n        for updater in mobject.get_updaters():\n            self.add_updater(updater)\n        return self\n\n    def suspend_updating(self, recursive: bool = True) -> Self:\n        \"\"\"Disable updating from updaters and animations.\n\n\n        Parameters\n        ----------\n        recursive\n            Whether to recursively suspend updating on all submobjects.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        See also\n        --------\n        :meth:`resume_updating`\n        :meth:`add_updater`\n\n        \"\"\"\n        self.updating_suspended = True\n        if recursive:\n            for submob in self.submobjects:\n                submob.suspend_updating(recursive)\n        return self\n\n    def resume_updating(self, recursive: bool = True) -> Self:\n        \"\"\"Enable updating from updaters and animations.\n\n        Parameters\n        ----------\n        recursive\n            Whether to recursively enable updating on all submobjects.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        See also\n        --------\n        :meth:`suspend_updating`\n        :meth:`add_updater`\n\n        \"\"\"\n        self.updating_suspended = False\n        if recursive:\n            for submob in self.submobjects:\n                submob.resume_updating(recursive)\n        self.update(dt=0, recursive=recursive)\n        return self\n\n    # Transforming operations\n\n    def apply_to_family(self, func: Callable[[Mobject], None]) -> None:\n        \"\"\"Apply a function to ``self`` and every submobject with points recursively.\n\n        Parameters\n        ----------\n        func\n            The function to apply to each mobject. ``func`` gets passed the respective\n            (sub)mobject as parameter.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        See also\n        --------\n        :meth:`family_members_with_points`\n\n        \"\"\"\n        for mob in self.family_members_with_points():\n            func(mob)\n\n    def shift(self, *vectors: Vector3DLike) -> Self:\n        \"\"\"Shift by the given vectors.\n\n        Parameters\n        ----------\n        vectors\n            Vectors to shift by. If multiple vectors are given, they are added\n            together.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        See also\n        --------\n        :meth:`move_to`\n        \"\"\"\n        total_vector = reduce(op.add, vectors)\n        for mob in self.family_members_with_points():\n            mob.points = mob.points.astype(\"float\")\n            mob.points += total_vector\n\n        return self\n\n    def scale(\n        self,\n        scale_factor: float,\n        *,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n    ) -> Self:\n        r\"\"\"Scale the size by a factor.\n\n        Default behavior is to scale about the center of the mobject.\n\n        Parameters\n        ----------\n        scale_factor\n            The scaling factor :math:`\\alpha`. If :math:`0 < |\\alpha| < 1`, the mobject\n            will shrink, and for :math:`|\\alpha| > 1` it will grow. Furthermore,\n            if :math:`\\alpha < 0`, the mobject is also flipped.\n        about_point\n            The point about which to apply the scaling.\n        about_edge\n            The edge about which to apply the scaling.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        Examples\n        --------\n\n        .. manim:: MobjectScaleExample\n            :save_last_frame:\n\n            class MobjectScaleExample(Scene):\n                def construct(self):\n                    f1 = Text(\"F\")\n                    f2 = Text(\"F\").scale(2)\n                    f3 = Text(\"F\").scale(0.5)\n                    f4 = Text(\"F\").scale(-1)\n\n                    vgroup = VGroup(f1, f2, f3, f4).arrange(6 * RIGHT)\n                    self.add(vgroup)\n\n        See also\n        --------\n        :meth:`move_to`\n\n        \"\"\"\n        self.apply_points_function_about_point(\n            lambda points: scale_factor * points, about_point, about_edge\n        )\n        return self\n\n    def rotate_about_origin(self, angle: float, axis: Vector3DLike = OUT) -> Self:\n        \"\"\"Rotates the :class:`~.Mobject` about the ORIGIN, which is at [0,0,0].\"\"\"\n        return self.rotate(angle, axis, about_point=ORIGIN)\n\n    def rotate(\n        self,\n        angle: float,\n        axis: Vector3DLike = OUT,\n        *,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Rotates the :class:`~.Mobject` around a specified axis and point.\n\n        Parameters\n        ----------\n        angle\n            The angle of rotation in radians. Predefined constants such as ``DEGREES``\n            can also be used to specify the angle in degrees.\n        axis\n            The rotation axis (see :class:`~.Rotating` for more).\n        about_point\n            The point about which the mobject rotates. If ``None``, rotation occurs around\n            the center of the mobject.\n        about_edge\n            The edge about which to apply the scaling.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self`` (for method chaining)\n\n\n        .. note::\n            To animate a rotation, use :class:`~.Rotating` or :class:`~.Rotate`\n            instead of ``.animate.rotate(...)``.\n            The ``.animate.rotate(...)`` syntax only applies a transformation\n            from the initial state to the final rotated state\n            (interpolation between the two states), without showing proper rotational motion\n            based on the angle (from 0 to the given angle).\n\n        Examples\n        --------\n\n        .. manim:: RotateMethodExample\n            :save_last_frame:\n\n            class RotateMethodExample(Scene):\n                def construct(self):\n                    circle = Circle(radius=1, color=BLUE)\n                    line = Line(start=ORIGIN, end=RIGHT)\n                    arrow1 = Arrow(start=ORIGIN, end=RIGHT, buff=0, color=GOLD)\n                    group1 = VGroup(circle, line, arrow1)\n\n                    group2 = group1.copy()\n                    arrow2 = group2[2]\n                    arrow2.rotate(angle=PI / 4, about_point=arrow2.get_start())\n\n                    group3 = group1.copy()\n                    arrow3 = group3[2]\n                    arrow3.rotate(angle=120 * DEGREES, about_point=arrow3.get_start())\n\n                    self.add(VGroup(group1, group2, group3).arrange(RIGHT, buff=1))\n\n        See also\n        --------\n        :class:`~.Rotating`, :class:`~.Rotate`, :attr:`~.Mobject.animate`, :meth:`apply_points_function_about_point`\n\n        \"\"\"\n        rot_matrix = rotation_matrix(angle, axis)\n        self.apply_points_function_about_point(\n            lambda points: np.dot(points, rot_matrix.T), about_point, about_edge\n        )\n        return self\n\n    def flip(\n        self,\n        axis: Vector3DLike = UP,\n        *,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n    ) -> Self:\n        \"\"\"Flips/Mirrors an mobject about its center.\n\n        Examples\n        --------\n\n        .. manim:: FlipExample\n            :save_last_frame:\n\n            class FlipExample(Scene):\n                def construct(self):\n                    s= Line(LEFT, RIGHT+UP).shift(4*LEFT)\n                    self.add(s)\n                    s2= s.copy().flip()\n                    self.add(s2)\n\n        \"\"\"\n        return self.rotate(\n            TAU / 2, axis, about_point=about_point, about_edge=about_edge\n        )\n\n    def stretch(\n        self,\n        factor: float,\n        dim: int,\n        *,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n    ) -> Self:\n        def func(points: Point3D_Array) -> Point3D_Array:\n            points[:, dim] *= factor\n            return points\n\n        self.apply_points_function_about_point(func, about_point, about_edge)\n        return self\n\n    def apply_function(\n        self,\n        function: MappingFunction,\n        *,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n    ) -> Self:\n        # Default to applying matrix about the origin, not mobjects center\n        if about_point is None and about_edge is None:\n            about_point = ORIGIN\n\n        def multi_mapping_function(points: Point3D_Array) -> Point3D_Array:\n            result: Point3D_Array = np.apply_along_axis(function, 1, points)\n            return result\n\n        self.apply_points_function_about_point(\n            multi_mapping_function,\n            about_point,\n            about_edge,\n        )\n        return self\n\n    def apply_function_to_position(self, function: MappingFunction) -> Self:\n        self.move_to(function(self.get_center()))\n        return self\n\n    def apply_function_to_submobject_positions(self, function: MappingFunction) -> Self:\n        for submob in self.submobjects:\n            submob.apply_function_to_position(function)\n        return self\n\n    def apply_matrix(\n        self,\n        matrix: MatrixMN,\n        *,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n    ) -> Self:\n        # Default to applying matrix about the origin, not mobjects center\n        if about_point is None and about_edge is None:\n            about_point = ORIGIN\n        full_matrix = np.identity(self.dim)\n        matrix = np.array(matrix)\n        full_matrix[: matrix.shape[0], : matrix.shape[1]] = matrix\n        self.apply_points_function_about_point(\n            lambda points: np.dot(points, full_matrix.T), about_point, about_edge\n        )\n        return self\n\n    def apply_complex_function(\n        self,\n        function: Callable[[complex], complex],\n        *,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n    ) -> Self:\n        \"\"\"Applies a complex function to a :class:`Mobject`.\n        The x and y Point3Ds correspond to the real and imaginary parts respectively.\n\n        Example\n        -------\n\n        .. manim:: ApplyFuncExample\n\n            class ApplyFuncExample(Scene):\n                def construct(self):\n                    circ = Circle().scale(1.5)\n                    circ_ref = circ.copy()\n                    circ.apply_complex_function(\n                        lambda x: np.exp(x*1j)\n                    )\n                    t = ValueTracker(0)\n                    circ.add_updater(\n                        lambda x: x.become(circ_ref.copy().apply_complex_function(\n                            lambda x: np.exp(x+t.get_value()*1j)\n                        )).set_color(BLUE)\n                    )\n                    self.add(circ_ref)\n                    self.play(TransformFromCopy(circ_ref, circ))\n                    self.play(t.animate.set_value(TAU), run_time=3)\n        \"\"\"\n\n        def R3_func(point: Point3D) -> Point3D:\n            x, y, z = point\n            xy_complex = function(complex(x, y))\n            return np.array([xy_complex.real, xy_complex.imag, z])\n\n        return self.apply_function(\n            R3_func, about_point=about_point, about_edge=about_edge\n        )\n\n    def reverse_points(self) -> Self:\n        for mob in self.family_members_with_points():\n            mob.apply_over_attr_arrays(lambda arr: np.array(list(reversed(arr))))\n        return self\n\n    def repeat(self, count: int) -> Self:\n        \"\"\"This can make transition animations nicer\"\"\"\n\n        def repeat_array(array: Point3D_Array) -> Point3D_Array:\n            return reduce(lambda a1, a2: np.append(a1, a2, axis=0), [array] * count)\n\n        for mob in self.family_members_with_points():\n            mob.apply_over_attr_arrays(repeat_array)\n        return self\n\n    # In place operations.\n    # Note, much of these are now redundant with default behavior of\n    # above methods\n\n    # TODO: name is inconsistent with OpenGLMobject.apply_points_function()\n    def apply_points_function_about_point(\n        self,\n        func: MultiMappingFunction,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n    ) -> Self:\n        if about_point is None:\n            if about_edge is None:\n                about_edge = ORIGIN\n            about_point = self.get_critical_point(about_edge)\n        # Make a copy to prevent mutation of the original array if about_point is a view\n        about_point = np.array(about_point, copy=True)\n        for mob in self.family_members_with_points():\n            mob.points -= about_point\n            mob.points = func(mob.points)\n            mob.points += about_point\n        return self\n\n    def pose_at_angle(self, **kwargs: Any) -> Self:\n        self.rotate(TAU / 14, RIGHT + UP, **kwargs)\n        return self\n\n    # Positioning methods\n\n    def center(self) -> Self:\n        \"\"\"Moves the center of the mobject to the center of the scene.\n\n        Returns\n        -------\n        :class:`.Mobject`\n            The centered mobject.\n        \"\"\"\n        self.shift(-self.get_center())\n        return self\n\n    def align_on_border(\n        self, direction: Vector3DLike, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER\n    ) -> Self:\n        \"\"\"Direction just needs to be a vector pointing towards side or\n        corner in the 2d plane.\n        \"\"\"\n        target_point = np.sign(direction) * (\n            config[\"frame_x_radius\"],\n            config[\"frame_y_radius\"],\n            0,\n        )\n        point_to_align = self.get_critical_point(direction)\n        shift_val = target_point - point_to_align - buff * np.array(direction)\n        shift_val = shift_val * abs(np.sign(direction))\n        self.shift(shift_val)\n        return self\n\n    def to_corner(\n        self, corner: Vector3DLike = DL, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER\n    ) -> Self:\n        \"\"\"Moves this :class:`~.Mobject` to the given corner of the screen.\n\n        Returns\n        -------\n        :class:`.Mobject`\n            The newly positioned mobject.\n\n        Examples\n        --------\n\n        .. manim:: ToCornerExample\n            :save_last_frame:\n\n            class ToCornerExample(Scene):\n                def construct(self):\n                    c = Circle()\n                    c.to_corner(UR)\n                    t = Tex(\"To the corner!\")\n                    t2 = MathTex(\"x^3\").shift(DOWN)\n                    self.add(c,t,t2)\n                    t.to_corner(DL, buff=0)\n                    t2.to_corner(UL, buff=1.5)\n        \"\"\"\n        return self.align_on_border(corner, buff)\n\n    def to_edge(\n        self, edge: Vector3DLike = LEFT, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER\n    ) -> Self:\n        \"\"\"Moves this :class:`~.Mobject` to the given edge of the screen,\n        without affecting its position in the other dimension.\n\n        Returns\n        -------\n        :class:`.Mobject`\n            The newly positioned mobject.\n\n        Examples\n        --------\n\n        .. manim:: ToEdgeExample\n            :save_last_frame:\n\n            class ToEdgeExample(Scene):\n                def construct(self):\n                    tex_top = Tex(\"I am at the top!\")\n                    tex_top.to_edge(UP)\n                    tex_side = Tex(\"I am moving to the side!\")\n                    c = Circle().shift(2*DOWN)\n                    self.add(tex_top, tex_side, c)\n                    tex_side.to_edge(LEFT)\n                    c.to_edge(RIGHT, buff=0)\n\n        \"\"\"\n        return self.align_on_border(edge, buff)\n\n    def next_to(\n        self,\n        mobject_or_point: Mobject | Point3DLike,\n        direction: Vector3DLike = RIGHT,\n        buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,\n        aligned_edge: Vector3DLike = ORIGIN,\n        submobject_to_align: Mobject | None = None,\n        index_of_submobject_to_align: int | None = None,\n        coor_mask: Vector3DLike = np.array([1, 1, 1]),\n    ) -> Self:\n        \"\"\"Move this :class:`~.Mobject` next to another's :class:`~.Mobject` or Point3D.\n\n        Examples\n        --------\n\n        .. manim:: GeometricShapes\n            :save_last_frame:\n\n            class GeometricShapes(Scene):\n                def construct(self):\n                    d = Dot()\n                    c = Circle()\n                    s = Square()\n                    t = Triangle()\n                    d.next_to(c, RIGHT)\n                    s.next_to(c, LEFT)\n                    t.next_to(c, DOWN)\n                    self.add(d, c, s, t)\n\n        \"\"\"\n        np_direction = np.asarray(direction)\n        np_aligned_edge = np.asarray(aligned_edge)\n\n        if isinstance(mobject_or_point, Mobject):\n            mob = mobject_or_point\n            if index_of_submobject_to_align is not None:\n                target_aligner = mob[index_of_submobject_to_align]\n            else:\n                target_aligner = mob\n            target_point = target_aligner.get_critical_point(\n                np_aligned_edge + np_direction\n            )\n        else:\n            target_point = mobject_or_point\n        if submobject_to_align is not None:\n            aligner = submobject_to_align\n        elif index_of_submobject_to_align is not None:\n            aligner = self[index_of_submobject_to_align]\n        else:\n            aligner = self\n        point_to_align = aligner.get_critical_point(np_aligned_edge - np_direction)\n        self.shift((target_point - point_to_align + buff * np_direction) * coor_mask)\n        return self\n\n    def shift_onto_screen(self, **kwargs: Any) -> Self:\n        space_lengths = [config[\"frame_x_radius\"], config[\"frame_y_radius\"]]\n        for vect in UP, DOWN, LEFT, RIGHT:\n            dim = np.argmax(np.abs(vect))\n            buff = kwargs.get(\"buff\", DEFAULT_MOBJECT_TO_EDGE_BUFFER)\n            max_val = space_lengths[dim] - buff\n            edge_center = self.get_edge_center(vect)\n            if np.dot(edge_center, vect) > max_val:\n                self.to_edge(vect, **kwargs)\n        return self\n\n    def is_off_screen(self) -> bool:\n        if self.get_left()[0] > config[\"frame_x_radius\"]:\n            return True\n        if self.get_right()[0] < -config[\"frame_x_radius\"]:\n            return True\n        if self.get_bottom()[1] > config[\"frame_y_radius\"]:\n            return True\n        rv: bool = self.get_top()[1] < -config[\"frame_y_radius\"]\n        return rv\n\n    def stretch_about_point(self, factor: float, dim: int, point: Point3DLike) -> Self:\n        return self.stretch(factor, dim, about_point=point)\n\n    def rescale_to_fit(\n        self, length: float, dim: int, stretch: bool = False, **kwargs: Any\n    ) -> Self:\n        old_length = self.length_over_dim(dim)\n        if old_length == 0:\n            return self\n        if stretch:\n            self.stretch(length / old_length, dim, **kwargs)\n        else:\n            self.scale(length / old_length, **kwargs)\n        return self\n\n    def scale_to_fit_width(self, width: float, **kwargs: Any) -> Self:\n        \"\"\"Scales the :class:`~.Mobject` to fit a width while keeping height/depth proportional.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import *\n            >>> sq = Square()\n            >>> sq.height\n            np.float64(2.0)\n            >>> sq.scale_to_fit_width(5)\n            Square\n            >>> sq.width\n            np.float64(5.0)\n            >>> sq.height\n            np.float64(5.0)\n        \"\"\"\n        return self.rescale_to_fit(width, 0, stretch=False, **kwargs)\n\n    def stretch_to_fit_width(self, width: float, **kwargs: Any) -> Self:\n        \"\"\"Stretches the :class:`~.Mobject` to fit a width, not keeping height/depth proportional.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import *\n            >>> sq = Square()\n            >>> sq.height\n            np.float64(2.0)\n            >>> sq.stretch_to_fit_width(5)\n            Square\n            >>> sq.width\n            np.float64(5.0)\n            >>> sq.height\n            np.float64(2.0)\n        \"\"\"\n        return self.rescale_to_fit(width, 0, stretch=True, **kwargs)\n\n    def scale_to_fit_height(self, height: float, **kwargs: Any) -> Self:\n        \"\"\"Scales the :class:`~.Mobject` to fit a height while keeping width/depth proportional.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import *\n            >>> sq = Square()\n            >>> sq.width\n            np.float64(2.0)\n            >>> sq.scale_to_fit_height(5)\n            Square\n            >>> sq.height\n            np.float64(5.0)\n            >>> sq.width\n            np.float64(5.0)\n        \"\"\"\n        return self.rescale_to_fit(height, 1, stretch=False, **kwargs)\n\n    def stretch_to_fit_height(self, height: float, **kwargs: Any) -> Self:\n        \"\"\"Stretches the :class:`~.Mobject` to fit a height, not keeping width/depth proportional.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import *\n            >>> sq = Square()\n            >>> sq.width\n            np.float64(2.0)\n            >>> sq.stretch_to_fit_height(5)\n            Square\n            >>> sq.height\n            np.float64(5.0)\n            >>> sq.width\n            np.float64(2.0)\n        \"\"\"\n        return self.rescale_to_fit(height, 1, stretch=True, **kwargs)\n\n    def scale_to_fit_depth(self, depth: float, **kwargs: Any) -> Self:\n        \"\"\"Scales the :class:`~.Mobject` to fit a depth while keeping width/height proportional.\"\"\"\n        return self.rescale_to_fit(depth, 2, stretch=False, **kwargs)\n\n    def stretch_to_fit_depth(self, depth: float, **kwargs: Any) -> Self:\n        \"\"\"Stretches the :class:`~.Mobject` to fit a depth, not keeping width/height proportional.\"\"\"\n        return self.rescale_to_fit(depth, 2, stretch=True, **kwargs)\n\n    def set_coord(\n        self, value: float, dim: int, direction: Vector3DLike = ORIGIN\n    ) -> Self:\n        curr = self.get_coord(dim, direction)\n        shift_vect = np.zeros(self.dim)\n        shift_vect[dim] = value - curr\n        self.shift(shift_vect)\n        return self\n\n    def set_x(self, x: float, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Set x value of the center of the :class:`~.Mobject` (``int`` or ``float``)\"\"\"\n        return self.set_coord(x, 0, direction)\n\n    def set_y(self, y: float, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Set y value of the center of the :class:`~.Mobject` (``int`` or ``float``)\"\"\"\n        return self.set_coord(y, 1, direction)\n\n    def set_z(self, z: float, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Set z value of the center of the :class:`~.Mobject` (``int`` or ``float``)\"\"\"\n        return self.set_coord(z, 2, direction)\n\n    def space_out_submobjects(self, factor: float = 1.5, **kwargs: Any) -> Self:\n        self.scale(factor, **kwargs)\n        for submob in self.submobjects:\n            submob.scale(1.0 / factor)\n        return self\n\n    def move_to(\n        self,\n        point_or_mobject: Point3DLike | Mobject,\n        aligned_edge: Vector3DLike = ORIGIN,\n        coor_mask: Vector3DLike = np.array([1, 1, 1]),\n    ) -> Self:\n        \"\"\"Move center of the :class:`~.Mobject` to certain Point3D.\"\"\"\n        if isinstance(point_or_mobject, Mobject):\n            target = point_or_mobject.get_critical_point(aligned_edge)\n        else:\n            target = point_or_mobject\n        point_to_align = self.get_critical_point(aligned_edge)\n        self.shift((target - point_to_align) * coor_mask)\n        return self\n\n    def replace(\n        self, mobject: Mobject, dim_to_match: int = 0, stretch: bool = False\n    ) -> Self:\n        if not mobject.get_num_points() and not mobject.submobjects:\n            raise Warning(\"Attempting to replace mobject with no points\")\n        if stretch:\n            self.stretch_to_fit_width(mobject.width)\n            self.stretch_to_fit_height(mobject.height)\n        else:\n            self.rescale_to_fit(\n                mobject.length_over_dim(dim_to_match),\n                dim_to_match,\n                stretch=False,\n            )\n        self.shift(mobject.get_center() - self.get_center())\n        return self\n\n    def surround(\n        self,\n        mobject: Mobject,\n        dim_to_match: int = 0,\n        stretch: bool = False,\n        buff: float = MED_SMALL_BUFF,\n    ) -> Self:\n        self.replace(mobject, dim_to_match, stretch)\n        length = mobject.length_over_dim(dim_to_match)\n        self.scale((length + buff) / length)\n        return self\n\n    def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self:\n        curr_start, curr_end = self.get_start_and_end()\n        curr_vect = curr_end - curr_start\n        if np.all(curr_vect == 0):\n            # TODO: this looks broken. It makes self.points a Point3D instead\n            # of a Point3D_Array. However, modifying this breaks some tests\n            # where this is currently expected.\n            self.points = np.array(start)\n            return self\n        target_vect = np.asarray(end) - np.asarray(start)\n        axis = (\n            normalize(np.cross(curr_vect, target_vect))\n            if np.linalg.norm(np.cross(curr_vect, target_vect)) != 0\n            else OUT\n        )\n        self.scale(\n            np.linalg.norm(target_vect) / np.linalg.norm(curr_vect),\n            about_point=curr_start,\n        )\n        self.rotate(\n            angle_between_vectors(curr_vect, target_vect),\n            about_point=curr_start,\n            axis=axis,\n        )\n        self.shift(start - curr_start)\n        return self\n\n    # Background rectangle\n    def add_background_rectangle(\n        self,\n        color: ParsableManimColor | None = None,\n        opacity: float = 0.75,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Add a BackgroundRectangle as submobject.\n\n        The BackgroundRectangle is added behind other submobjects.\n\n        This can be used to increase the mobjects visibility in front of a noisy background.\n\n        Parameters\n        ----------\n        color\n            The color of the BackgroundRectangle\n        opacity\n            The opacity of the BackgroundRectangle\n        kwargs\n            Additional keyword arguments passed to the BackgroundRectangle constructor\n\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        See Also\n        --------\n        :meth:`add_to_back`\n        :class:`~.BackgroundRectangle`\n\n        \"\"\"\n        # TODO, this does not behave well when the mobject has points,\n        # since it gets displayed on top\n        from manim.mobject.geometry.shape_matchers import BackgroundRectangle\n\n        self.background_rectangle = BackgroundRectangle(\n            self, color=color, fill_opacity=opacity, **kwargs\n        )\n        self.add_to_back(self.background_rectangle)\n        return self\n\n    def add_background_rectangle_to_submobjects(self, **kwargs: Any) -> Self:\n        for submobject in self.submobjects:\n            submobject.add_background_rectangle(**kwargs)\n        return self\n\n    def add_background_rectangle_to_family_members_with_points(\n        self, **kwargs: Any\n    ) -> Self:\n        for mob in self.family_members_with_points():\n            mob.add_background_rectangle(**kwargs)\n        return self\n\n    # Color functions\n\n    def set_color(\n        self,\n        color: ParsableManimColor = PURE_YELLOW,\n        alpha: Any = None,\n        family: bool = True,\n    ) -> Self:\n        \"\"\"Condition is function which takes in one arguments, (x, y, z).\n        Here it just recurses to submobjects, but in subclasses this\n        should be further implemented based on the the inner workings\n        of color\n        \"\"\"\n        if family:\n            for submob in self.submobjects:\n                submob.set_color(color, family=family)\n\n        self.color = ManimColor.parse(color)\n        return self\n\n    def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self:\n        \"\"\"\n        Parameters\n        ----------\n        colors\n            The colors to use for the gradient. Use like `set_color_by_gradient(RED, BLUE, GREEN)`.\n\n        self.color = ManimColor.parse(color)\n        return self\n        \"\"\"\n        self.set_submobject_colors_by_gradient(*colors)\n        return self\n\n    def set_colors_by_radial_gradient(\n        self,\n        center: Point3DLike | None = None,\n        radius: float = 1,\n        inner_color: ParsableManimColor = WHITE,\n        outer_color: ParsableManimColor = BLACK,\n    ) -> Self:\n        self.set_submobject_colors_by_radial_gradient(\n            center,\n            radius,\n            inner_color,\n            outer_color,\n        )\n        return self\n\n    def set_submobject_colors_by_gradient(self, *colors: ParsableManimColor) -> Self:\n        if len(colors) == 0:\n            raise ValueError(\"Need at least one color\")\n        elif len(colors) == 1:\n            return self.set_color(*colors)\n\n        mobs = self.family_members_with_points()\n        new_colors = color_gradient(colors, len(mobs))\n\n        for mob, color in zip(mobs, new_colors, strict=True):\n            mob.set_color(color, family=False)\n        return self\n\n    def set_submobject_colors_by_radial_gradient(\n        self,\n        center: Point3DLike | None = None,\n        radius: float = 1,\n        inner_color: ParsableManimColor = WHITE,\n        outer_color: ParsableManimColor = BLACK,\n    ) -> Self:\n        if center is None:\n            center = self.get_center()\n\n        for mob in self.family_members_with_points():\n            t = np.linalg.norm(mob.get_center() - center) / radius\n            t = min(t, 1)\n            mob_color = interpolate_color(\n                ManimColor(inner_color), ManimColor(outer_color), t\n            )\n            mob.set_color(mob_color, family=False)\n\n        return self\n\n    def to_original_color(self) -> Self:\n        self.set_color(self.color)\n        return self\n\n    def fade_to(\n        self, color: ParsableManimColor, alpha: float, family: bool = True\n    ) -> Self:\n        if self.get_num_points() > 0:\n            new_color = interpolate_color(self.get_color(), ManimColor(color), alpha)\n            self.set_color(new_color, family=False)\n        if family:\n            for submob in self.submobjects:\n                submob.fade_to(color, alpha)\n        return self\n\n    def fade(self, darkness: float = 0.5, family: bool = True) -> Self:\n        if family:\n            for submob in self.submobjects:\n                submob.fade(darkness, family)\n        return self\n\n    def get_color(self) -> ManimColor:\n        \"\"\"Returns the color of the :class:`~.Mobject`\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import Square, RED\n            >>> Square(color=RED).get_color() == RED\n            True\n\n        \"\"\"\n        return self.color\n\n    ##\n\n    def save_state(self) -> Self:\n        \"\"\"Save the current state (position, color & size). Can be restored with :meth:`~.Mobject.restore`.\"\"\"\n        if hasattr(self, \"saved_state\"):\n            # Prevent exponential growth of data\n            self.saved_state = None\n        self.saved_state = self.copy()\n\n        return self\n\n    def restore(self) -> Self:\n        \"\"\"Restores the state that was previously saved with :meth:`~.Mobject.save_state`.\"\"\"\n        if not hasattr(self, \"saved_state\") or self.saved_state is None:\n            raise Exception(\"Trying to restore without having saved\")\n        self.become(self.saved_state)\n        return self\n\n    def reduce_across_dimension(\n        self, reduce_func: Callable[[Iterable[float]], float], dim: int\n    ) -> float:\n        \"\"\"Find the min or max value from a dimension across all points in this and submobjects.\"\"\"\n        assert dim >= 0\n        assert dim <= 2\n        if len(self.submobjects) == 0 and len(self.points) == 0:\n            # If we have no points and no submobjects, return 0 (e.g. center)\n            return 0\n\n        # If we do not have points (but do have submobjects)\n        # use only the points from those.\n        if len(self.points) == 0:  # noqa: SIM108\n            rv = None\n        else:\n            # Otherwise, be sure to include our own points\n            rv = reduce_func(self.points[:, dim])\n        # Recursively ask submobjects (if any) for the biggest/\n        # smallest dimension they have and compare it to the return value.\n        for mobj in self.submobjects:\n            value = mobj.reduce_across_dimension(reduce_func, dim)\n            rv = value if rv is None else reduce_func([value, rv])\n        assert rv is not None\n        return rv\n\n    def nonempty_submobjects(self) -> Sequence[Mobject]:\n        return [\n            submob\n            for submob in self.submobjects\n            if len(submob.submobjects) != 0 or len(submob.points) != 0\n        ]\n\n    def get_merged_array(self, array_attr: str) -> np.ndarray:\n        \"\"\"Return all of a given attribute from this mobject and all submobjects.\n\n        May contain duplicates; the order is in a depth-first (pre-order)\n        traversal of the submobjects.\n        \"\"\"\n        result = getattr(self, array_attr)\n        for submob in self.submobjects:\n            result = np.append(result, submob.get_merged_array(array_attr), axis=0)\n        return result\n\n    def get_all_points(self) -> Point3D_Array:\n        \"\"\"Return all points from this mobject and all submobjects.\n\n        May contain duplicates; the order is in a depth-first (pre-order)\n        traversal of the submobjects.\n        \"\"\"\n        return self.get_merged_array(\"points\")\n\n    # Getters\n\n    def get_points_defining_boundary(self) -> Point3D_Array:\n        return self.get_all_points()\n\n    def get_num_points(self) -> int:\n        return len(self.points)\n\n    def get_extremum_along_dim(\n        self, points: Point3DLike_Array | None = None, dim: int = 0, key: int = 0\n    ) -> float:\n        np_points: Point3D_Array = (\n            self.get_points_defining_boundary()\n            if points is None\n            else np.asarray(points)\n        )\n        values = np_points[:, dim]\n        if key < 0:\n            rv: float = np.min(values)\n            return rv\n        elif key == 0:\n            rv = (np.min(values) + np.max(values)) / 2\n            return rv\n        else:\n            rv = np.max(values)\n            return rv\n\n    def get_critical_point(self, direction: Vector3DLike) -> Point3D:\n        \"\"\"Picture a box bounding the :class:`~.Mobject`.  Such a box has\n        9 'critical points': 4 corners, 4 edge center, the\n        center. This returns one of them, along the given direction.\n\n        ::\n\n            sample = Arc(start_angle=PI / 7, angle=PI / 5)\n\n            # These are all equivalent\n            max_y_1 = sample.get_top()[1]\n            max_y_2 = sample.get_critical_point(UP)[1]\n            max_y_3 = sample.get_extremum_along_dim(dim=1, key=1)\n\n        \"\"\"\n        result = np.zeros(self.dim)\n        all_points = self.get_points_defining_boundary()\n        if len(all_points) == 0:\n            return result\n        for dim in range(self.dim):\n            result[dim] = self.get_extremum_along_dim(\n                all_points,\n                dim=dim,\n                key=np.array(direction[dim]),\n            )\n        return result\n\n    # Pseudonyms for more general get_critical_point method\n\n    def get_edge_center(self, direction: Vector3DLike) -> Point3D:\n        \"\"\"Get edge Point3Ds for certain direction.\"\"\"\n        return self.get_critical_point(direction)\n\n    def get_corner(self, direction: Vector3DLike) -> Point3D:\n        \"\"\"Get corner Point3Ds for certain direction.\"\"\"\n        return self.get_critical_point(direction)\n\n    def get_center(self) -> Point3D:\n        \"\"\"Get center Point3Ds\"\"\"\n        return self.get_critical_point(np.zeros(self.dim))\n\n    def get_center_of_mass(self) -> Point3D:\n        return np.apply_along_axis(np.mean, 0, self.get_all_points())\n\n    def get_boundary_point(self, direction: Vector3DLike) -> Point3D:\n        all_points = self.get_points_defining_boundary()\n        index = np.argmax(np.dot(all_points, direction))\n        return all_points[index]\n\n    def get_midpoint(self) -> Point3D:\n        \"\"\"Get Point3Ds of the middle of the path that forms the  :class:`~.Mobject`.\n\n        Examples\n        --------\n\n        .. manim:: AngleMidPoint\n            :save_last_frame:\n\n            class AngleMidPoint(Scene):\n                def construct(self):\n                    line1 = Line(ORIGIN, 2*RIGHT)\n                    line2 = Line(ORIGIN, 2*RIGHT).rotate_about_origin(80*DEGREES)\n\n                    a = Angle(line1, line2, radius=1.5, other_angle=False)\n                    d = Dot(a.get_midpoint()).set_color(RED)\n\n                    self.add(line1, line2, a, d)\n                    self.wait()\n\n        \"\"\"\n        return self.point_from_proportion(0.5)\n\n    def get_top(self) -> Point3D:\n        \"\"\"Get top Point3Ds of a box bounding the :class:`~.Mobject`\"\"\"\n        return self.get_edge_center(UP)\n\n    def get_bottom(self) -> Point3D:\n        \"\"\"Get bottom Point3Ds of a box bounding the :class:`~.Mobject`\"\"\"\n        return self.get_edge_center(DOWN)\n\n    def get_right(self) -> Point3D:\n        \"\"\"Get right Point3Ds of a box bounding the :class:`~.Mobject`\"\"\"\n        return self.get_edge_center(RIGHT)\n\n    def get_left(self) -> Point3D:\n        \"\"\"Get left Point3Ds of a box bounding the :class:`~.Mobject`\"\"\"\n        return self.get_edge_center(LEFT)\n\n    def get_zenith(self) -> Point3D:\n        \"\"\"Get zenith Point3Ds of a box bounding a 3D :class:`~.Mobject`.\"\"\"\n        return self.get_edge_center(OUT)\n\n    def get_nadir(self) -> Point3D:\n        \"\"\"Get nadir (opposite the zenith) Point3Ds of a box bounding a 3D :class:`~.Mobject`.\"\"\"\n        return self.get_edge_center(IN)\n\n    def length_over_dim(self, dim: int) -> float:\n        \"\"\"Measure the length of an :class:`~.Mobject` in a certain direction.\"\"\"\n        max_coord: float = self.reduce_across_dimension(\n            max,\n            dim,\n        )\n        min_coord: float = self.reduce_across_dimension(min, dim)\n        return max_coord - min_coord\n\n    def get_coord(self, dim: int, direction: Vector3DLike = ORIGIN) -> float:\n        \"\"\"Meant to generalize ``get_x``, ``get_y`` and ``get_z``\"\"\"\n        return self.get_extremum_along_dim(dim=dim, key=np.array(direction)[dim])\n\n    def get_x(self, direction: Vector3DLike = ORIGIN) -> float:\n        \"\"\"Returns x Point3D of the center of the :class:`~.Mobject` as ``float``\"\"\"\n        return self.get_coord(0, direction)\n\n    def get_y(self, direction: Vector3DLike = ORIGIN) -> float:\n        \"\"\"Returns y Point3D of the center of the :class:`~.Mobject` as ``float``\"\"\"\n        return self.get_coord(1, direction)\n\n    def get_z(self, direction: Vector3DLike = ORIGIN) -> float:\n        \"\"\"Returns z Point3D of the center of the :class:`~.Mobject` as ``float``\"\"\"\n        return self.get_coord(2, direction)\n\n    def get_start(self) -> Point3D:\n        \"\"\"Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts.\"\"\"\n        self.throw_error_if_no_points()\n        return np.array(self.points[0])\n\n    def get_end(self) -> Point3D:\n        \"\"\"Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends.\"\"\"\n        self.throw_error_if_no_points()\n        return np.array(self.points[-1])\n\n    def get_start_and_end(self) -> tuple[Point3D, Point3D]:\n        \"\"\"Returns starting and ending point of a stroke as a ``tuple``.\"\"\"\n        return self.get_start(), self.get_end()\n\n    def point_from_proportion(self, alpha: float) -> Point3D:\n        raise NotImplementedError(\"Please override in a child class.\")\n\n    def proportion_from_point(self, point: Point3DLike) -> float:\n        raise NotImplementedError(\"Please override in a child class.\")\n\n    def get_pieces(self, n_pieces: float) -> Group:\n        template = self.copy()\n        template.submobjects = []\n        alphas = np.linspace(0, 1, n_pieces + 1)\n        return Group(\n            *(\n                template.copy().pointwise_become_partial(self, a1, a2)\n                for a1, a2 in zip(alphas[:-1], alphas[1:], strict=True)\n            )\n        )\n\n    def get_z_index_reference_point(self) -> Point3D:\n        # TODO, better place to define default z_index_group?\n        z_index_group = getattr(self, \"z_index_group\", self)\n        return z_index_group.get_center()\n\n    def has_points(self) -> bool:\n        \"\"\"Check if :class:`~.Mobject` contains points.\"\"\"\n        return len(self.points) > 0\n\n    def has_no_points(self) -> bool:\n        \"\"\"Check if :class:`~.Mobject` *does not* contains points.\"\"\"\n        return not self.has_points()\n\n    # Match other mobject properties\n\n    def match_color(self, mobject: Mobject) -> Self:\n        \"\"\"Match the color with the color of another :class:`~.Mobject`.\"\"\"\n        return self.set_color(mobject.get_color())\n\n    def match_dim_size(self, mobject: Mobject, dim: int, **kwargs: Any) -> Self:\n        \"\"\"Match the specified dimension with the dimension of another :class:`~.Mobject`.\"\"\"\n        return self.rescale_to_fit(mobject.length_over_dim(dim), dim, **kwargs)\n\n    def match_width(self, mobject: Mobject, **kwargs: Any) -> Self:\n        \"\"\"Match the width with the width of another :class:`~.Mobject`.\"\"\"\n        return self.match_dim_size(mobject, 0, **kwargs)\n\n    def match_height(self, mobject: Mobject, **kwargs: Any) -> Self:\n        \"\"\"Match the height with the height of another :class:`~.Mobject`.\"\"\"\n        return self.match_dim_size(mobject, 1, **kwargs)\n\n    def match_depth(self, mobject: Mobject, **kwargs: Any) -> Self:\n        \"\"\"Match the depth with the depth of another :class:`~.Mobject`.\"\"\"\n        return self.match_dim_size(mobject, 2, **kwargs)\n\n    def match_coord(\n        self, mobject: Mobject, dim: int, direction: Vector3DLike = ORIGIN\n    ) -> Self:\n        \"\"\"Match the Point3Ds with the Point3Ds of another :class:`~.Mobject`.\"\"\"\n        return self.set_coord(\n            mobject.get_coord(dim, direction),\n            dim=dim,\n            direction=direction,\n        )\n\n    def match_x(self, mobject: Mobject, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Match x coord. to the x coord. of another :class:`~.Mobject`.\"\"\"\n        return self.match_coord(mobject, 0, direction)\n\n    def match_y(self, mobject: Mobject, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Match y coord. to the x coord. of another :class:`~.Mobject`.\"\"\"\n        return self.match_coord(mobject, 1, direction)\n\n    def match_z(self, mobject: Mobject, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Match z coord. to the x coord. of another :class:`~.Mobject`.\"\"\"\n        return self.match_coord(mobject, 2, direction)\n\n    def align_to(\n        self,\n        mobject_or_point: Mobject | Point3DLike,\n        direction: Vector3DLike = ORIGIN,\n    ) -> Self:\n        \"\"\"Aligns mobject to another :class:`~.Mobject` in a certain direction.\n\n        Examples:\n        mob1.align_to(mob2, UP) moves mob1 vertically so that its\n        top edge lines ups with mob2's top edge.\n        \"\"\"\n        if isinstance(mobject_or_point, Mobject):\n            point = mobject_or_point.get_critical_point(direction)\n        else:\n            point = mobject_or_point\n\n        for dim in range(self.dim):\n            if direction[dim] != 0:\n                self.set_coord(point[dim], dim, direction)\n        return self\n\n    # Family matters\n\n    def __getitem__(self, value: Any) -> Mobject | Group:\n        self_list = self.split()\n        if isinstance(value, slice):\n            GroupClass = self.get_group_class()\n            return GroupClass(*self_list.__getitem__(value))\n        rv: Mobject | Group = self_list.__getitem__(value)\n        return rv\n\n    def __iter__(self) -> Iterator[Mobject]:\n        return iter(self.split())\n\n    def __len__(self) -> int:\n        return len(self.split())\n\n    def get_group_class(self) -> type[Group]:\n        return Group\n\n    @staticmethod\n    def get_mobject_type_class() -> type[Mobject]:\n        \"\"\"Return the base class of this mobject type.\"\"\"\n        return Mobject\n\n    def split(self) -> list[Mobject]:\n        result: list[Mobject] = [self] if len(self.points) > 0 else []\n        return result + self.submobjects\n\n    def get_family(self, recurse: bool = True) -> list[Mobject]:\n        \"\"\"Lists all mobjects in the hierarchy (family) of the given mobject,\n        including the mobject itself and all its submobjects recursively.\n\n        Parameters\n        ----------\n        recurse\n            Just for consistency with get_family method in OpenGLMobject.\n\n        Returns\n        -------\n        list[Mobject]\n            A list of mobjects in the family of the given mobject.\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import Square, Rectangle, VGroup, Group, Mobject, VMobject\n            >>> s, r, m, v = Square(), Rectangle(), Mobject(), VMobject()\n            >>> vg = VGroup(s, r)\n            >>> gr = Group(vg, m, v)\n            >>> gr.get_family()\n            [Group, VGroup(Square, Rectangle), Square, Rectangle, Mobject, VMobject]\n\n        See also\n        --------\n        :meth:`~.Mobject.family_members_with_points`, :meth:`~.Mobject.align_data`\n\n        \"\"\"\n        sub_families = [x.get_family() for x in self.submobjects]\n        all_mobjects = [self] + list(it.chain(*sub_families))\n        return remove_list_redundancies(all_mobjects)\n\n    def family_members_with_points(self) -> list[Mobject]:\n        \"\"\"Filters the list of family members (generated by :meth:`.get_family`) to include only mobjects with points.\n\n        Returns\n        -------\n        list[Mobject]\n            A list of mobjects that have points.\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import Square, Rectangle, VGroup, Group, Mobject, VMobject\n            >>> s, r, m, v = Square(), Rectangle(), Mobject(), VMobject()\n            >>> vg = VGroup(s, r)\n            >>> gr = Group(vg, m, v)\n            >>> gr.family_members_with_points()\n            [Square, Rectangle]\n\n        See also\n        --------\n        :meth:`~.Mobject.get_family`\n\n        \"\"\"\n        return [m for m in self.get_family() if m.get_num_points() > 0]\n\n    def arrange(\n        self,\n        direction: Vector3DLike = RIGHT,\n        buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,\n        center: bool = True,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Sorts :class:`~.Mobject` next to each other on screen.\n\n        Examples\n        --------\n\n        .. manim:: Example\n            :save_last_frame:\n\n            class Example(Scene):\n                def construct(self):\n                    s1 = Square()\n                    s2 = Square()\n                    s3 = Square()\n                    s4 = Square()\n                    x = VGroup(s1, s2, s3, s4).set_x(0).arrange(buff=1.0)\n                    self.add(x)\n        \"\"\"\n        for m1, m2 in zip(self.submobjects[:-1], self.submobjects[1:], strict=True):\n            m2.next_to(m1, direction, buff, **kwargs)\n        if center:\n            self.center()\n        return self\n\n    def arrange_in_grid(\n        self,\n        rows: int | None = None,\n        cols: int | None = None,\n        buff: float | tuple[float, float] = MED_SMALL_BUFF,\n        cell_alignment: Vector3DLike = ORIGIN,\n        row_alignments: str | None = None,  # \"ucd\"\n        col_alignments: str | None = None,  # \"lcr\"\n        row_heights: Iterable[float | None] | None = None,\n        col_widths: Iterable[float | None] | None = None,\n        flow_order: str = \"rd\",\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Arrange submobjects in a grid.\n\n        Parameters\n        ----------\n        rows\n            The number of rows in the grid.\n        cols\n            The number of columns in the grid.\n        buff\n            The gap between grid cells. To specify a different buffer in the horizontal and\n            vertical directions, a tuple of two values can be given - ``(row, col)``.\n        cell_alignment\n            The way each submobject is aligned in its grid cell.\n        row_alignments\n            The vertical alignment for each row (top to bottom). Accepts the following characters: ``\"u\"`` -\n            up, ``\"c\"`` - center, ``\"d\"`` - down.\n        col_alignments\n            The horizontal alignment for each column (left to right). Accepts the following characters ``\"l\"`` - left,\n            ``\"c\"`` - center, ``\"r\"`` - right.\n        row_heights\n            Defines a list of heights for certain rows (top to bottom). If the list contains\n            ``None``, the corresponding row will fit its height automatically based\n            on the highest element in that row.\n        col_widths\n            Defines a list of widths for certain columns (left to right). If the list contains ``None``, the\n            corresponding column will fit its width automatically based on the widest element in that column.\n        flow_order\n            The order in which submobjects fill the grid. Can be one of the following values:\n            \"rd\", \"dr\", \"ld\", \"dl\", \"ru\", \"ur\", \"lu\", \"ul\". (\"rd\" -> fill rightwards then downwards)\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n        Raises\n        ------\n        ValueError\n            If ``rows`` and ``cols`` are too small to fit all submobjects.\n        ValueError\n            If :code:`cols`, :code:`col_alignments` and :code:`col_widths` or :code:`rows`,\n            :code:`row_alignments` and :code:`row_heights` have mismatching sizes.\n\n        Notes\n        -----\n        If only one of ``cols`` and ``rows`` is set implicitly, the other one will be chosen big\n        enough to fit all submobjects. If neither is set, they will be chosen to be about the same,\n        tending towards ``cols`` > ``rows`` (simply because videos are wider than they are high).\n\n        If both ``cell_alignment`` and ``row_alignments`` / ``col_alignments`` are\n        defined, the latter has higher priority.\n\n        Examples\n        --------\n        .. manim:: ExampleBoxes\n            :save_last_frame:\n\n            class ExampleBoxes(Scene):\n                def construct(self):\n                    boxes=VGroup(*[Square() for s in range(0,6)])\n                    boxes.arrange_in_grid(rows=2, buff=0.1)\n                    self.add(boxes)\n\n\n        .. manim:: ArrangeInGrid\n            :save_last_frame:\n\n            class ArrangeInGrid(Scene):\n                def construct(self):\n                    boxes = VGroup(*[\n                        Rectangle(WHITE, 0.5, 0.5).add(Text(str(i+1)).scale(0.5))\n                        for i in range(24)\n                    ])\n                    self.add(boxes)\n\n                    boxes.arrange_in_grid(\n                        buff=(0.25,0.5),\n                        col_alignments=\"lccccr\",\n                        row_alignments=\"uccd\",\n                        col_widths=[1, *[None]*4, 1],\n                        row_heights=[1, None, None, 1],\n                        flow_order=\"dr\"\n                    )\n\n\n        \"\"\"\n        from manim.mobject.geometry.line import Line\n\n        mobs = self.submobjects.copy()\n        start_pos = self.get_center()\n\n        # get cols / rows values if given (implicitly)\n        def init_size(\n            num: int | None,\n            alignments: str | None,\n            sizes: Iterable[float | None] | None,\n        ) -> int | None:\n            if num is not None:\n                return num\n            if alignments is not None:\n                return len(alignments)\n            if sizes is not None:\n                return len(list(sizes))\n            return None\n\n        cols = init_size(cols, col_alignments, col_widths)\n        rows = init_size(rows, row_alignments, row_heights)\n\n        # calculate rows cols\n        if rows is None and cols is None:\n            cols = math.ceil(math.sqrt(len(mobs)))\n            # make the grid as close to quadratic as possible.\n            # choosing cols first can results in cols>rows.\n            # This is favored over rows>cols since in general\n            # the scene is wider than high.\n        if rows is None:\n            assert isinstance(cols, int)\n            rows = math.ceil(len(mobs) / cols)\n        if cols is None:\n            cols = math.ceil(len(mobs) / rows)\n        if rows * cols < len(mobs):\n            raise ValueError(\"Too few rows and columns to fit all submobjetcs.\")\n        # rows and cols are now finally valid.\n\n        if isinstance(buff, tuple):\n            buff_x = buff[0]\n            buff_y = buff[1]\n        else:\n            buff_x = buff_y = buff\n\n        # Initialize alignments correctly\n        def init_alignments(\n            alignments: str | None,\n            num: int,\n            char_to_direction: dict[str, Vector3D],\n            name: str,\n            dir_: Vector3D,\n        ) -> list[Vector3D]:\n            if alignments is None:\n                # Use cell_alignment as fallback\n                return [cell_alignment * dir_] * num\n            if len(alignments) != num:\n                raise ValueError(f\"{name}_alignments has a mismatching size.\")\n            alignment_directions = [char_to_direction[char] for char in alignments]\n            return alignment_directions\n\n        row_alignment_directions = init_alignments(\n            row_alignments,\n            rows,\n            {\"u\": UP, \"c\": ORIGIN, \"d\": DOWN},\n            \"row\",\n            RIGHT,\n        )\n        col_alignment_directions = init_alignments(\n            col_alignments,\n            cols,\n            {\"l\": LEFT, \"c\": ORIGIN, \"r\": RIGHT},\n            \"col\",\n            UP,\n        )\n        # Now row_alignment[r] + col_alignment[c] is the alignment in cell [r][c]\n\n        mapper: dict[str, Callable[[int, int], int]] = {\n            \"dr\": lambda r, c: (rows - r - 1) + c * rows,\n            \"dl\": lambda r, c: (rows - r - 1) + (cols - c - 1) * rows,\n            \"ur\": lambda r, c: r + c * rows,\n            \"ul\": lambda r, c: r + (cols - c - 1) * rows,\n            \"rd\": lambda r, c: (rows - r - 1) * cols + c,\n            \"ld\": lambda r, c: (rows - r - 1) * cols + (cols - c - 1),\n            \"ru\": lambda r, c: r * cols + c,\n            \"lu\": lambda r, c: r * cols + (cols - c - 1),\n        }\n        if flow_order not in mapper:\n            raise ValueError(\n                'flow_order must be one of the following values: \"dr\", \"rd\", \"ld\" \"dl\", \"ru\", \"ur\", \"lu\", \"ul\".',\n            )\n        get_mob_index_by_position = mapper[flow_order]\n\n        # Reverse row_alignment_directions and row_heights. Necessary since the\n        # grid filling is handled bottom up for simplicity reasons.\n        row_alignment_directions.reverse()\n        row_heights_list = list(row_heights) if row_heights is not None else []\n        row_heights_list.reverse()\n        col_widths_list = list(col_widths) if col_widths is not None else []\n\n        placeholder = Mobject()\n        # Used to fill up the grid temporarily, doesn't get added to the scene.\n        # In this case a Mobject is better than None since it has width and height\n        # properties of 0.\n\n        mobs.extend([placeholder] * (rows * cols - len(mobs)))\n        grid = [\n            [mobs[get_mob_index_by_position(r, c)] for c in range(cols)]\n            for r in range(rows)\n        ]\n\n        measured_heigths = [\n            max(grid[r][c].height for c in range(cols)) for r in range(rows)\n        ]\n        measured_widths = [\n            max(grid[r][c].width for r in range(rows)) for c in range(cols)\n        ]\n\n        # Initialize row_heights / col_widths correctly using measurements as fallback\n        def init_sizes(\n            sizes: list[float | None] | None, num: int, measures: list[float], name: str\n        ) -> list[float]:\n            if sizes is None or len(sizes) == 0:\n                sizes = [None] * num\n            if len(sizes) != num:\n                raise ValueError(f\"{name} has a mismatching size.\")\n            return [\n                size if size is not None else measure\n                for size, measure in zip(sizes, measures, strict=False)\n            ]\n\n        heights = init_sizes(row_heights_list, rows, measured_heigths, \"row_heights\")\n        widths = init_sizes(col_widths_list, cols, measured_widths, \"col_widths\")\n\n        x, y = 0.0, 0.0\n        for r in range(rows):\n            x = 0\n            for c in range(cols):\n                if grid[r][c] is not placeholder:\n                    alignment = (\n                        row_alignment_directions[r] + col_alignment_directions[c]\n                    )\n                    line = Line(\n                        x * RIGHT + y * UP,\n                        (x + widths[c]) * RIGHT + (y + heights[r]) * UP,\n                    )\n                    # Use a mobject to avoid rewriting align inside\n                    # box code that Mobject.move_to(Mobject) already\n                    # includes.\n\n                    grid[r][c].move_to(line, alignment)\n                x += widths[c] + buff_x\n            y += heights[r] + buff_y\n\n        self.move_to(start_pos)\n        return self\n\n    def sort(\n        self,\n        point_to_num_func: Callable[[Point3DLike], float] = lambda p: p[0],\n        submob_func: Callable[[Mobject], Any] | None = None,\n    ) -> Self:\n        \"\"\"Sorts the list of :attr:`submobjects` by a function defined by ``submob_func``.\"\"\"\n        if submob_func is None:\n\n            def submob_func(m: Mobject) -> float:\n                return point_to_num_func(m.get_center())\n\n        self.submobjects.sort(key=submob_func)\n        return self\n\n    def shuffle(self, recursive: bool = False) -> None:\n        \"\"\"Shuffles the list of :attr:`submobjects`.\"\"\"\n        if recursive:\n            for submob in self.submobjects:\n                submob.shuffle(recursive=True)\n        random.shuffle(self.submobjects)\n\n    def invert(self, recursive: bool = False) -> None:\n        \"\"\"Inverts the list of :attr:`submobjects`.\n\n        Parameters\n        ----------\n        recursive\n            If ``True``, all submobject lists of this mobject's family are inverted.\n\n        Examples\n        --------\n\n        .. manim:: InvertSumobjectsExample\n\n            class InvertSumobjectsExample(Scene):\n                def construct(self):\n                    s = VGroup(*[Dot().shift(i*0.1*RIGHT) for i in range(-20,20)])\n                    s2 = s.copy()\n                    s2.invert()\n                    s2.shift(DOWN)\n                    self.play(Write(s), Write(s2))\n        \"\"\"\n        if recursive:\n            for submob in self.submobjects:\n                submob.invert(recursive=True)\n        self.submobjects.reverse()\n\n    # Just here to keep from breaking old scenes.\n    def arrange_submobjects(self, *args: Any, **kwargs: Any) -> Self:\n        \"\"\"Arrange the position of :attr:`submobjects` with a small buffer.\n\n        Examples\n        --------\n\n        .. manim:: ArrangeSumobjectsExample\n            :save_last_frame:\n\n            class ArrangeSumobjectsExample(Scene):\n                def construct(self):\n                    s= VGroup(*[Dot().shift(i*0.1*RIGHT*np.random.uniform(-1,1)+UP*np.random.uniform(-1,1)) for i in range(0,15)])\n                    s.shift(UP).set_color(BLUE)\n                    s2= s.copy().set_color(RED)\n                    s2.arrange_submobjects()\n                    s2.shift(DOWN)\n                    self.add(s,s2)\n\n        \"\"\"\n        return self.arrange(*args, **kwargs)\n\n    def sort_submobjects(self, *args: Any, **kwargs: Any) -> Self:\n        \"\"\"Sort the :attr:`submobjects`\"\"\"\n        return self.sort(*args, **kwargs)\n\n    def shuffle_submobjects(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"Shuffles the order of :attr:`submobjects`\n\n        Examples\n        --------\n\n        .. manim:: ShuffleSubmobjectsExample\n\n            class ShuffleSubmobjectsExample(Scene):\n                def construct(self):\n                    s= VGroup(*[Dot().shift(i*0.1*RIGHT) for i in range(-20,20)])\n                    s2= s.copy()\n                    s2.shuffle_submobjects()\n                    s2.shift(DOWN)\n                    self.play(Write(s), Write(s2))\n        \"\"\"\n        return self.shuffle(*args, **kwargs)\n\n    # Alignment\n    def align_data(self, mobject: Mobject, skip_point_alignment: bool = False) -> None:\n        \"\"\"Aligns the family structure and data of this mobject with another mobject.\n\n        Afterwards, the two mobjects will have the same number of submobjects\n        (see :meth:`.align_submobjects`) and the same parent structure (see\n        :meth:`.null_point_align`). If ``skip_point_alignment`` is ``False``,\n        they will also have the same number of points (see :meth:`.align_points`).\n\n        Parameters\n        ----------\n        mobject\n            The other mobject this mobject should be aligned to.\n        skip_point_alignment\n            Controls whether or not the computationally expensive\n            point alignment is skipped (default: ``False``).\n\n\n        .. note::\n\n            This method is primarily used internally by :meth:`.become` and the\n            :class:`~.Transform` animation to ensure that mobjects are structurally\n            compatible before transformation.\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import Rectangle, Line, ORIGIN, RIGHT\n            >>> rect = Rectangle(width=4.0, height=2.0, grid_xstep=1.0, grid_ystep=0.5)\n            >>> line = Line(start=ORIGIN,end=RIGHT)\n            >>> line.align_data(rect)\n            >>> len(line.get_family()) == len(rect.get_family())\n            True\n            >>> line.get_num_points() == rect.get_num_points()\n            True\n\n        See also\n        --------\n        :class:`~.Transform`, :meth:`~.Mobject.become`, :meth:`~.VMobject.align_points`, :meth:`~.Mobject.get_family`\n\n        \"\"\"\n        self.null_point_align(mobject)\n        self.align_submobjects(mobject)\n        if not skip_point_alignment:\n            self.align_points(mobject)\n        # Recurse\n        for m1, m2 in zip(self.submobjects, mobject.submobjects, strict=True):\n            m1.align_data(m2)\n\n    def get_point_mobject(self, center: Point3DLike | None = None) -> Point:\n        \"\"\"The simplest :class:`~.Mobject` to be transformed to or from self.\n        Should by a point of the appropriate type\n        \"\"\"\n        msg = f\"get_point_mobject not implemented for {self.__class__.__name__}\"\n        raise NotImplementedError(msg)\n\n    def align_points(self, mobject: Mobject) -> Self:\n        count1 = self.get_num_points()\n        count2 = mobject.get_num_points()\n        if count1 < count2:\n            self.align_points_with_larger(mobject)\n        elif count2 < count1:\n            mobject.align_points_with_larger(self)\n        return self\n\n    def align_points_with_larger(self, larger_mobject: Mobject) -> None:\n        raise NotImplementedError(\"Please override in a child class.\")\n\n    def align_submobjects(self, mobject: Mobject) -> Self:\n        mob1 = self\n        mob2 = mobject\n        n1 = len(mob1.submobjects)\n        n2 = len(mob2.submobjects)\n        mob1.add_n_more_submobjects(max(0, n2 - n1))\n        mob2.add_n_more_submobjects(max(0, n1 - n2))\n        return self\n\n    def null_point_align(self, mobject: Mobject) -> Self:\n        \"\"\"If a :class:`~.Mobject` with points is being aligned to\n        one without, treat both as groups, and push\n        the one with points into its own submobjects\n        list.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n        \"\"\"\n        for m1, m2 in (self, mobject), (mobject, self):\n            if m1.has_no_points() and m2.has_points():\n                m2.push_self_into_submobjects()\n        return self\n\n    def push_self_into_submobjects(self) -> Self:\n        copy = self.copy()\n        copy.submobjects = []\n        self.reset_points()\n        self.add(copy)\n        return self\n\n    def add_n_more_submobjects(self, n: int) -> Self | None:\n        if n == 0:\n            return None\n\n        curr = len(self.submobjects)\n        if curr == 0:\n            # If empty, simply add n point mobjects\n            self.submobjects = [self.get_point_mobject() for k in range(n)]\n            return None\n\n        target = curr + n\n        # TODO, factor this out to utils so as to reuse\n        # with VMobject.insert_n_curves\n        repeat_indices = (np.arange(target) * curr) // target\n        split_factors = [sum(repeat_indices == i) for i in range(curr)]\n        new_submobs = []\n        for submob, sf in zip(self.submobjects, split_factors, strict=True):\n            new_submobs.append(submob)\n            new_submobs.extend(submob.copy().fade(1) for _ in range(1, sf))\n        self.submobjects = new_submobs\n        return self\n\n    def repeat_submobject(self, submob: Mobject) -> Mobject:\n        return submob.copy()\n\n    def interpolate(\n        self,\n        mobject1: Mobject,\n        mobject2: Mobject,\n        alpha: float,\n        path_func: PathFuncType = straight_path(),\n    ) -> Self:\n        \"\"\"Turns this :class:`~.Mobject` into an interpolation between ``mobject1``\n        and ``mobject2``.\n\n        The interpolation is applied to the points and color of the mobject.\n\n        Parameters\n        ----------\n        mobject1\n            The starting Mobject.\n        mobject2\n            The target Mobject.\n        alpha\n            Interpolation factor between 0 (at ``mobject1``) and 1 (at ``mobject2``).\n        path_func\n            The function defining the interpolation path. Defaults to a straight path.\n\n        Returns\n        -------\n        :class:`Mobject`\n            ``self``\n\n\n        .. note::\n\n            - Both mobjects must have the same number of points. If not, this will raise an error.\n              Use :meth:`~.VMobject.align_points` to match point counts beforehand if needed.\n            - This method is used internally by the :class:`~.Transform` animation\n              to interpolate between two mobjects during a transformation.\n\n        Examples\n        --------\n\n        .. manim:: InterpolateExample\n            :save_last_frame:\n\n            class InterpolateExample(Scene):\n                def construct(self):\n                    # No need for point alignment:\n                    dotL = Dot(color=DARK_GREY).to_edge(LEFT)\n                    dotR = Dot(color=YELLOW).scale(10).to_edge(RIGHT)\n                    dotMid1 = VMobject().interpolate(dotL, dotR, alpha=0.1)\n                    dotMid2 = VMobject().interpolate(dotL, dotR, alpha=0.25)\n                    dotMid3 = VMobject().interpolate(dotL, dotR, alpha=0.5)\n                    dotMid4 = VMobject().interpolate(dotL, dotR, alpha=0.75)\n                    dots = VGroup(dotL, dotR, dotMid1, dotMid2, dotMid3, dotMid4)\n\n                    # Needs point alignment:\n                    line = Line(ORIGIN, UP).to_edge(LEFT)\n                    sq = Square(color=RED, fill_opacity=1, stroke_color=BLUE).to_edge(RIGHT)\n                    line.align_points(sq)\n                    mid1 = VMobject().interpolate(line, sq, alpha=0.1)\n                    mid2 = VMobject().interpolate(line, sq, alpha=0.25)\n                    mid3 = VMobject().interpolate(line, sq, alpha=0.5)\n                    mid4 = VMobject().interpolate(line, sq, alpha=0.75)\n                    linesquares = VGroup(line, sq, mid1, mid2, mid3, mid4)\n\n                    self.add(VGroup(dots, linesquares).arrange(DOWN, buff=1))\n        See also\n        --------\n        :class:`~.Transform`, :meth:`~.VMobject.align_points`, :meth:`~.VMobject.interpolate_color`\n\n        \"\"\"\n        self.points = path_func(mobject1.points, mobject2.points, alpha)\n        self.interpolate_color(mobject1, mobject2, alpha)\n        return self\n\n    def interpolate_color(\n        self, mobject1: Mobject, mobject2: Mobject, alpha: float\n    ) -> None:\n        raise NotImplementedError(\"Please override in a child class.\")\n\n    def become(\n        self,\n        mobject: Mobject,\n        match_height: bool = False,\n        match_width: bool = False,\n        match_depth: bool = False,\n        match_center: bool = False,\n        stretch: bool = False,\n    ) -> Self:\n        \"\"\"Edit points, colors and submobjects to be identical\n        to another :class:`~.Mobject`\n\n        .. note::\n\n            If both match_height and match_width are ``True`` then the transformed :class:`~.Mobject`\n            will match the height first and then the width.\n\n        Parameters\n        ----------\n        match_height\n            Whether or not to preserve the height of the original\n            :class:`~.Mobject`.\n        match_width\n            Whether or not to preserve the width of the original\n            :class:`~.Mobject`.\n        match_depth\n            Whether or not to preserve the depth of the original\n            :class:`~.Mobject`.\n        match_center\n            Whether or not to preserve the center of the original\n            :class:`~.Mobject`.\n        stretch\n            Whether or not to stretch the target mobject to match the\n            the proportions of the original :class:`~.Mobject`.\n\n        Examples\n        --------\n        .. manim:: BecomeScene\n\n            class BecomeScene(Scene):\n                def construct(self):\n                    circ = Circle(fill_color=RED, fill_opacity=0.8)\n                    square = Square(fill_color=BLUE, fill_opacity=0.2)\n                    self.add(circ)\n                    self.wait(0.5)\n                    circ.become(square)\n                    self.wait(0.5)\n\n\n        The following examples illustrate how mobject measurements\n        change when using the ``match_...`` and ``stretch`` arguments.\n        We start with a rectangle that is 2 units high and 4 units wide,\n        which we want to turn into a circle of radius 3::\n\n            >>> from manim import Rectangle, Circle\n            >>> import numpy as np\n            >>> rect = Rectangle(height=2, width=4)\n            >>> circ = Circle(radius=3)\n\n        With ``stretch=True``, the target circle is deformed to match\n        the proportions of the rectangle, which results in the target\n        mobject being an ellipse with height 2 and width 4. We can\n        check that the resulting points satisfy the ellipse equation\n        :math:`x^2/a^2 + y^2/b^2 = 1` with :math:`a = 4/2` and :math:`b = 2/2`\n        being the semi-axes::\n\n            >>> result = rect.copy().become(circ, stretch=True)\n            >>> result.height, result.width\n            (np.float64(2.0), np.float64(4.0))\n            >>> ellipse_points = np.array(result.get_anchors())\n            >>> ellipse_eq = np.sum(ellipse_points**2 * [1/4, 1, 0], axis=1)\n            >>> np.allclose(ellipse_eq, 1)\n            True\n\n        With ``match_height=True`` and ``match_width=True`` the circle is\n        scaled such that the height or the width of the rectangle will\n        be preserved, respectively.\n        The points of the resulting mobject satisfy the circle equation\n        :math:`x^2 + y^2 = r^2` for the corresponding radius :math:`r`::\n\n            >>> result = rect.copy().become(circ, match_height=True)\n            >>> result.height, result.width\n            (np.float64(2.0), np.float64(2.0))\n            >>> circle_points = np.array(result.get_anchors())\n            >>> circle_eq = np.sum(circle_points**2, axis=1)\n            >>> np.allclose(circle_eq, 1)\n            True\n            >>> result = rect.copy().become(circ, match_width=True)\n            >>> result.height, result.width\n            (np.float64(4.0), np.float64(4.0))\n            >>> circle_points = np.array(result.get_anchors())\n            >>> circle_eq = np.sum(circle_points**2, axis=1)\n            >>> np.allclose(circle_eq, 2**2)\n            True\n\n        With ``match_center=True``, the resulting mobject is moved such that\n        its center is the same as the center of the original mobject::\n\n            >>> rect = rect.shift(np.array([0, 1, 0]))\n            >>> np.allclose(rect.get_center(), circ.get_center())\n            False\n            >>> result = rect.copy().become(circ, match_center=True)\n            >>> np.allclose(rect.get_center(), result.get_center())\n            True\n\n        See also\n        --------\n        :meth:`~.Mobject.align_data`, :meth:`~.VMobject.interpolate_color`\n        \"\"\"\n        if stretch or match_height or match_width or match_depth or match_center:\n            mobject = mobject.copy()\n            if stretch:\n                mobject.stretch_to_fit_height(self.height)\n                mobject.stretch_to_fit_width(self.width)\n                mobject.stretch_to_fit_depth(self.depth)\n            else:\n                if match_height:\n                    mobject.match_height(self)\n                if match_width:\n                    mobject.match_width(self)\n                if match_depth:\n                    mobject.match_depth(self)\n\n            if match_center:\n                mobject.move_to(self.get_center())\n\n        self.align_data(mobject, skip_point_alignment=True)\n        for sm1, sm2 in zip(self.get_family(), mobject.get_family(), strict=True):\n            sm1.points = np.array(sm2.points)\n            sm1.interpolate_color(sm1, sm2, 1)\n        return self\n\n    def match_points(self, mobject: Mobject, copy_submobjects: bool = True) -> Self:\n        \"\"\"Edit points, positions, and submobjects to be identical\n        to another :class:`~.Mobject`, while keeping the style unchanged.\n\n        Examples\n        --------\n        .. manim:: MatchPointsScene\n\n            class MatchPointsScene(Scene):\n                def construct(self):\n                    circ = Circle(fill_color=RED, fill_opacity=0.8)\n                    square = Square(fill_color=BLUE, fill_opacity=0.2)\n                    self.add(circ)\n                    self.wait(0.5)\n                    self.play(circ.animate.match_points(square))\n                    self.wait(0.5)\n        \"\"\"\n        for sm1, sm2 in zip(self.get_family(), mobject.get_family(), strict=False):\n            sm1.points = np.array(sm2.points)\n        return self\n\n    # Errors\n    def throw_error_if_no_points(self) -> None:\n        if self.has_no_points():\n            caller_name = sys._getframe(1).f_code.co_name\n            raise Exception(\n                f\"Cannot call Mobject.{caller_name} for a Mobject with no points\",\n            )\n\n    # About z-index\n    def set_z_index(\n        self,\n        z_index_value: float,\n        family: bool = True,\n    ) -> Self:\n        \"\"\"Sets the :class:`~.Mobject`'s :attr:`z_index` to the value specified in `z_index_value`.\n\n        Parameters\n        ----------\n        z_index_value\n            The new value of :attr:`z_index` set.\n        family\n            If ``True``, the :attr:`z_index` value of all submobjects is also set.\n\n        Returns\n        -------\n        :class:`Mobject`\n            The Mobject itself, after :attr:`z_index` is set. For chaining purposes. (Returns `self`.)\n\n        Examples\n        --------\n        .. manim:: SetZIndex\n            :save_last_frame:\n\n            class SetZIndex(Scene):\n                def construct(self):\n                    text = Text('z_index = 3', color = PURE_RED).shift(UP).set_z_index(3)\n                    square = Square(2, fill_opacity=1).set_z_index(2)\n                    tex = Tex(r'zIndex = 1', color = PURE_BLUE).shift(DOWN).set_z_index(1)\n                    circle = Circle(radius = 1.7, color = GREEN, fill_opacity = 1) # z_index = 0\n\n                    # Displaying order is now defined by z_index values\n                    self.add(text)\n                    self.add(square)\n                    self.add(tex)\n                    self.add(circle)\n        \"\"\"\n        if family:\n            for submob in self.submobjects:\n                submob.set_z_index(z_index_value, family=family)\n        self.z_index = z_index_value\n        return self\n\n    def set_z_index_by_z_Point3D(self) -> Self:\n        \"\"\"Sets the :class:`~.Mobject`'s z Point3D to the value of :attr:`z_index`.\n\n        Returns\n        -------\n        :class:`Mobject`\n            The Mobject itself, after :attr:`z_index` is set. (Returns `self`.)\n        \"\"\"\n        z_coord = self.get_center()[-1]\n        self.set_z_index(z_coord)\n        return self\n\n\nclass Group(Mobject, metaclass=ConvertToOpenGL):\n    \"\"\"Groups together multiple :class:`Mobjects <.Mobject>`.\n\n    Notes\n    -----\n    When adding the same mobject more than once, repetitions are ignored.\n    Use :meth:`.Mobject.copy` to create a separate copy which can then\n    be added to the group.\n    \"\"\"\n\n    def __init__(self, *mobjects: Any, **kwargs: Any) -> None:\n        super().__init__(**kwargs)\n        self.add(*mobjects)\n\n\nclass _AnimationBuilder:\n    def __init__(self, mobject: Mobject) -> None:\n        self.mobject = mobject\n        self.mobject.generate_target()\n\n        self.overridden_animation: Animation | None = None\n        self.is_chaining = False\n        self.methods: list[MethodWithArgs] = []\n\n        # Whether animation args can be passed\n        self.cannot_pass_args = False\n        self.anim_args: dict[str, Any] = {}\n\n    def __call__(self, **kwargs: Any) -> Self:\n        if self.cannot_pass_args:\n            raise ValueError(\n                \"Animation arguments must be passed before accessing methods and can only be passed once\",\n            )\n\n        self.anim_args = kwargs\n        self.cannot_pass_args = True\n\n        return self\n\n    def __getattr__(self, method_name: str) -> Callable[..., _AnimationBuilder]:\n        method = getattr(self.mobject.target, method_name)\n        has_overridden_animation = hasattr(method, \"_override_animate\")\n\n        if (self.is_chaining and has_overridden_animation) or self.overridden_animation:\n            raise NotImplementedError(\n                \"Method chaining is currently not supported for overridden animations\",\n            )\n\n        def update_target(*method_args: Any, **method_kwargs: Any) -> _AnimationBuilder:\n            if has_overridden_animation:\n                self.overridden_animation = method._override_animate(\n                    self.mobject,\n                    *method_args,\n                    anim_args=self.anim_args,\n                    **method_kwargs,\n                )\n            else:\n                self.methods.append(MethodWithArgs(method, method_args, method_kwargs))\n                method(*method_args, **method_kwargs)\n            return self\n\n        self.is_chaining = True\n        self.cannot_pass_args = True\n\n        return update_target\n\n    def build(self) -> Animation:\n        from ..animation.transform import _MethodAnimation\n\n        anim = self.overridden_animation or _MethodAnimation(self.mobject, self.methods)\n\n        for attr, value in self.anim_args.items():\n            setattr(anim, attr, value)\n\n        return anim\n\n\nclass _UpdaterBuilder:\n    \"\"\"Syntactic sugar for adding updaters to mobjects.\"\"\"\n\n    def __init__(self, mobject: Mobject):\n        self._mobject = mobject\n\n    def __getattr__(self, name: str, /) -> Callable[..., _UpdaterBuilder]:\n        # just return a function that will add the updater\n        def add_updater(*method_args: Any, **method_kwargs: Any) -> _UpdaterBuilder:\n            self._mobject.add_updater(\n                lambda m: getattr(m, name)(*method_args, **method_kwargs),\n                call_updater=True,\n            )\n            return self\n\n        return add_updater\n\n\ndef override_animate(\n    method: types.MethodType,\n) -> Callable[[types.MethodType], types.MethodType]:\n    r\"\"\"Decorator for overriding method animations.\n\n    This allows to specify a method (returning an :class:`~.Animation`)\n    which is called when the decorated method is used with the ``.animate`` syntax\n    for animating the application of a method.\n\n    .. seealso::\n\n        :attr:`~.Mobject.animate`\n\n    .. note::\n\n        Overridden methods cannot be combined with normal or other overridden\n        methods using method chaining with the ``.animate`` syntax.\n\n\n    Examples\n    --------\n\n    .. manim:: AnimationOverrideExample\n\n        class CircleWithContent(VGroup):\n            def __init__(self, content):\n                super().__init__()\n                self.circle = Circle()\n                self.content = content\n                self.add(self.circle, content)\n                content.move_to(self.circle.get_center())\n\n            def clear_content(self):\n                self.remove(self.content)\n                self.content = None\n\n            @override_animate(clear_content)\n            def _clear_content_animation(self, anim_args=None):\n                if anim_args is None:\n                    anim_args = {}\n                anim = Uncreate(self.content, **anim_args)\n                self.clear_content()\n                return anim\n\n        class AnimationOverrideExample(Scene):\n            def construct(self):\n                t = Text(\"hello!\")\n                my_mobject = CircleWithContent(t)\n                self.play(Create(my_mobject))\n                self.play(my_mobject.animate.clear_content())\n                self.wait()\n\n    \"\"\"\n    temp_method = cast(_AnimationBuilder, method)\n\n    def decorator(animation_method: types.MethodType) -> types.MethodType:\n        # error: \"Callable[..., Animation]\" has no attribute \"_override_animate\"  [attr-defined]\n        temp_method._override_animate = animation_method  # type: ignore[attr-defined]\n        return animation_method\n\n    return decorator\n"
  },
  {
    "path": "manim/mobject/opengl/__init__.py",
    "content": ""
  },
  {
    "path": "manim/mobject/opengl/dot_cloud.py",
    "content": "from __future__ import annotations\n\n__all__ = [\"TrueDot\", \"DotCloud\"]\n\nfrom typing import Any, Self\n\nimport numpy as np\n\nfrom manim.constants import ORIGIN, RIGHT, UP\nfrom manim.mobject.opengl.opengl_point_cloud_mobject import OpenGLPMobject\nfrom manim.typing import Point3DLike\nfrom manim.utils.color import PURE_YELLOW, ParsableManimColor\n\n\nclass DotCloud(OpenGLPMobject):\n    def __init__(\n        self,\n        color: ParsableManimColor = PURE_YELLOW,\n        stroke_width: float = 2.0,\n        radius: float = 2.0,\n        density: float = 10,\n        **kwargs: Any,\n    ):\n        self.radius = radius\n        self.epsilon = 1.0 / density\n        super().__init__(\n            stroke_width=stroke_width, density=density, color=color, **kwargs\n        )\n\n    def init_points(self) -> None:\n        self.points = np.array(\n            [\n                r * (np.cos(theta) * RIGHT + np.sin(theta) * UP)\n                for r in np.arange(self.epsilon, self.radius, self.epsilon)\n                # Num is equal to int(stop - start)/ (step + 1) reformulated.\n                for theta in np.linspace(\n                    0,\n                    2 * np.pi,\n                    num=int(2 * np.pi * (r + self.epsilon) / self.epsilon),\n                )\n            ],\n            dtype=np.float32,\n        )\n\n    def make_3d(self, gloss: float = 0.5, shadow: float = 0.2) -> Self:\n        self.set_gloss(gloss)\n        self.set_shadow(shadow)\n        self.apply_depth_test()\n        return self\n\n\nclass TrueDot(DotCloud):\n    def __init__(\n        self, center: Point3DLike = ORIGIN, stroke_width: float = 2.0, **kwargs: Any\n    ):\n        self.radius = stroke_width\n        super().__init__(points=[center], stroke_width=stroke_width, **kwargs)\n"
  },
  {
    "path": "manim/mobject/opengl/opengl_compatibility.py",
    "content": "from __future__ import annotations\n\nfrom abc import ABCMeta\nfrom typing import Any\n\nfrom manim import config\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.mobject.opengl.opengl_point_cloud_mobject import OpenGLPMobject\nfrom manim.mobject.opengl.opengl_three_dimensions import OpenGLSurface\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject\n\nfrom ...constants import RendererType\n\n__all__ = [\"ConvertToOpenGL\"]\n\n\nclass ConvertToOpenGL(ABCMeta):\n    \"\"\"Metaclass for swapping (V)Mobject with its OpenGL counterpart at runtime\n    depending on config.renderer. This metaclass should only need to be inherited\n    on the lowest order inheritance classes such as Mobject and VMobject.\n    \"\"\"\n\n    _converted_classes: list[type] = []\n\n    def __new__(\n        mcls, name: str, bases: tuple[type, ...], namespace: dict[str, Any]\n    ) -> type:\n        if config.renderer == RendererType.OPENGL:\n            # Must check class names to prevent\n            # cyclic importing.\n            base_names_to_opengl: dict[str, type] = {\n                \"Mobject\": OpenGLMobject,\n                \"VMobject\": OpenGLVMobject,\n                \"PMobject\": OpenGLPMobject,\n                \"Mobject1D\": OpenGLPMobject,\n                \"Mobject2D\": OpenGLPMobject,\n                \"Surface\": OpenGLSurface,\n            }\n\n            bases = tuple(\n                base_names_to_opengl.get(base.__name__, base) for base in bases\n            )\n\n        return super().__new__(mcls, name, bases, namespace)\n\n    def __init__(cls, name: str, bases: tuple[type, ...], namespace: dict[str, Any]):\n        super().__init__(name, bases, namespace)\n        cls._converted_classes.append(cls)\n"
  },
  {
    "path": "manim/mobject/opengl/opengl_geometry.py",
    "content": "from __future__ import annotations\n\nfrom typing import Any, Self, cast\n\nimport numpy as np\n\nfrom manim.constants import *\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.opengl.opengl_vectorized_mobject import (\n    OpenGLDashedVMobject,\n    OpenGLMobject,\n    OpenGLVGroup,\n    OpenGLVMobject,\n)\nfrom manim.typing import (\n    Point3D,\n    Point3D_Array,\n    Point3DLike,\n    QuadraticSpline,\n    Vector2DLike,\n    Vector3D,\n    Vector3DLike,\n)\nfrom manim.utils.color import *\nfrom manim.utils.iterables import adjacent_n_tuples, adjacent_pairs\nfrom manim.utils.simple_functions import clip\nfrom manim.utils.space_ops import (\n    angle_between_vectors,\n    angle_of_vector,\n    compass_directions,\n    find_intersection,\n    normalize,\n    rotate_vector,\n    rotation_matrix_transpose,\n)\n\nDEFAULT_DOT_RADIUS = 0.08\nDEFAULT_DASH_LENGTH = 0.05\nDEFAULT_ARROW_TIP_LENGTH = 0.35\nDEFAULT_ARROW_TIP_WIDTH = 0.35\n\n__all__ = [\n    \"OpenGLTipableVMobject\",\n    \"OpenGLArc\",\n    \"OpenGLArcBetweenPoints\",\n    \"OpenGLCurvedArrow\",\n    \"OpenGLCurvedDoubleArrow\",\n    \"OpenGLCircle\",\n    \"OpenGLDot\",\n    \"OpenGLEllipse\",\n    \"OpenGLAnnularSector\",\n    \"OpenGLSector\",\n    \"OpenGLAnnulus\",\n    \"OpenGLLine\",\n    \"OpenGLDashedLine\",\n    \"OpenGLTangentLine\",\n    \"OpenGLElbow\",\n    \"OpenGLArrow\",\n    \"OpenGLVector\",\n    \"OpenGLDoubleArrow\",\n    \"OpenGLCubicBezier\",\n    \"OpenGLPolygon\",\n    \"OpenGLRegularPolygon\",\n    \"OpenGLTriangle\",\n    \"OpenGLArrowTip\",\n]\n\n\nclass OpenGLTipableVMobject(OpenGLVMobject):\n    \"\"\"\n    Meant for shared functionality between Arc and Line.\n    Functionality can be classified broadly into these groups:\n\n        * Adding, Creating, Modifying tips\n            - add_tip calls create_tip, before pushing the new tip\n                into the TipableVMobject's list of submobjects\n            - stylistic and positional configuration\n\n        * Checking for tips\n            - Boolean checks for whether the TipableVMobject has a tip\n                and a starting tip\n\n        * Getters\n            - Straightforward accessors, returning information pertaining\n                to the TipableVMobject instance's tip(s), its length etc\n    \"\"\"\n\n    # Adding, Creating, Modifying tips\n\n    def __init__(\n        self,\n        tip_length: float = DEFAULT_ARROW_TIP_LENGTH,\n        normal_vector: Vector3DLike = OUT,\n        tip_config: dict[str, Any] = {},\n        **kwargs: Any,\n    ):\n        self.tip_length = tip_length\n        self.normal_vector = normal_vector\n        self.tip_config = tip_config\n        super().__init__(**kwargs)\n\n    def add_tip(self, at_start: bool = False, **kwargs: Any) -> Self:\n        \"\"\"\n        Adds a tip to the TipableVMobject instance, recognising\n        that the endpoints might need to be switched if it's\n        a 'starting tip' or not.\n        \"\"\"\n        tip = self.create_tip(at_start, **kwargs)\n        self.reset_endpoints_based_on_tip(tip, at_start)\n        self.assign_tip_attr(tip, at_start)\n        self.add(tip)\n        return self\n\n    def create_tip(self, at_start: bool = False, **kwargs: Any) -> OpenGLArrowTip:\n        \"\"\"\n        Stylises the tip, positions it spacially, and returns\n        the newly instantiated tip to the caller.\n        \"\"\"\n        tip = self.get_unpositioned_tip(**kwargs)\n        self.position_tip(tip, at_start)\n        return tip\n\n    def get_unpositioned_tip(self, **kwargs: Any) -> OpenGLArrowTip:\n        \"\"\"\n        Returns a tip that has been stylistically configured,\n        but has not yet been given a position in space.\n        \"\"\"\n        config = {}\n        config.update(self.tip_config)\n        config.update(kwargs)\n        return OpenGLArrowTip(**config)\n\n    def position_tip(\n        self, tip: OpenGLArrowTip, at_start: bool = False\n    ) -> OpenGLArrowTip:\n        # Last two control points, defining both\n        # the end, and the tangency direction\n        if at_start:\n            anchor = self.get_start()\n            handle = self.get_first_handle()\n        else:\n            handle = self.get_last_handle()\n            anchor = self.get_end()\n        tip.rotate(angle_of_vector(handle - anchor) - PI - tip.get_angle())\n        tip.shift(anchor - tip.get_tip_point())\n        return tip\n\n    def reset_endpoints_based_on_tip(self, tip: OpenGLArrowTip, at_start: bool) -> Self:\n        if self.get_length() == 0:\n            # Zero length, put_start_and_end_on wouldn't\n            # work\n            return self\n\n        if at_start:\n            start = tip.get_base()\n            end = self.get_end()\n        else:\n            start = self.get_start()\n            end = tip.get_base()\n        self.put_start_and_end_on(start, end)\n        return self\n\n    def assign_tip_attr(self, tip: OpenGLArrowTip, at_start: bool) -> Self:\n        if at_start:\n            self.start_tip = tip\n        else:\n            self.tip = tip\n        return self\n\n    # Checking for tips\n    def has_tip(self) -> bool:\n        return hasattr(self, \"tip\") and self.tip in self\n\n    def has_start_tip(self) -> bool:\n        return hasattr(self, \"start_tip\") and self.start_tip in self\n\n    # Getters\n    def pop_tips(self) -> OpenGLVGroup:\n        start, end = self.get_start_and_end()\n        result = OpenGLVGroup()\n        if self.has_tip():\n            result.add(self.tip)\n            self.remove(self.tip)\n        if self.has_start_tip():\n            result.add(self.start_tip)\n            self.remove(self.start_tip)\n        self.put_start_and_end_on(start, end)\n        return result\n\n    def get_tips(self) -> OpenGLVGroup:\n        \"\"\"\n        Returns a VGroup (collection of VMobjects) containing\n        the TipableVMObject instance's tips.\n        \"\"\"\n        result = OpenGLVGroup()\n        if hasattr(self, \"tip\"):\n            result.add(self.tip)\n        if hasattr(self, \"start_tip\"):\n            result.add(self.start_tip)\n        return result\n\n    def get_tip(self) -> OpenGLArrowTip:\n        \"\"\"Returns the TipableVMobject instance's (first) tip,\n        otherwise throws an exception.\n        \"\"\"\n        tips = self.get_tips()\n        if len(tips) == 0:\n            raise Exception(\"tip not found\")\n        else:\n            rv = cast(OpenGLArrowTip, tips[0])\n            return rv\n\n    def get_default_tip_length(self) -> float:\n        return self.tip_length\n\n    def get_first_handle(self) -> Point3D:\n        return self.points[1]\n\n    def get_last_handle(self) -> Point3D:\n        return self.points[-2]\n\n    def get_end(self) -> Point3D:\n        if self.has_tip():\n            return self.tip.get_start()\n        else:\n            return super().get_end()\n\n    def get_start(self) -> Point3D:\n        if self.has_start_tip():\n            return self.start_tip.get_start()\n        else:\n            return super().get_start()\n\n    def get_length(self) -> float:\n        start, end = self.get_start_and_end()\n        rv: float = np.linalg.norm(start - end)\n        return rv\n\n\nclass OpenGLArc(OpenGLTipableVMobject):\n    def __init__(\n        self,\n        start_angle: float = 0,\n        angle: float = TAU / 4,\n        radius: float = 1.0,\n        n_components: int = 8,\n        arc_center: Point3DLike = ORIGIN,\n        **kwargs: Any,\n    ):\n        self.start_angle = start_angle\n        self.angle = angle\n        self.radius = radius\n        self.n_components = n_components\n        self.arc_center = arc_center\n        super().__init__(**kwargs)\n        self.orientation = -1\n\n    def init_points(self) -> None:\n        self.set_points(\n            OpenGLArc.create_quadratic_bezier_points(\n                angle=self.angle,\n                start_angle=self.start_angle,\n                n_components=self.n_components,\n            ),\n        )\n        # To maintain proper orientation for fill shaders.\n        self.scale(self.radius, about_point=ORIGIN)\n        self.shift(self.arc_center)\n\n    @staticmethod\n    def create_quadratic_bezier_points(\n        angle: float, start_angle: float = 0, n_components: int = 8\n    ) -> QuadraticSpline:\n        samples = np.array(\n            [\n                [np.cos(a), np.sin(a), 0]\n                for a in np.linspace(\n                    start_angle,\n                    start_angle + angle,\n                    2 * n_components + 1,\n                )\n            ],\n        )\n        theta = angle / n_components\n        samples[1::2] /= np.cos(theta / 2)\n\n        points = np.zeros((3 * n_components, 3))\n        points[0::3] = samples[0:-1:2]\n        points[1::3] = samples[1::2]\n        points[2::3] = samples[2::2]\n        return points\n\n    def get_arc_center(self) -> Point3D:\n        \"\"\"\n        Looks at the normals to the first two\n        anchors, and finds their intersection points\n        \"\"\"\n        # First two anchors and handles\n        a1, h, a2 = self.points[:3]\n        # Tangent vectors\n        t1 = h - a1\n        t2 = h - a2\n        # Normals\n        n1 = rotate_vector(t1, TAU / 4)\n        n2 = rotate_vector(t2, TAU / 4)\n        return find_intersection(a1, n1, a2, n2)\n\n    def get_start_angle(self) -> float:\n        angle = angle_of_vector(self.get_start() - self.get_arc_center())\n        rv: float = angle % TAU\n        return rv\n\n    def get_stop_angle(self) -> float:\n        angle = angle_of_vector(self.get_end() - self.get_arc_center())\n        rv: float = angle % TAU\n        return rv\n\n    def move_arc_center_to(self, point: Point3DLike) -> Self:\n        self.shift(point - self.get_arc_center())\n        return self\n\n\nclass OpenGLArcBetweenPoints(OpenGLArc):\n    def __init__(\n        self,\n        start: Point3DLike,\n        end: Point3DLike,\n        angle: float = TAU / 4,\n        **kwargs: Any,\n    ):\n        super().__init__(angle=angle, **kwargs)\n        if angle == 0:\n            self.set_points_as_corners([LEFT, RIGHT])\n        self.put_start_and_end_on(start, end)\n\n\nclass OpenGLCurvedArrow(OpenGLArcBetweenPoints):\n    def __init__(self, start_point: Point3DLike, end_point: Point3DLike, **kwargs: Any):\n        super().__init__(start_point, end_point, **kwargs)\n        self.add_tip()\n\n\nclass OpenGLCurvedDoubleArrow(OpenGLCurvedArrow):\n    def __init__(self, start_point: Point3DLike, end_point: Point3DLike, **kwargs: Any):\n        super().__init__(start_point, end_point, **kwargs)\n        self.add_tip(at_start=True)\n\n\nclass OpenGLCircle(OpenGLArc):\n    def __init__(self, color: ParsableManimColor = RED, **kwargs: Any):\n        super().__init__(0, TAU, color=color, **kwargs)\n\n    def surround(\n        self,\n        mobject: OpenGLMobject,\n        dim_to_match: int = 0,\n        stretch: bool = False,\n        buff: float = MED_SMALL_BUFF,\n    ) -> Self:\n        # Ignores dim_to_match and stretch; result will always be a circle\n        # TODO: Perhaps create an ellipse class to handle singele-dimension stretching\n\n        self.replace(mobject, dim_to_match, stretch)\n        self.stretch((self.get_width() + 2 * buff) / self.get_width(), 0)\n        self.stretch((self.get_height() + 2 * buff) / self.get_height(), 1)\n        return self\n\n    def point_at_angle(self, angle: float) -> Point3D:\n        start_angle = self.get_start_angle()\n        return self.point_from_proportion((angle - start_angle) / TAU)\n\n\nclass OpenGLDot(OpenGLCircle):\n    def __init__(\n        self,\n        point: Point3DLike = ORIGIN,\n        radius: float = DEFAULT_DOT_RADIUS,\n        stroke_width: float = 0,\n        fill_opacity: float = 1.0,\n        color: ParsableManimColor = WHITE,\n        **kwargs: Any,\n    ):\n        super().__init__(\n            arc_center=point,\n            radius=radius,\n            stroke_width=stroke_width,\n            fill_opacity=fill_opacity,\n            color=color,\n            **kwargs,\n        )\n\n\nclass OpenGLEllipse(OpenGLCircle):\n    def __init__(self, width: float = 2, height: float = 1, **kwargs: Any):\n        super().__init__(**kwargs)\n        self.set_width(width, stretch=True)\n        self.set_height(height, stretch=True)\n\n\nclass OpenGLAnnularSector(OpenGLArc):\n    def __init__(\n        self,\n        inner_radius: float = 1,\n        outer_radius: float = 2,\n        angle: float = TAU / 4,\n        start_angle: float = 0,\n        fill_opacity: float = 1,\n        stroke_width: float = 0,\n        color: ParsableManimColor = WHITE,\n        **kwargs: Any,\n    ):\n        self.inner_radius = inner_radius\n        self.outer_radius = outer_radius\n        super().__init__(\n            start_angle=start_angle,\n            angle=angle,\n            fill_opacity=fill_opacity,\n            stroke_width=stroke_width,\n            color=color,\n            **kwargs,\n        )\n\n    def init_points(self) -> None:\n        inner_arc, outer_arc = (\n            OpenGLArc(\n                start_angle=self.start_angle,\n                angle=self.angle,\n                radius=radius,\n                arc_center=self.arc_center,\n            )\n            for radius in (self.inner_radius, self.outer_radius)\n        )\n        outer_arc.reverse_points()\n        self.append_points(inner_arc.points)\n        self.add_line_to(outer_arc.points[0])\n        self.append_points(outer_arc.points)\n        self.add_line_to(inner_arc.points[0])\n\n\nclass OpenGLSector(OpenGLAnnularSector):\n    def __init__(self, outer_radius: float = 1, inner_radius: float = 0, **kwargs: Any):\n        super().__init__(inner_radius=inner_radius, outer_radius=outer_radius, **kwargs)\n\n\nclass OpenGLAnnulus(OpenGLCircle):\n    def __init__(\n        self,\n        inner_radius: float = 1,\n        outer_radius: float = 2,\n        fill_opacity: float = 1,\n        stroke_width: float = 0,\n        color: ParsableManimColor = WHITE,\n        mark_paths_closed: bool = False,\n        **kwargs: Any,\n    ):\n        self.mark_paths_closed = mark_paths_closed  # is this even used?\n        self.inner_radius = inner_radius\n        self.outer_radius = outer_radius\n        super().__init__(\n            fill_opacity=fill_opacity, stroke_width=stroke_width, color=color, **kwargs\n        )\n\n    def init_points(self) -> None:\n        self.radius = self.outer_radius\n        outer_circle = OpenGLCircle(radius=self.outer_radius)\n        inner_circle = OpenGLCircle(radius=self.inner_radius)\n        inner_circle.reverse_points()\n        self.append_points(outer_circle.points)\n        self.append_points(inner_circle.points)\n        self.shift(self.arc_center)\n\n\nclass OpenGLLine(OpenGLTipableVMobject):\n    def __init__(\n        self,\n        start: Point3DLike = LEFT,\n        end: Point3DLike = RIGHT,\n        buff: float = 0,\n        path_arc: float = 0,\n        **kwargs: Any,\n    ):\n        self.dim = 3\n        self.buff = buff\n        self.path_arc = path_arc\n        self.set_start_and_end_attrs(start, end)\n        super().__init__(**kwargs)\n\n    def init_points(self) -> None:\n        self.set_points_by_ends(self.start, self.end, self.buff, self.path_arc)\n\n    def set_points_by_ends(\n        self, start: Point3DLike, end: Point3DLike, buff: float = 0, path_arc: float = 0\n    ) -> None:\n        if path_arc:\n            self.set_points(OpenGLArc.create_quadratic_bezier_points(path_arc))\n            self.put_start_and_end_on(start, end)\n        else:\n            self.set_points_as_corners([start, end])\n        self.account_for_buff(self.buff)\n\n    def set_path_arc(self, new_value: float) -> None:\n        self.path_arc = new_value\n        self.init_points()\n\n    def account_for_buff(self, buff: float) -> Self:\n        if buff == 0:\n            return self\n        #\n        length = self.get_length() if self.path_arc == 0 else self.get_arc_length()\n        #\n        if length < 2 * buff:\n            return self\n        buff_prop = buff / length\n        self.pointwise_become_partial(self, buff_prop, 1 - buff_prop)\n        return self\n\n    def set_start_and_end_attrs(\n        self, start: Mobject | Point3DLike, end: Mobject | Point3DLike\n    ) -> None:\n        # If either start or end are Mobjects, this\n        # gives their centers\n        rough_start = self.pointify(start)\n        rough_end = self.pointify(end)\n        vect = normalize(rough_end - rough_start)\n        # Now that we know the direction between them,\n        # we can find the appropriate boundary point from\n        # start and end, if they're mobjects\n        self.start = self.pointify(start, vect) + self.buff * vect\n        self.end = self.pointify(end, -vect) - self.buff * vect\n\n    def pointify(\n        self, mob_or_point: Mobject | Point3DLike, direction: Vector3DLike = None\n    ) -> Point3D:\n        \"\"\"\n        Take an argument passed into Line (or subclass) and turn\n        it into a 3d point.\n        \"\"\"\n        if isinstance(mob_or_point, Mobject):\n            mob = mob_or_point\n            if direction is None:\n                return mob.get_center()\n            else:\n                return mob.get_continuous_bounding_box_point(direction)\n        else:\n            point = mob_or_point\n            result = np.zeros(self.dim)\n            result[: len(point)] = point\n            return result\n\n    def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self:\n        curr_start, curr_end = self.get_start_and_end()\n        if (curr_start == curr_end).all():\n            self.set_points_by_ends(start, end, self.path_arc)\n        return super().put_start_and_end_on(start, end)\n\n    def get_vector(self) -> Vector3D:\n        return self.get_end() - self.get_start()\n\n    def get_unit_vector(self) -> Vector3D:\n        return normalize(self.get_vector())\n\n    def get_angle(self) -> float:\n        return angle_of_vector(self.get_vector())\n\n    def get_projection(self, point: Point3DLike) -> Point3D:\n        \"\"\"Return projection of a point onto the line\"\"\"\n        unit_vect = self.get_unit_vector()\n        start = self.get_start()\n        return start + np.dot(point - start, unit_vect) * unit_vect\n\n    def get_slope(self) -> float:\n        rv: float = np.tan(self.get_angle())\n        return rv\n\n    def set_angle(self, angle: float, about_point: Point3DLike | None = None) -> Self:\n        if about_point is None:\n            about_point = self.get_start()\n        self.rotate(\n            angle - self.get_angle(),\n            about_point=about_point,\n        )\n        return self\n\n    def set_length(self, length: float) -> None:\n        self.scale(length / self.get_length())\n\n\nclass OpenGLDashedLine(OpenGLLine):\n    def __init__(\n        self,\n        *args: Any,\n        dash_length: float = DEFAULT_DASH_LENGTH,\n        dashed_ratio: float = 0.5,\n        **kwargs: Any,\n    ):\n        self.dashed_ratio = dashed_ratio\n        self.dash_length = dash_length\n        super().__init__(*args, **kwargs)\n        dashed_ratio = self.dashed_ratio\n        num_dashes = self.calculate_num_dashes(dashed_ratio)\n        dashes = OpenGLDashedVMobject(\n            self,\n            num_dashes=num_dashes,\n            dashed_ratio=dashed_ratio,\n        )\n        self.clear_points()\n        self.add(*dashes)\n\n    def calculate_num_dashes(self, dashed_ratio: float) -> int:\n        return max(\n            2,\n            int(np.ceil((self.get_length() / self.dash_length) * dashed_ratio)),\n        )\n\n    def get_start(self) -> Point3D:\n        if len(self.submobjects) > 0:\n            return self.submobjects[0].get_start()\n        else:\n            return super().get_start()\n\n    def get_end(self) -> Point3D:\n        if len(self.submobjects) > 0:\n            return self.submobjects[-1].get_end()\n        else:\n            return super().get_end()\n\n    def get_first_handle(self) -> Point3D:\n        return self.submobjects[0].points[1]\n\n    def get_last_handle(self) -> Point3D:\n        return self.submobjects[-1].points[-2]\n\n\nclass OpenGLTangentLine(OpenGLLine):\n    def __init__(\n        self,\n        vmob: OpenGLVMobject,\n        alpha: float,\n        length: float = 1,\n        d_alpha: float = 1e-6,\n        **kwargs: Any,\n    ):\n        self.length = length\n        self.d_alpha = d_alpha\n        da = self.d_alpha\n        a1 = clip(alpha - da, 0, 1)\n        a2 = clip(alpha + da, 0, 1)\n        super().__init__(vmob.pfp(a1), vmob.pfp(a2), **kwargs)\n        self.scale(self.length / self.get_length())\n\n\nclass OpenGLElbow(OpenGLVMobject):\n    def __init__(self, width: float = 0.2, angle: float = 0, **kwargs: Any):\n        self.angle = angle\n        super().__init__(self, **kwargs)\n        self.set_points_as_corners([UP, UP + RIGHT, RIGHT])\n        self.set_width(width, about_point=ORIGIN)\n        self.rotate(self.angle, about_point=ORIGIN)\n\n\nclass OpenGLArrow(OpenGLLine):\n    def __init__(\n        self,\n        start: Point3DLike = LEFT,\n        end: Point3DLike = RIGHT,\n        path_arc: float = 0,\n        fill_color: ParsableManimColor = GREY_A,\n        fill_opacity: float = 1,\n        stroke_width: float = 0,\n        buff: float = MED_SMALL_BUFF,\n        thickness: float = 0.05,\n        tip_width_ratio: float = 5,\n        tip_angle: float = PI / 3,\n        max_tip_length_to_length_ratio: float = 0.5,\n        max_width_to_length_ratio: float = 0.1,\n        **kwargs: Any,\n    ):\n        self.thickness = thickness\n        self.tip_width_ratio = tip_width_ratio\n        self.tip_angle = tip_angle\n        self.max_tip_length_to_length_ratio = max_tip_length_to_length_ratio\n        self.max_width_to_length_ratio = max_width_to_length_ratio\n        super().__init__(\n            start=start,\n            end=end,\n            buff=buff,\n            path_arc=path_arc,\n            fill_color=fill_color,\n            fill_opacity=fill_opacity,\n            stroke_width=stroke_width,\n            **kwargs,\n        )\n\n    def set_points_by_ends(\n        self, start: Point3DLike, end: Point3DLike, buff: float = 0, path_arc: float = 0\n    ) -> None:\n        # Find the right tip length and thickness\n        vect = np.asarray(end) - np.asarray(start)\n        length = max(np.linalg.norm(vect), 1e-8)\n        thickness = self.thickness\n        w_ratio = self.max_width_to_length_ratio / (thickness / length)\n        if w_ratio < 1:\n            thickness *= w_ratio\n\n        tip_width = self.tip_width_ratio * thickness\n        tip_length = tip_width / (2 * np.tan(self.tip_angle / 2))\n        t_ratio = self.max_tip_length_to_length_ratio / (tip_length / length)\n        if t_ratio < 1:\n            tip_length *= t_ratio\n            tip_width *= t_ratio\n\n        # Find points for the stem\n        if path_arc == 0:\n            points1 = (length - tip_length) * np.array([RIGHT, 0.5 * RIGHT, ORIGIN])\n            points1 += thickness * UP / 2\n            points2 = points1[::-1] + thickness * DOWN\n        else:\n            # Solve for radius so that the tip-to-tail length matches |end - start|\n            a = 2 * (1 - np.cos(path_arc))\n            b = -2 * tip_length * np.sin(path_arc)\n            c = tip_length**2 - length**2\n            R = (-b + np.sqrt(b**2 - 4 * a * c)) / (2 * a)\n\n            # Find arc points\n            points1 = OpenGLArc.create_quadratic_bezier_points(path_arc)\n            points2 = np.array(points1[::-1])\n            points1 *= R + thickness / 2\n            points2 *= R - thickness / 2\n            if path_arc < 0:\n                tip_length *= -1\n            rot_T = rotation_matrix_transpose(PI / 2 - path_arc, OUT)\n            for points in points1, points2:\n                points[:] = np.dot(points, rot_T)\n                points += R * DOWN\n\n        self.set_points(points1)\n        # Tip\n        self.add_line_to(tip_width * UP / 2)\n        self.add_line_to(tip_length * LEFT)\n        self.tip_index = len(self.points) - 1\n        self.add_line_to(tip_width * DOWN / 2)\n        self.add_line_to(points2[0])\n        # Close it out\n        self.append_points(points2)\n        self.add_line_to(points1[0])\n\n        if length > 0:\n            # Final correction\n            super().scale(length / self.get_length())\n\n        self.rotate(angle_of_vector(vect) - self.get_angle())\n        self.rotate(\n            PI / 2 - np.arccos(normalize(vect)[2]),\n            axis=rotate_vector(self.get_unit_vector(), -PI / 2),\n        )\n        self.shift(start - self.get_start())\n        self.refresh_triangulation()\n\n    def reset_points_around_ends(self) -> Self:\n        self.set_points_by_ends(\n            self.get_start(),\n            self.get_end(),\n            path_arc=self.path_arc,\n        )\n        return self\n\n    def get_start(self) -> Point3D:\n        nppc = self.n_points_per_curve\n        points = self.points\n        return (points[0] + points[-nppc]) / 2\n\n    def get_end(self) -> Point3D:\n        return self.points[self.tip_index]\n\n    def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self:\n        self.set_points_by_ends(start, end, buff=0, path_arc=self.path_arc)\n        return self\n\n    def scale(self, *args: Any, **kwargs: Any) -> Self:\n        super().scale(*args, **kwargs)\n        self.reset_points_around_ends()\n        return self\n\n    def set_thickness(self, thickness: float) -> Self:\n        self.thickness = thickness\n        self.reset_points_around_ends()\n        return self\n\n    def set_path_arc(self, path_arc: float) -> None:\n        self.path_arc = path_arc\n        self.reset_points_around_ends()\n        # return self\n\n\nclass OpenGLVector(OpenGLArrow):\n    def __init__(\n        self,\n        direction: Vector2DLike | Vector3DLike = RIGHT,\n        buff: float = 0,\n        **kwargs: Any,\n    ):\n        self.buff = buff\n        if len(direction) == 2:\n            direction = np.hstack([direction, 0])\n        super().__init__(ORIGIN, direction, buff=buff, **kwargs)\n\n\nclass OpenGLDoubleArrow(OpenGLArrow):\n    def __init__(self, *args: Any, **kwargs: Any):\n        super().__init__(*args, **kwargs)\n        self.add_tip(at_start=True)\n\n\nclass OpenGLCubicBezier(OpenGLVMobject):\n    def __init__(\n        self,\n        a0: Point3DLike,\n        h0: Point3DLike,\n        h1: Point3DLike,\n        a1: Point3DLike,\n        **kwargs: Any,\n    ):\n        super().__init__(**kwargs)\n        self.add_cubic_bezier_curve(a0, h0, h1, a1)\n\n\nclass OpenGLPolygon(OpenGLVMobject):\n    def __init__(self, *vertices: Point3DLike, **kwargs: Any):\n        self.vertices: Point3D_Array = np.array(vertices)\n        super().__init__(**kwargs)\n\n    def init_points(self) -> None:\n        verts = self.vertices\n        self.set_points_as_corners([*verts, verts[0]])\n\n    def get_vertices(self) -> Point3D_Array:\n        return self.get_start_anchors()\n\n    def round_corners(self, radius: float = 0.5) -> Self:\n        vertices = self.get_vertices()\n        arcs = []\n        for v1, v2, v3 in adjacent_n_tuples(vertices, 3):\n            vect1 = v2 - v1\n            vect2 = v3 - v2\n            unit_vect1 = normalize(vect1)\n            unit_vect2 = normalize(vect2)\n            angle = angle_between_vectors(vect1, vect2)\n            # Negative radius gives concave curves\n            angle *= np.sign(radius)\n            # Distance between vertex and start of the arc\n            cut_off_length = radius * np.tan(angle / 2)\n            # Determines counterclockwise vs. clockwise\n            sign = np.sign(np.cross(vect1, vect2)[2])\n            arc = OpenGLArcBetweenPoints(\n                v2 - unit_vect1 * cut_off_length,\n                v2 + unit_vect2 * cut_off_length,\n                angle=sign * angle,\n                n_components=2,\n            )\n            arcs.append(arc)\n\n        self.clear_points()\n        # To ensure that we loop through starting with last\n        arcs = [arcs[-1], *arcs[:-1]]\n        for arc1, arc2 in adjacent_pairs(arcs):\n            self.append_points(arc1.points)\n            line = OpenGLLine(arc1.get_end(), arc2.get_start())\n            # Make sure anchors are evenly distributed\n            len_ratio = line.get_length() / arc1.get_arc_length()\n            line.insert_n_curves(int(arc1.get_num_curves() * len_ratio))\n            self.append_points(line.points)\n        return self\n\n\nclass OpenGLRegularPolygon(OpenGLPolygon):\n    def __init__(self, n: int = 6, start_angle: float | None = None, **kwargs: Any):\n        self.start_angle = start_angle\n        if self.start_angle is None:\n            if n % 2 == 0:\n                self.start_angle = 0\n            else:\n                self.start_angle = 90 * DEGREES\n        start_vect = rotate_vector(RIGHT, self.start_angle)\n        vertices = compass_directions(n, start_vect)\n        super().__init__(*vertices, **kwargs)\n\n\nclass OpenGLTriangle(OpenGLRegularPolygon):\n    def __init__(self, **kwargs: Any):\n        super().__init__(n=3, **kwargs)\n\n\nclass OpenGLArrowTip(OpenGLTriangle):\n    def __init__(\n        self,\n        fill_opacity: float = 1,\n        fill_color: ParsableManimColor = WHITE,\n        stroke_width: float = 0,\n        width: float = DEFAULT_ARROW_TIP_WIDTH,\n        length: float = DEFAULT_ARROW_TIP_LENGTH,\n        angle: float = 0,\n        **kwargs: Any,\n    ):\n        super().__init__(\n            start_angle=0,\n            fill_opacity=fill_opacity,\n            fill_color=fill_color,\n            stroke_width=stroke_width,\n            **kwargs,\n        )\n        self.set_width(width, stretch=True)\n        self.set_height(length, stretch=True)\n\n    def get_base(self) -> Point3D:\n        return self.point_from_proportion(0.5)\n\n    def get_tip_point(self) -> Point3D:\n        return self.points[0]\n\n    def get_vector(self) -> Vector3D:\n        return self.get_tip_point() - self.get_base()\n\n    def get_angle(self) -> float:\n        return angle_of_vector(self.get_vector())\n\n    def get_length(self) -> float:\n        rv: float = np.linalg.norm(self.get_vector())\n        return rv\n\n\nclass OpenGLRectangle(OpenGLPolygon):\n    def __init__(\n        self,\n        color: ParsableManimColor = WHITE,\n        width: float = 4.0,\n        height: float = 2.0,\n        **kwargs: Any,\n    ):\n        super().__init__(UR, UL, DL, DR, color=color, **kwargs)\n\n        self.set_width(width, stretch=True)\n        self.set_height(height, stretch=True)\n\n\nclass OpenGLSquare(OpenGLRectangle):\n    def __init__(self, side_length: float = 2.0, **kwargs: Any):\n        self.side_length = side_length\n\n        super().__init__(height=side_length, width=side_length, **kwargs)\n\n\nclass OpenGLRoundedRectangle(OpenGLRectangle):\n    def __init__(self, corner_radius: float = 0.5, **kwargs: Any):\n        self.corner_radius = corner_radius\n        super().__init__(**kwargs)\n        self.round_corners(self.corner_radius)\n"
  },
  {
    "path": "manim/mobject/opengl/opengl_image_mobject.py",
    "content": "from __future__ import annotations\n\n__all__ = [\n    \"OpenGLImageMobject\",\n]\n\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\nfrom PIL import Image\nfrom PIL.Image import Resampling\n\nfrom manim.mobject.opengl.opengl_surface import OpenGLSurface, OpenGLTexturedSurface\nfrom manim.utils.images import get_full_raster_image_path\n\nif TYPE_CHECKING:\n    import numpy.typing as npt\n\n__all__ = [\"OpenGLImageMobject\"]\n\n\nclass OpenGLImageMobject(OpenGLTexturedSurface):\n    def __init__(\n        self,\n        filename_or_array: str | Path | npt.NDArray,\n        width: float | None = None,\n        height: float | None = None,\n        image_mode: str = \"RGBA\",\n        resampling_algorithm: Resampling = Resampling.BICUBIC,\n        opacity: float = 1,\n        gloss: float = 0,\n        shadow: float = 0,\n        **kwargs: Any,\n    ):\n        self.image = filename_or_array\n        self.resampling_algorithm = resampling_algorithm\n        if isinstance(filename_or_array, np.ndarray):\n            self.size = filename_or_array.shape[1::-1]\n        elif isinstance(filename_or_array, (str, Path)):\n            path = get_full_raster_image_path(filename_or_array)\n            self.size = Image.open(path).size\n\n        if width is None and height is None:\n            width = 4 * self.size[0] / self.size[1]\n            height = 4\n        if height is None:\n            height = width * self.size[1] / self.size[0]\n        if width is None:\n            width = height * self.size[0] / self.size[1]\n\n        surface = OpenGLSurface(\n            lambda u, v: np.array([u, v, 0]),\n            [-width / 2, width / 2],\n            [-height / 2, height / 2],\n            opacity=opacity,\n            gloss=gloss,\n            shadow=shadow,\n        )\n\n        super().__init__(\n            surface,\n            self.image,\n            image_mode=image_mode,\n            opacity=opacity,\n            gloss=gloss,\n            shadow=shadow,\n            **kwargs,\n        )\n\n    def get_image_from_file(\n        self,\n        image_file: str | Path | np.ndarray,\n        image_mode: str,\n    ) -> Image.Image:\n        if isinstance(image_file, (str, Path)):\n            return super().get_image_from_file(image_file, image_mode)\n        else:\n            return (\n                Image.fromarray(image_file.astype(\"uint8\"))\n                .convert(image_mode)\n                .resize(\n                    image_file.shape[:2]\n                    * 200,  # assumption of 200 ppmu (pixels per manim unit) would suffice\n                    resample=self.resampling_algorithm,\n                )\n            )\n"
  },
  {
    "path": "manim/mobject/opengl/opengl_mobject.py",
    "content": "from __future__ import annotations\n\nimport copy\nimport inspect\nimport itertools as it\nimport random\nimport sys\nimport types\nfrom collections.abc import Callable, Iterable, Iterator, Sequence\nfrom functools import partialmethod, wraps\nfrom math import ceil\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    ClassVar,\n    Never,\n    Protocol,\n    Self,\n    TypeAlias,\n    TypeVar,\n    cast,\n    overload,\n)\n\nimport moderngl\nimport numpy as np\nimport numpy.typing as npt\nfrom typing_extensions import (\n    override,\n)\n\nfrom manim import config, logger\nfrom manim.constants import *\nfrom manim.data_structures import MethodWithArgs\nfrom manim.renderer.shader_wrapper import get_colormap_code\nfrom manim.typing import (\n    Point3D,\n    Point3D_Array,\n    Point3DLike,\n    Point3DLike_Array,\n)\nfrom manim.utils.bezier import integer_interpolate, interpolate\nfrom manim.utils.color import (\n    WHITE,\n    ManimColor,\n    ParsableManimColor,\n    color_gradient,\n    color_to_rgb,\n    rgb_to_hex,\n)\nfrom manim.utils.config_ops import _Data, _Uniforms\n\n# from ..utils.iterables import batch_by_property\nfrom manim.utils.iterables import (\n    batch_by_property,\n    list_update,\n    listify,\n    make_even,\n    resize_array,\n    resize_preserving_order,\n    resize_with_interpolation,\n    uniq_chain,\n)\nfrom manim.utils.paths import straight_path\nfrom manim.utils.space_ops import (\n    angle_between_vectors,\n    normalize,\n    rotation_matrix_transpose,\n)\n\nif TYPE_CHECKING:\n    from manim.animation.animation import Animation\n    from manim.renderer.shader_wrapper import ShaderWrapper\n    from manim.typing import (\n        FloatRGB_Array,\n        FloatRGBA_Array,\n        ManimFloat,\n        MappingFunction,\n        MatrixMN,\n        MultiMappingFunction,\n        PathFuncType,\n        Vector3D,\n        Vector3DLike,\n    )\n\n    _TimeBasedUpdater: TypeAlias = Callable[[\"OpenGLMobject\", float], object]\n    _NonTimeBasedUpdater: TypeAlias = Callable[[\"OpenGLMobject\"], object]\n    _Updater: TypeAlias = _NonTimeBasedUpdater | _TimeBasedUpdater\n\n    _T = TypeVar(\"_T\")\n    _T_np = TypeVar(\"_T_np\", bound=np.generic)\n\n\ndef affects_shader_info_id(\n    func: Callable[[OpenGLMobject], OpenGLMobject],\n) -> Callable[[OpenGLMobject], OpenGLMobject]:\n    @wraps(func)\n    def wrapper(self: OpenGLMobject) -> OpenGLMobject:\n        for mob in self.get_family():\n            func(mob)\n            mob.refresh_shader_wrapper_id()\n        return self\n\n    return wrapper\n\n\n__all__ = [\"OpenGLMobject\", \"OpenGLGroup\", \"OpenGLPoint\", \"_AnimationBuilder\"]\n\n\n_ShaderDType: TypeAlias = np.void\n\"\"\"The dtype for NumPy arrays representing shader data. It's a structured dtype with signature `(point, np.float32, (3,))`.\"\"\"\n_ShaderData: TypeAlias = npt.NDArray[_ShaderDType]\n\n\nclass OpenGLMobject:\n    \"\"\"Mathematical Object: base class for objects that can be displayed on screen.\n\n    Attributes\n    ----------\n    submobjects : List[:class:`OpenGLMobject`]\n        The contained objects.\n    points : :class:`numpy.ndarray`\n        The points of the objects.\n\n        .. seealso::\n\n            :class:`~.OpenGLVMobject`\n\n    \"\"\"\n\n    _original__init__: ClassVar[Callable[..., None]]\n\n    shader_dtype: ClassVar[Sequence[tuple[str, type[np.generic], tuple[int, ...]]]] = [\n        (\"point\", np.float32, (3,)),\n    ]\n    shader_folder: ClassVar[str] = \"\"\n\n    # _Data and _Uniforms are set as class variables to tell manim how to handle setting/getting these attributes later.\n    points: _Data[Point3D_Array] = _Data()\n    bounding_box: _Data[Point3D_Array] = _Data()\n    rgbas: _Data[FloatRGBA_Array] = _Data()\n\n    is_fixed_in_frame: _Uniforms = _Uniforms()\n    is_fixed_orientation: _Uniforms = _Uniforms()\n    fixed_orientation_center: _Uniforms[tuple[float, float, float]] = (\n        _Uniforms()\n    )  # for fixed orientation reference\n    gloss: _Uniforms = _Uniforms()\n    shadow: _Uniforms = _Uniforms()\n\n    def __init__(\n        self,\n        color: ParsableManimColor | Sequence[ParsableManimColor] = WHITE,\n        opacity: float = 1,\n        dim: int = 3,  # TODO, get rid of this\n        # Lighting parameters\n        # Positive gloss up to 1 makes it reflect the light.\n        gloss: float = 0.0,\n        # Positive shadow up to 1 makes a side opposite the light darker\n        shadow: float = 0.0,\n        # For shaders\n        render_primitive: int = moderngl.TRIANGLES,\n        texture_paths: dict[str, str] | None = None,\n        depth_test: bool = False,\n        # If true, the mobject will not get rotated according to camera position\n        is_fixed_in_frame: bool = False,\n        is_fixed_orientation: bool = False,\n        # Must match in attributes of vert shader\n        # Event listener\n        listen_to_events: bool = False,\n        model_matrix: MatrixMN | None = None,\n        should_render: bool = True,\n        name: str | None = None,\n        **kwargs: Any,\n    ):\n        self.name: str = self.__class__.__name__ if name is None else name\n        # getattr in case data/uniforms are already defined in parent classes.\n        self.data: dict[str, npt.NDArray[Any]] = getattr(self, \"data\", {})\n        self.uniforms: dict[str, float | tuple[float, ...]] = getattr(\n            self, \"uniforms\", {}\n        )\n\n        self.opacity: float | Iterable[float] = opacity\n        self.dim: int = dim  # TODO, get rid of this\n        # Lighting parameters\n        # Positive gloss up to 1 makes it reflect the light.\n        self.gloss = gloss\n        # Positive shadow up to 1 makes a side opposite the light darker\n        self.shadow = shadow\n        # For shaders\n        self.render_primitive: int = render_primitive\n        self.texture_paths: dict[str, str] | None = texture_paths\n        self.depth_test: bool = depth_test\n        # If true, the mobject will not get rotated according to camera position\n        self.is_fixed_in_frame = float(is_fixed_in_frame)\n        self.is_fixed_orientation = float(is_fixed_orientation)\n        self.fixed_orientation_center = (0, 0, 0)\n        # Must match in attributes of vert shader\n        # Event listener\n        self.listen_to_events: bool = listen_to_events\n\n        self._submobjects: list[OpenGLMobject] = []\n        self.parents: list[OpenGLMobject] = []\n        self.parent: OpenGLMobject | None = None\n        self.family: list[OpenGLMobject] = [self]\n        self.locked_data_keys: set[str] = set()\n        self.needs_new_bounding_box: bool = True\n        if model_matrix is None:\n            self.model_matrix: MatrixMN = np.eye(4)\n        else:\n            self.model_matrix = model_matrix\n\n        self.init_data()\n        self.init_updaters()\n        # self.init_event_listners()\n        self.init_points()\n        self.color: ManimColor | list[ManimColor] = ManimColor.parse(color)\n        self.init_colors()\n\n        self.shader_indices: Sequence[int] | None = None\n\n        if self.depth_test:\n            self.apply_depth_test()\n\n        self.should_render: bool = should_render\n\n    def _assert_valid_submobjects(self, submobjects: Iterable[OpenGLMobject]) -> Self:\n        \"\"\"Check that all submobjects are actually instances of\n        :class:`OpenGLMobject`, and that none of them is\n        ``self`` (an :class:`OpenGLMobject` cannot contain itself).\n\n        This is an auxiliary function called when adding OpenGLMobjects to the\n        :attr:`submobjects` list.\n\n        This function is intended to be overridden by subclasses such as\n        :class:`OpenGLVMobject`, which should assert that only other\n        OpenGLVMobjects may be added into it.\n\n        Parameters\n        ----------\n        submobjects\n            The list containing values to validate.\n\n        Returns\n        -------\n        :class:`OpenGLMobject`\n            The OpenGLMobject itself.\n\n        Raises\n        ------\n        TypeError\n            If any of the values in `submobjects` is not an\n            :class:`OpenGLMobject`.\n        ValueError\n            If there was an attempt to add an :class:`OpenGLMobject` as its own\n            submobject.\n        \"\"\"\n        return self._assert_valid_submobjects_internal(submobjects, OpenGLMobject)\n\n    def _assert_valid_submobjects_internal(\n        self, submobjects: Iterable[OpenGLMobject], mob_class: type[OpenGLMobject]\n    ) -> Self:\n        for i, submob in enumerate(submobjects):\n            if not isinstance(submob, mob_class):\n                error_message = (\n                    f\"Only values of type {mob_class.__name__} can be added \"\n                    f\"as submobjects of {type(self).__name__}, but the value \"\n                    f\"{submob} (at index {i}) is of type \"\n                    f\"{type(submob).__name__}.\"\n                )\n                # Intended for subclasses such as OpenGLVMobject, which\n                # cannot have regular OpenGLMobjects as submobjects\n                if isinstance(submob, OpenGLMobject):\n                    error_message += (\n                        \" You can try adding this value into a Group instead.\"\n                    )\n                raise TypeError(error_message)\n            if submob is self:\n                raise ValueError(\n                    f\"Cannot add {type(self).__name__} as a submobject of \"\n                    f\"itself (at index {i}).\"\n                )\n        return self\n\n    @classmethod\n    def __init_subclass__(cls, **kwargs: Any) -> None:\n        super().__init_subclass__(**kwargs)\n        cls._original__init__ = cls.__init__\n\n    @override\n    def __str__(self) -> str:\n        return self.__class__.__name__\n\n    @override\n    def __repr__(self) -> str:\n        return str(self.name)\n\n    def __sub__(self, other: Never) -> object:\n        return NotImplemented\n\n    def __isub__(self, other: Never) -> object:\n        return NotImplemented\n\n    def __add__(self, mobject: Never) -> object:\n        return NotImplemented\n\n    def __iadd__(self, mobject: Never) -> object:\n        return NotImplemented\n\n    @classmethod\n    def set_default(cls, **kwargs: Any) -> None:\n        \"\"\"Sets the default values of keyword arguments.\n\n        If this method is called without any additional keyword\n        arguments, the original default values of the initialization\n        method of this class are restored.\n\n        Parameters\n        ----------\n\n        kwargs\n            Passing any keyword argument will update the default\n            values of the keyword arguments of the initialization\n            function of this class.\n\n        Examples\n        --------\n\n        ::\n\n            >>> from manim import Square, GREEN\n            >>> Square.set_default(color=GREEN, fill_opacity=0.25)\n            >>> s = Square(); s.color, s.fill_opacity\n            (ManimColor('#83C167'), 0.25)\n            >>> Square.set_default()\n            >>> s = Square(); s.color, s.fill_opacity\n            (ManimColor('#FFFFFF'), 0.0)\n\n        .. manim:: ChangedDefaultTextcolor\n            :save_last_frame:\n\n            config.background_color = WHITE\n\n            class ChangedDefaultTextcolor(Scene):\n                def construct(self):\n                    Text.set_default(color=BLACK)\n                    self.add(Text(\"Changing default values is easy!\"))\n\n                    # we revert the colour back to the default to prevent a bug in the docs.\n                    Text.set_default(color=WHITE)\n\n        \"\"\"\n        if kwargs:\n            # Apparently mypy does not correctly understand `partialmethod`:\n            #   see https://github.com/python/mypy/issues/8619\n            cls.__init__ = partialmethod(cls.__init__, **kwargs)  # type: ignore[assignment]\n        else:\n            cls.__init__ = cls._original__init__\n\n    def init_data(self) -> None:\n        \"\"\"Initializes the ``points``, ``bounding_box`` and ``rgbas`` attributes and groups them into self.data.\n        Subclasses can inherit and overwrite this method to extend `self.data`.\n        \"\"\"\n        self.points = np.zeros((0, 3))\n        self.bounding_box = np.zeros((3, 3))\n        self.rgbas = np.zeros((1, 4))\n\n    def init_colors(self) -> None:\n        \"\"\"Initializes the colors.\n\n        Gets called upon creation\n        \"\"\"\n        self.set_color(self.color, self.opacity)\n\n    def init_points(self) -> None:\n        \"\"\"Initializes :attr:`points` and therefore the shape.\n\n        Gets called upon creation. This is an empty method that can be implemented by\n        subclasses.\n        \"\"\"\n        # Typically implemented in subclass, unless purposefully left blank\n        pass\n\n    def set(self, **kwargs: object) -> Self:\n        \"\"\"Sets attributes.\n\n        Mainly to be used along with :attr:`animate` to\n        animate setting attributes.\n\n        Examples\n        --------\n        ::\n\n            >>> mob = OpenGLMobject()\n            >>> mob.set(foo=0)\n            OpenGLMobject\n            >>> mob.foo\n            0\n\n        Parameters\n        ----------\n        **kwargs\n            The attributes and corresponding values to set.\n\n        Returns\n        -------\n        :class:`OpenGLMobject`\n            ``self``\n\n\n        \"\"\"\n        for attr, value in kwargs.items():\n            setattr(self, attr, value)\n\n        return self\n\n    def set_data(self, data: dict[str, Any]) -> Self:\n        for key in data:\n            self.data[key] = data[key].copy()\n        return self\n\n    def set_uniforms(self, uniforms: dict[str, Any]) -> Self:\n        for key in uniforms:\n            self.uniforms[key] = uniforms[key]  # Copy?\n        return self\n\n    @property\n    def animate(self) -> _AnimationBuilder | Self:\n        \"\"\"Used to animate the application of a method.\n\n        .. warning::\n\n            Passing multiple animations for the same :class:`OpenGLMobject` in one\n            call to :meth:`~.Scene.play` is discouraged and will most likely\n            not work properly. Instead of writing an animation like\n\n            ::\n\n                self.play(\n                    my_mobject.animate.shift(RIGHT), my_mobject.animate.rotate(PI)\n                )\n\n            make use of method chaining for ``animate``, meaning::\n\n                self.play(my_mobject.animate.shift(RIGHT).rotate(PI))\n\n        Keyword arguments that can be passed to :meth:`.Scene.play` can be passed\n        directly after accessing ``.animate``, like so::\n\n            self.play(my_mobject.animate(rate_func=linear).shift(RIGHT))\n\n        This is especially useful when animating simultaneous ``.animate`` calls that\n        you want to behave differently::\n\n            self.play(\n                mobject1.animate(run_time=2).rotate(PI),\n                mobject2.animate(rate_func=there_and_back).shift(RIGHT),\n            )\n\n        .. seealso::\n\n            :func:`override_animate`\n\n\n        Examples\n        --------\n\n        .. manim:: AnimateExample\n\n            class AnimateExample(Scene):\n                def construct(self):\n                    s = Square()\n                    self.play(Create(s))\n                    self.play(s.animate.shift(RIGHT))\n                    self.play(s.animate.scale(2))\n                    self.play(s.animate.rotate(PI / 2))\n                    self.play(Uncreate(s))\n\n\n        .. manim:: AnimateChainExample\n\n            class AnimateChainExample(Scene):\n                def construct(self):\n                    s = Square()\n                    self.play(Create(s))\n                    self.play(s.animate.shift(RIGHT).scale(2).rotate(PI / 2))\n                    self.play(Uncreate(s))\n\n        .. manim:: AnimateWithArgsExample\n\n            class AnimateWithArgsExample(Scene):\n                def construct(self):\n                    s = Square()\n                    c = Circle()\n\n                    VGroup(s, c).arrange(RIGHT, buff=2)\n                    self.add(s, c)\n\n                    self.play(\n                        s.animate(run_time=2).rotate(PI / 2),\n                        c.animate(rate_func=there_and_back).shift(RIGHT),\n                    )\n\n        .. warning::\n\n            ``.animate``\n             will interpolate the :class:`~.OpenGLMobject` between its points prior to\n             ``.animate`` and its points after applying ``.animate`` to it. This may\n             result in unexpected behavior when attempting to interpolate along paths,\n             or rotations.\n             If you want animations to consider the points between, consider using\n             :class:`~.ValueTracker` with updaters instead.\n\n        \"\"\"\n        return _AnimationBuilder(self)\n\n    @property\n    def width(self) -> float:\n        \"\"\"The width of the mobject.\n\n        Returns\n        -------\n        :class:`float`\n\n        Examples\n        --------\n        .. manim:: WidthExample\n\n            class WidthExample(Scene):\n                def construct(self):\n                    decimal = DecimalNumber().to_edge(UP)\n                    rect = Rectangle(color=BLUE)\n                    rect_copy = rect.copy().set_stroke(GRAY, opacity=0.5)\n\n                    decimal.add_updater(lambda d: d.set_value(rect.width))\n\n                    self.add(rect_copy, rect, decimal)\n                    self.play(rect.animate.set(width=7))\n                    self.wait()\n\n        See also\n        --------\n        :meth:`length_over_dim`\n\n        \"\"\"\n        # Get the length across the X dimension\n        return self.length_over_dim(0)\n\n    # Only these methods should directly affect points\n    @width.setter\n    def width(self, value: float) -> None:\n        self.rescale_to_fit(value, 0, stretch=False)\n\n    @property\n    def height(self) -> float:\n        \"\"\"The height of the mobject.\n\n        Returns\n        -------\n        :class:`float`\n\n        Examples\n        --------\n        .. manim:: HeightExample\n\n            class HeightExample(Scene):\n                def construct(self):\n                    decimal = DecimalNumber().to_edge(UP)\n                    rect = Rectangle(color=BLUE)\n                    rect_copy = rect.copy().set_stroke(GRAY, opacity=0.5)\n\n                    decimal.add_updater(lambda d: d.set_value(rect.height))\n\n                    self.add(rect_copy, rect, decimal)\n                    self.play(rect.animate.set(height=5))\n                    self.wait()\n\n        See also\n        --------\n        :meth:`length_over_dim`\n\n        \"\"\"\n        # Get the length across the Y dimension\n        return self.length_over_dim(1)\n\n    @height.setter\n    def height(self, value: float) -> None:\n        self.rescale_to_fit(value, 1, stretch=False)\n\n    @property\n    def depth(self) -> float:\n        \"\"\"The depth of the mobject.\n\n        Returns\n        -------\n        :class:`float`\n\n        See also\n        --------\n        :meth:`length_over_dim`\n\n        \"\"\"\n        # Get the length across the Z dimension\n        return self.length_over_dim(2)\n\n    @depth.setter\n    def depth(self, value: float) -> None:\n        self.rescale_to_fit(value, 2, stretch=False)\n\n    def resize_points(\n        self,\n        new_length: int,\n        resize_func: Callable[[Point3D_Array, int], Point3D_Array] = resize_array,\n    ) -> Self:\n        if new_length != len(self.points):\n            self.points = resize_func(self.points, new_length)\n        self.refresh_bounding_box()\n        return self\n\n    def set_points(self, points: Point3DLike_Array) -> Self:\n        if len(points) == len(self.points):\n            self.points[:] = points\n        elif isinstance(points, np.ndarray):\n            self.points = points.copy()\n        else:\n            self.points = np.array(points)\n        self.refresh_bounding_box()\n        return self\n\n    def apply_over_attr_arrays(\n        self, func: Callable[[npt.NDArray[_T_np]], npt.NDArray[_T_np]]\n    ) -> Self:\n        for attr in self.get_array_attrs():\n            setattr(self, attr, func(getattr(self, attr)))\n        return self\n\n    def get_array_attrs(self) -> Iterable[str]:\n        return [\"points\"]\n\n    def append_points(self, new_points: Point3DLike_Array) -> Self:\n        self.points = np.vstack([self.points, new_points])\n        self.refresh_bounding_box()\n        return self\n\n    def reverse_points(self) -> Self:\n        for mob in self.get_family():\n            for key in mob.data:\n                mob.data[key] = mob.data[key][::-1]\n        return self\n\n    def get_midpoint(self) -> Point3D:\n        \"\"\"Get coordinates of the middle of the path that forms the  :class:`~.OpenGLMobject`.\n\n        Examples\n        --------\n\n        .. manim:: AngleMidPoint\n            :save_last_frame:\n\n            class AngleMidPoint(Scene):\n                def construct(self):\n                    line1 = Line(ORIGIN, 2*RIGHT)\n                    line2 = Line(ORIGIN, 2*RIGHT).rotate_about_origin(80*DEGREES)\n\n                    a = Angle(line1, line2, radius=1.5, other_angle=False)\n                    d = Dot(a.get_midpoint()).set_color(RED)\n\n                    self.add(line1, line2, a, d)\n                    self.wait()\n\n        \"\"\"\n        return self.point_from_proportion(0.5)\n\n    # TODO: name is inconsistent with Mobject.apply_points_function_about_point()\n    def apply_points_function(\n        self,\n        func: MultiMappingFunction,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = ORIGIN,\n        works_on_bounding_box: bool = False,\n    ) -> Self:\n        if about_point is None and about_edge is not None:\n            about_point = self.get_bounding_box_point(about_edge)\n\n        for mob in self.get_family():\n            arrs: list[Point3D_Array] = []\n            if mob.has_points():\n                arrs.append(mob.points)\n            if works_on_bounding_box:\n                arrs.append(mob.get_bounding_box())\n\n            for arr in arrs:\n                if about_point is None:\n                    arr[:] = func(arr)\n                else:\n                    arr[:] = func(arr - about_point) + about_point\n\n        if not works_on_bounding_box:\n            self.refresh_bounding_box(recurse_down=True)\n        else:\n            for parent in self.parents:\n                parent.refresh_bounding_box()\n        return self\n\n    # Others related to points\n\n    def match_points(self, mobject: OpenGLMobject) -> Self:\n        \"\"\"Edit points, positions, and submobjects to be identical\n        to another :class:`~.OpenGLMobject`, while keeping the style unchanged.\n\n        Examples\n        --------\n        .. manim:: MatchPointsScene\n\n            class MatchPointsScene(Scene):\n                def construct(self):\n                    circ = Circle(fill_color=RED, fill_opacity=0.8)\n                    square = Square(fill_color=BLUE, fill_opacity=0.2)\n                    self.add(circ)\n                    self.wait(0.5)\n                    self.play(circ.animate.match_points(square))\n                    self.wait(0.5)\n        \"\"\"\n        self.set_points(mobject.points)\n        return self\n\n    def clear_points(self) -> Self:\n        self.points = np.empty((0, 3))\n        return self\n\n    def get_num_points(self) -> int:\n        return len(self.points)\n\n    def get_all_points(self) -> Point3D_Array:\n        if self.submobjects:\n            return np.vstack([sm.points for sm in self.get_family()])\n        else:\n            return self.points\n\n    def has_points(self) -> bool:\n        return self.get_num_points() > 0\n\n    def get_bounding_box(self) -> Point3D_Array:\n        if self.needs_new_bounding_box:\n            self.bounding_box = self.compute_bounding_box()\n            self.needs_new_bounding_box = False\n        return self.bounding_box\n\n    def compute_bounding_box(self) -> Point3D_Array:\n        all_points = np.vstack(\n            [\n                self.points,\n                *(\n                    mob.get_bounding_box()\n                    for mob in self.get_family()[1:]\n                    if mob.has_points()\n                ),\n            ],\n        )\n        if len(all_points) == 0:\n            return np.zeros((3, self.dim))\n        else:\n            # Lower left and upper right corners\n            mins = all_points.min(0)\n            maxs = all_points.max(0)\n            mids = (mins + maxs) / 2\n            return np.array([mins, mids, maxs])\n\n    def refresh_bounding_box(\n        self, recurse_down: bool = False, recurse_up: bool = True\n    ) -> Self:\n        for mob in self.get_family(recurse_down):\n            mob.needs_new_bounding_box = True\n        if recurse_up:\n            for parent in self.parents:\n                parent.refresh_bounding_box()\n        return self\n\n    def is_point_touching(\n        self, point: Point3DLike, buff: float = MED_SMALL_BUFF\n    ) -> bool:\n        bb = self.get_bounding_box()\n        mins = bb[0] - buff\n        maxs = bb[2] + buff\n        rv: bool = (point >= mins).all() and (point <= maxs).all()\n        return rv\n\n    # Family matters\n\n    def __getitem__(self, value: int | slice) -> OpenGLMobject:\n        if isinstance(value, slice):\n            GroupClass = self.get_group_class()\n            return GroupClass(*self.split().__getitem__(value))\n        return self.split().__getitem__(value)\n\n    def __iter__(self) -> Iterator[OpenGLMobject]:\n        return iter(self.split())\n\n    def __len__(self) -> int:\n        return len(self.split())\n\n    def split(self) -> Sequence[OpenGLMobject]:\n        return self.submobjects\n\n    def assemble_family(self) -> Self:\n        sub_families = (sm.get_family() for sm in self.submobjects)\n        self.family = [self, *uniq_chain(*sub_families)]\n        self.refresh_has_updater_status()\n        self.refresh_bounding_box()\n        for parent in self.parents:\n            parent.assemble_family()\n        return self\n\n    def get_family(self, recurse: bool = True) -> Sequence[OpenGLMobject]:\n        if recurse and hasattr(self, \"family\"):\n            return self.family\n        else:\n            return [self]\n\n    def family_members_with_points(self) -> Sequence[OpenGLMobject]:\n        return [m for m in self.get_family() if m.has_points()]\n\n    def add(self, *mobjects: OpenGLMobject, update_parent: bool = False) -> Self:\n        \"\"\"Add mobjects as submobjects.\n\n        The mobjects are added to :attr:`submobjects`.\n\n        Subclasses of mobject may implement ``+`` and ``+=`` dunder methods.\n\n        Parameters\n        ----------\n        mobjects\n            The mobjects to add.\n\n        Returns\n        -------\n        :class:`OpenGLMobject`\n            ``self``\n\n        Raises\n        ------\n        :class:`ValueError`\n            When a mobject tries to add itself.\n        :class:`TypeError`\n            When trying to add an object that is not an instance of :class:`OpenGLMobject`.\n\n\n        Notes\n        -----\n        A mobject cannot contain itself, and it cannot contain a submobject\n        more than once.  If the parent mobject is displayed, the newly-added\n        submobjects will also be displayed (i.e. they are automatically added\n        to the parent Scene).\n\n        See Also\n        --------\n        :meth:`remove`\n        :meth:`add_to_back`\n\n        Examples\n        --------\n        ::\n\n            >>> outer = OpenGLMobject()\n            >>> inner = OpenGLMobject()\n            >>> outer = outer.add(inner)\n\n        Duplicates are not added again::\n\n            >>> outer = outer.add(inner)\n            >>> len(outer.submobjects)\n            1\n\n        Only OpenGLMobjects can be added::\n\n            >>> outer.add(3)\n            Traceback (most recent call last):\n            ...\n            TypeError: Only values of type OpenGLMobject can be added as submobjects of OpenGLMobject, but the value 3 (at index 0) is of type int.\n\n        Adding an object to itself raises an error::\n\n            >>> outer.add(outer)\n            Traceback (most recent call last):\n            ...\n            ValueError: Cannot add OpenGLMobject as a submobject of itself (at index 0).\n\n        \"\"\"\n        if update_parent:\n            assert len(mobjects) == 1, \"Can't set multiple parents.\"\n            mobjects[0].parent = self\n\n        self._assert_valid_submobjects(mobjects)\n\n        if any(mobjects.count(elem) > 1 for elem in mobjects):\n            logger.warning(\n                \"Attempted adding some Mobject as a child more than once, \"\n                \"this is not possible. Repetitions are ignored.\",\n            )\n        for mobject in mobjects:\n            if mobject not in self.submobjects:\n                self.submobjects.append(mobject)\n            if self not in mobject.parents:\n                mobject.parents.append(self)\n        self.assemble_family()\n        return self\n\n    def insert(\n        self, index: int, mobject: OpenGLMobject, update_parent: bool = False\n    ) -> Self:\n        \"\"\"Inserts a mobject at a specific position into self.submobjects\n\n        Effectively just calls  ``self.submobjects.insert(index, mobject)``,\n        where ``self.submobjects`` is a list.\n\n        Highly adapted from ``OpenGLMobject.add``.\n\n        Parameters\n        ----------\n        index\n            The index at which\n        mobject\n            The mobject to be inserted.\n        update_parent\n            Whether or not to set ``mobject.parent`` to ``self``.\n        \"\"\"\n        if update_parent:\n            mobject.parent = self\n\n        self._assert_valid_submobjects([mobject])\n\n        if mobject not in self.submobjects:\n            self.submobjects.insert(index, mobject)\n\n        if self not in mobject.parents:\n            mobject.parents.append(self)\n\n        self.assemble_family()\n        return self\n\n    def remove(self, *mobjects: OpenGLMobject, update_parent: bool = False) -> Self:\n        \"\"\"Remove :attr:`submobjects`.\n\n        The mobjects are removed from :attr:`submobjects`, if they exist.\n\n        Subclasses of mobject may implement ``-`` and ``-=`` dunder methods.\n\n        Parameters\n        ----------\n        mobjects\n            The mobjects to remove.\n\n        Returns\n        -------\n        :class:`OpenGLMobject`\n            ``self``\n\n        See Also\n        --------\n        :meth:`add`\n\n        \"\"\"\n        if update_parent:\n            assert len(mobjects) == 1, \"Can't remove multiple parents.\"\n            mobjects[0].parent = None\n\n        for mobject in mobjects:\n            if mobject in self.submobjects:\n                self.submobjects.remove(mobject)\n            if self in mobject.parents:\n                mobject.parents.remove(self)\n        self.assemble_family()\n        return self\n\n    def add_to_back(self, *mobjects: OpenGLMobject) -> Self:\n        # NOTE: is the note true OpenGLMobjects?\n        \"\"\"Add all passed mobjects to the back of the submobjects.\n\n        If :attr:`submobjects` already contains the given mobjects, they just get moved\n        to the back instead.\n\n        Parameters\n        ----------\n        mobjects\n            The mobjects to add.\n\n        Returns\n        -------\n        :class:`OpenGLMobject`\n            ``self``\n\n\n        .. note::\n\n            Technically, this is done by adding (or moving) the mobjects to\n            the head of :attr:`submobjects`. The head of this list is rendered\n            first, which places the corresponding mobjects behind the\n            subsequent list members.\n\n        Raises\n        ------\n        :class:`ValueError`\n            When a mobject tries to add itself.\n        :class:`TypeError`\n            When trying to add an object that is not an instance of :class:`OpenGLMobject`.\n\n        Notes\n        -----\n        A mobject cannot contain itself, and it cannot contain a submobject\n        more than once.  If the parent mobject is displayed, the newly-added\n        submobjects will also be displayed (i.e. they are automatically added\n        to the parent Scene).\n\n        See Also\n        --------\n        :meth:`remove`\n        :meth:`add`\n\n        \"\"\"\n        self._assert_valid_submobjects(mobjects)\n        self.submobjects = list_update(mobjects, self.submobjects)\n        return self\n\n    def replace_submobject(self, index: int, new_submob: OpenGLMobject) -> Self:\n        self._assert_valid_submobjects([new_submob])\n        old_submob = self.submobjects[index]\n        if self in old_submob.parents:\n            old_submob.parents.remove(self)\n        self.submobjects[index] = new_submob\n        self.assemble_family()\n        return self\n\n    # Submobject organization\n\n    def arrange(\n        self,\n        direction: Vector3DLike = RIGHT,\n        center: bool = True,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Sorts :class:`~.OpenGLMobject` next to each other on screen.\n\n        Examples\n        --------\n\n        .. manim:: Example\n            :save_last_frame:\n\n            class Example(Scene):\n                def construct(self):\n                    s1 = Square()\n                    s2 = Square()\n                    s3 = Square()\n                    s4 = Square()\n                    x = OpenGLVGroup(s1, s2, s3, s4).set_x(0).arrange(buff=1.0)\n                    self.add(x)\n        \"\"\"\n        for m1, m2 in zip(self.submobjects[:-1], self.submobjects[1:], strict=True):\n            m2.next_to(m1, direction, **kwargs)\n        if center:\n            self.center()\n        return self\n\n    def arrange_in_grid(\n        self,\n        rows: int | None = None,\n        cols: int | None = None,\n        buff: float | tuple[float, float] = MED_SMALL_BUFF,\n        cell_alignment: Vector3DLike = ORIGIN,\n        row_alignments: str | None = None,  # \"ucd\"\n        col_alignments: str | None = None,  # \"lcr\"\n        row_heights: Sequence[float | None] | None = None,\n        col_widths: Sequence[float | None] | None = None,\n        flow_order: str = \"rd\",\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Arrange submobjects in a grid.\n\n        Parameters\n        ----------\n        rows\n            The number of rows in the grid.\n        cols\n            The number of columns in the grid.\n        buff\n            The gap between grid cells. To specify a different buffer in the horizontal and\n            vertical directions, a tuple of two values can be given - ``(row, col)``.\n        cell_alignment\n            The way each submobject is aligned in its grid cell.\n        row_alignments\n            The vertical alignment for each row (top to bottom). Accepts the following characters: ``\"u\"`` -\n            up, ``\"c\"`` - center, ``\"d\"`` - down.\n        col_alignments\n            The horizontal alignment for each column (left to right). Accepts the following characters ``\"l\"`` - left,\n            ``\"c\"`` - center, ``\"r\"`` - right.\n        row_heights\n            Defines a list of heights for certain rows (top to bottom). If the list contains\n            ``None``, the corresponding row will fit its height automatically based\n            on the highest element in that row.\n        col_widths\n            Defines a list of widths for certain columns (left to right). If the list contains ``None``, the\n            corresponding column will fit its width automatically based on the widest element in that column.\n        flow_order\n            The order in which submobjects fill the grid. Can be one of the following values:\n            \"rd\", \"dr\", \"ld\", \"dl\", \"ru\", \"ur\", \"lu\", \"ul\". (\"rd\" -> fill rightwards then downwards)\n\n        Returns\n        -------\n        OpenGLMobject\n            The mobject.\n\n        NOTES\n        -----\n\n        If only one of ``cols`` and ``rows`` is set implicitly, the other one will be chosen big\n        enough to fit all submobjects. If neither is set, they will be chosen to be about the same,\n        tending towards ``cols`` > ``rows`` (simply because videos are wider than they are high).\n\n        If both ``cell_alignment`` and ``row_alignments`` / ``col_alignments`` are\n        defined, the latter has higher priority.\n\n\n        Raises\n        ------\n        ValueError\n            If ``rows`` and ``cols`` are too small to fit all submobjects.\n        ValueError\n            If :code:`cols`, :code:`col_alignments` and :code:`col_widths` or :code:`rows`,\n            :code:`row_alignments` and :code:`row_heights` have mismatching sizes.\n\n        Examples\n        --------\n        .. manim:: ExampleBoxes\n            :save_last_frame:\n\n            class ExampleBoxes(Scene):\n                def construct(self):\n                    boxes=VGroup(*[Square() for s in range(0,6)])\n                    boxes.arrange_in_grid(rows=2, buff=0.1)\n                    self.add(boxes)\n\n\n        .. manim:: ArrangeInGrid\n            :save_last_frame:\n\n            class ArrangeInGrid(Scene):\n                def construct(self):\n                    #Add some numbered boxes:\n                    np.random.seed(3)\n                    boxes = VGroup(*[\n                        Rectangle(WHITE, np.random.random()+.5, np.random.random()+.5).add(Text(str(i+1)).scale(0.5))\n                        for i in range(22)\n                    ])\n                    self.add(boxes)\n\n                    boxes.arrange_in_grid(\n                        buff=(0.25,0.5),\n                        col_alignments=\"lccccr\",\n                        row_alignments=\"uccd\",\n                        col_widths=[2, *[None]*4, 2],\n                        flow_order=\"dr\"\n                    )\n\n\n        \"\"\"\n        from manim.mobject.geometry.line import Line\n\n        mobs = self.submobjects.copy()\n        start_pos = self.get_center()\n\n        # get cols / rows values if given (implicitly)\n        def init_size(\n            num: int | None,\n            alignments: str | None,\n            sizes: Sequence[float | None] | None,\n            name: str,\n        ) -> int:\n            if num is not None:\n                return num\n            if alignments is not None:\n                return len(alignments)\n            if sizes is not None:\n                return len(sizes)\n            raise ValueError(\n                f\"At least one of the following parameters: '{name}s', \"\n                f\"'{name}_alignments' or \"\n                f\"'{name}_{'widths' if name == 'col' else 'heights'}', \"\n                \"must not be None\"\n            )\n\n        cols = init_size(cols, col_alignments, col_widths, \"col\")\n        rows = init_size(rows, row_alignments, row_heights, \"row\")\n\n        # calculate rows cols\n        if rows is None and cols is None:\n            cols = ceil(np.sqrt(len(mobs)))\n            # make the grid as close to quadratic as possible.\n            # choosing cols first can results in cols>rows.\n            # This is favored over rows>cols since in general\n            # the sceene is wider than high.\n        if rows is None:\n            rows = ceil(len(mobs) / cols)\n        if cols is None:\n            cols = ceil(len(mobs) / rows)\n        if rows * cols < len(mobs):\n            raise ValueError(\"Too few rows and columns to fit all submobjetcs.\")\n        # rows and cols are now finally valid.\n\n        if isinstance(buff, tuple):\n            buff_x = buff[0]\n            buff_y = buff[1]\n        else:\n            buff_x = buff_y = buff\n\n        # Initialize alignments correctly\n        def init_alignments(\n            str_alignments: str | None,\n            num: int,\n            mapping: dict[str, Vector3D],\n            name: str,\n            direction: Vector3D,\n        ) -> Sequence[Vector3D]:\n            if str_alignments is None:\n                # Use cell_alignment as fallback\n                return [cast(\"Vector3D\", cell_alignment * direction)] * num\n            if len(str_alignments) != num:\n                raise ValueError(f\"{name}_alignments has a mismatching size.\")\n            return [mapping[letter] for letter in str_alignments]\n\n        row_alignments_seq: Sequence[Vector3D] = init_alignments(\n            row_alignments,\n            rows,\n            {\"u\": UP, \"c\": ORIGIN, \"d\": DOWN},\n            \"row\",\n            RIGHT,\n        )\n        col_alignments_seq: Sequence[Vector3D] = init_alignments(\n            col_alignments,\n            cols,\n            {\"l\": LEFT, \"c\": ORIGIN, \"r\": RIGHT},\n            \"col\",\n            UP,\n        )\n        # Now row_alignments_seq[r] + col_alignment_seq[c] is the alignment in cell [r][c]\n\n        mapper: dict[str, Callable[[int, int], int]] = {\n            \"dr\": lambda r, c: (rows - r - 1) + c * rows,\n            \"dl\": lambda r, c: (rows - r - 1) + (cols - c - 1) * rows,\n            \"ur\": lambda r, c: r + c * rows,\n            \"ul\": lambda r, c: r + (cols - c - 1) * rows,\n            \"rd\": lambda r, c: (rows - r - 1) * cols + c,\n            \"ld\": lambda r, c: (rows - r - 1) * cols + (cols - c - 1),\n            \"ru\": lambda r, c: r * cols + c,\n            \"lu\": lambda r, c: r * cols + (cols - c - 1),\n        }\n        if flow_order not in mapper:\n            valid_flow_orders = \",\".join([f'\"{key}\"' for key in mapper])\n            raise ValueError(\n                f\"flow_order must be one of the following values: {valid_flow_orders}.\",\n            )\n        flow_order_func = mapper[flow_order]\n\n        # Reverse row_alignments and row_heights. Necessary since the\n        # grid filling is handled bottom up for simplicity reasons.\n        if TYPE_CHECKING:\n\n            @overload\n            def reverse(maybe_list: None) -> None: ...\n            @overload\n            def reverse(maybe_list: Sequence[_T]) -> list[_T]: ...\n            @overload\n            def reverse(maybe_list: Sequence[_T] | None) -> list[_T] | None: ...\n\n        def reverse(maybe_list: Sequence[_T] | None) -> list[_T] | None:\n            if maybe_list is not None:\n                maybe_list = list(maybe_list)\n                maybe_list.reverse()\n                return maybe_list\n            return None\n\n        row_alignments_seq = reverse(row_alignments_seq)\n        row_heights = reverse(row_heights)\n\n        placeholder = OpenGLMobject()\n        # Used to fill up the grid temporarily, doesn't get added to the scene.\n        # In this case a Mobject is better than None since it has width and height\n        # properties of 0.\n\n        mobs.extend([placeholder] * (rows * cols - len(mobs)))\n        grid = [[mobs[flow_order_func(r, c)] for c in range(cols)] for r in range(rows)]\n\n        measured_heigths = [\n            max(grid[r][c].height for c in range(cols)) for r in range(rows)\n        ]\n        measured_widths = [\n            max(grid[r][c].width for r in range(rows)) for c in range(cols)\n        ]\n\n        # Initialize row_heights / col_widths correctly using measurements as fallback\n        def init_sizes(\n            sizes: Sequence[float | None] | None,\n            num: int,\n            measures: Sequence[float],\n            name: str,\n        ) -> Sequence[float]:\n            if sizes is None:\n                sizes = [None] * num\n            if len(sizes) != num:\n                raise ValueError(f\"{name} has a mismatching size.\")\n            return [\n                size if (size := sizes[i]) is not None else measures[i]\n                for i in range(num)\n            ]\n\n        heights = init_sizes(row_heights, rows, measured_heigths, \"row_heights\")\n        widths = init_sizes(col_widths, cols, measured_widths, \"col_widths\")\n\n        x, y = 0.0, 0.0\n        for r in range(rows):\n            x = 0.0\n            for c in range(cols):\n                if grid[r][c] is not placeholder:\n                    alignment = row_alignments_seq[r] + col_alignments_seq[c]\n                    line = Line(\n                        x * RIGHT + y * UP,\n                        (x + widths[c]) * RIGHT + (y + heights[r]) * UP,\n                    )\n                    # Use a mobject to avoid rewriting align inside\n                    # box code that Mobject.move_to(Mobject) already\n                    # includes.\n\n                    grid[r][c].move_to(line, alignment)\n                x += widths[c] + buff_x\n            y += heights[r] + buff_y\n\n        self.move_to(start_pos)\n        return self\n\n    def get_grid(\n        self,\n        n_rows: int,\n        n_cols: int,\n        height: float | None = None,\n        **kwargs: Any,\n    ) -> OpenGLGroup:\n        \"\"\"\n        Returns a new mobject containing multiple copies of this one\n        arranged in a grid\n        \"\"\"\n        grid = self.duplicate(n_rows * n_cols)\n        grid.arrange_in_grid(n_rows, n_cols, **kwargs)\n        if height is not None:\n            grid.set_height(height)\n        return grid\n\n    def duplicate(self, n: int) -> OpenGLGroup:\n        \"\"\"Returns an :class:`~.OpenGLGroup` containing ``n`` copies of the mobject.\"\"\"\n        return self.get_group_class()(*[self.copy() for _ in range(n)])\n\n    def sort(\n        self,\n        point_to_num_func: Callable[[Point3DLike], float] = lambda p: p[0],\n        submob_func: Callable[[OpenGLMobject], Any] | None = None,\n    ) -> Self:\n        \"\"\"Sorts the list of :attr:`submobjects` by a function defined by ``submob_func``.\"\"\"\n        if submob_func is not None:\n            self.submobjects.sort(key=submob_func)\n        else:\n            self.submobjects.sort(key=lambda m: point_to_num_func(m.get_center()))\n        return self\n\n    def shuffle(self, recurse: bool = False) -> Self:\n        \"\"\"Shuffles the order of :attr:`submobjects`\n\n        Examples\n        --------\n\n        .. manim:: ShuffleSubmobjectsExample\n\n            class ShuffleSubmobjectsExample(Scene):\n                def construct(self):\n                    s= OpenGLVGroup(*[Dot().shift(i*0.1*RIGHT) for i in range(-20,20)])\n                    s2= s.copy()\n                    s2.shuffle()\n                    s2.shift(DOWN)\n                    self.play(Write(s), Write(s2))\n        \"\"\"\n        if recurse:\n            for submob in self.submobjects:\n                submob.shuffle(recurse=True)\n        random.shuffle(self.submobjects)\n        self.assemble_family()\n        return self\n\n    def invert(self, recursive: bool = False) -> Self:\n        \"\"\"Inverts the list of :attr:`submobjects`.\n\n        Parameters\n        ----------\n        recursive\n            If ``True``, all submobject lists of this mobject's family are inverted.\n\n        Examples\n        --------\n\n        .. manim:: InvertSumobjectsExample\n\n            class InvertSumobjectsExample(Scene):\n                def construct(self):\n                    s = VGroup(*[Dot().shift(i*0.1*RIGHT) for i in range(-20,20)])\n                    s2 = s.copy()\n                    s2.invert()\n                    s2.shift(DOWN)\n                    self.play(Write(s), Write(s2))\n        \"\"\"\n        if recursive:\n            for submob in self.submobjects:\n                submob.invert(recursive=True)\n        self.submobjects.reverse()\n        self.assemble_family()\n        return self\n\n    # Copying\n\n    def copy(self, shallow: bool = False) -> OpenGLMobject:\n        \"\"\"Create and return an identical copy of the :class:`OpenGLMobject` including all\n        :attr:`submobjects`.\n\n        Returns\n        -------\n        :class:`OpenGLMobject`\n            The copy.\n\n        Parameters\n        ----------\n        shallow\n            Controls whether a shallow copy is returned.\n\n        Note\n        ----\n        The clone is initially not visible in the Scene, even if the original was.\n        \"\"\"\n        if not shallow:\n            return self.deepcopy()\n\n        # TODO, either justify reason for shallow copy, or\n        # remove this redundancy everywhere\n        # return self.deepcopy()\n\n        parents = self.parents\n        self.parents = []\n        copy_mobject = copy.copy(self)\n        self.parents = parents\n\n        copy_mobject.data = dict(self.data)\n        for key in self.data:\n            copy_mobject.data[key] = self.data[key].copy()\n\n        # TODO, are uniforms ever numpy arrays?\n        copy_mobject.uniforms = dict(self.uniforms)\n\n        copy_mobject.submobjects = []\n        copy_mobject.add(*(sm.copy() for sm in self.submobjects))\n        copy_mobject.match_updaters(self)\n\n        copy_mobject.needs_new_bounding_box = self.needs_new_bounding_box\n\n        # Make sure any mobject or numpy array attributes are copied\n        family = self.get_family()\n        for attr, value in list(self.__dict__.items()):\n            if (\n                isinstance(value, OpenGLMobject)\n                and value in family\n                and value is not self\n            ):\n                setattr(copy_mobject, attr, value.copy())\n            if isinstance(value, np.ndarray):\n                setattr(copy_mobject, attr, value.copy())\n            # if isinstance(value, ShaderWrapper):\n            #     setattr(copy_mobject, attr, value.copy())\n        return copy_mobject\n\n    def deepcopy(self) -> OpenGLMobject:\n        parents = self.parents\n        self.parents = []\n        result = copy.deepcopy(self)\n        self.parents = parents\n        return result\n\n    def generate_target(self, use_deepcopy: bool = False) -> OpenGLMobject:\n        self.target: OpenGLMobject | None = None  # Prevent exponential explosion\n        if use_deepcopy:\n            self.target = self.deepcopy()\n        else:\n            self.target = self.copy()\n        return self.target\n\n    def save_state(self, use_deepcopy: bool = False) -> Self:\n        \"\"\"Save the current state (position, color & size). Can be restored with :meth:`~.OpenGLMobject.restore`.\"\"\"\n        if hasattr(self, \"saved_state\"):\n            # Prevent exponential growth of data\n            self.saved_state: OpenGLMobject | None = None\n        if use_deepcopy:\n            self.saved_state = self.deepcopy()\n        else:\n            self.saved_state = self.copy()\n        return self\n\n    def restore(self) -> Self:\n        \"\"\"Restores the state that was previously saved with :meth:`~.OpenGLMobject.save_state`.\"\"\"\n        if not hasattr(self, \"saved_state\") or self.saved_state is None:\n            raise Exception(\"Trying to restore without having saved\")\n        self.become(self.saved_state)\n        return self\n\n    # Updating\n\n    def init_updaters(self) -> None:\n        self.time_based_updaters: list[\"_TimeBasedUpdater\"] = []  # noqa: UP037\n        self.non_time_updaters: list[\"_NonTimeBasedUpdater\"] = []  # noqa: UP037\n        self.has_updaters: bool = False\n        self.updating_suspended: bool = False\n\n    def update(self, dt: float = 0, recurse: bool = True) -> Self:\n        if self.has_updaters and not self.updating_suspended:\n            for time_based_updater in self.time_based_updaters:\n                time_based_updater(self, dt)\n            for non_time_updater in self.non_time_updaters:\n                non_time_updater(self)\n        if recurse:\n            for submob in self.submobjects:\n                submob.update(dt, recurse)\n        return self\n\n    def get_time_based_updaters(self) -> Sequence[_TimeBasedUpdater]:\n        return self.time_based_updaters\n\n    def has_time_based_updater(self) -> bool:\n        return len(self.time_based_updaters) > 0\n\n    def get_updaters(self) -> Sequence[_Updater]:\n        return cast(\"list[_Updater]\", self.time_based_updaters) + cast(\n            \"list[_Updater]\", self.non_time_updaters\n        )\n\n    def get_family_updaters(self) -> Sequence[_Updater]:\n        return list(it.chain(*(sm.get_updaters() for sm in self.get_family())))\n\n    def add_updater(\n        self,\n        update_function: _Updater,\n        index: int | None = None,\n        call_updater: bool = False,\n    ) -> Self:\n        updater_list: list[_TimeBasedUpdater] | list[_NonTimeBasedUpdater]\n        if \"dt\" in inspect.signature(update_function).parameters:\n            updater_list = self.time_based_updaters\n        else:\n            updater_list = self.non_time_updaters\n\n        if index is None:\n            cast(\"list[_Updater]\", updater_list).append(update_function)\n        else:\n            cast(\"list[_Updater]\", updater_list).insert(index, update_function)\n\n        self.refresh_has_updater_status()\n        if call_updater:\n            self.update()\n        return self\n\n    def remove_updater(self, update_function: _Updater) -> Self:\n        for updater_list in [self.time_based_updaters, self.non_time_updaters]:\n            updater_list = cast(\"list[_Updater]\", updater_list)\n            while update_function in updater_list:\n                updater_list.remove(update_function)\n        self.refresh_has_updater_status()\n        return self\n\n    def clear_updaters(self, recurse: bool = True) -> Self:\n        self.time_based_updaters = []\n        self.non_time_updaters = []\n        self.refresh_has_updater_status()\n        if recurse:\n            for submob in self.submobjects:\n                submob.clear_updaters()\n        return self\n\n    def match_updaters(self, mobject: OpenGLMobject) -> Self:\n        self.clear_updaters()\n        for updater in mobject.get_updaters():\n            self.add_updater(updater)\n        return self\n\n    def suspend_updating(self, recurse: bool = True) -> Self:\n        self.updating_suspended = True\n        if recurse:\n            for submob in self.submobjects:\n                submob.suspend_updating(recurse)\n        return self\n\n    def resume_updating(self, recurse: bool = True, call_updater: bool = True) -> Self:\n        self.updating_suspended = False\n        if recurse:\n            for submob in self.submobjects:\n                submob.resume_updating(recurse)\n        for parent in self.parents:\n            parent.resume_updating(recurse=False, call_updater=False)\n        if call_updater:\n            self.update(dt=0, recurse=recurse)\n        return self\n\n    def refresh_has_updater_status(self) -> Self:\n        self.has_updaters = any(mob.get_updaters() for mob in self.get_family())\n        return self\n\n    # Transforming operations\n\n    def shift(self, vector: Vector3DLike) -> Self:\n        self.apply_points_function(\n            lambda points: points + vector,\n            about_edge=None,\n            works_on_bounding_box=True,\n        )\n        return self\n\n    def scale(\n        self,\n        scale_factor: float,\n        about_point: Point3DLike | None = None,\n        about_edge: Point3DLike | None = ORIGIN,\n        **_kwargs: object,\n    ) -> Self:\n        r\"\"\"Scale the size by a factor.\n\n        Default behavior is to scale about the center of the mobject.\n        The argument about_edge can be a vector, indicating which side of\n        the mobject to scale about, e.g., mob.scale(about_edge = RIGHT)\n        scales about mob.get_right().\n\n        Otherwise, if about_point is given a value, scaling is done with\n        respect to that point.\n\n        Parameters\n        ----------\n        scale_factor\n            The scaling factor :math:`\\alpha`. If :math:`0 < |\\alpha| < 1`, the mobject\n            will shrink, and for :math:`|\\alpha| > 1` it will grow. Furthermore,\n            if :math:`\\alpha < 0`, the mobject is also flipped.\n        kwargs\n            Additional keyword arguments passed to\n            :meth:`apply_points_function`.\n\n        Returns\n        -------\n        OpenGLMobject\n            The scaled mobject.\n\n        Examples\n        --------\n\n        .. manim:: MobjectScaleExample\n            :save_last_frame:\n\n            class MobjectScaleExample(Scene):\n                def construct(self):\n                    f1 = Text(\"F\")\n                    f2 = Text(\"F\").scale(2)\n                    f3 = Text(\"F\").scale(0.5)\n                    f4 = Text(\"F\").scale(-1)\n\n                    vgroup = VGroup(f1, f2, f3, f4).arrange(6 * RIGHT)\n                    self.add(vgroup)\n\n        See also\n        --------\n        :meth:`move_to`\n\n        \"\"\"\n        self.apply_points_function(\n            lambda points: scale_factor * points,\n            about_point=about_point,\n            about_edge=about_edge,\n            works_on_bounding_box=True,\n        )\n        return self\n\n    def stretch(self, factor: float, dim: int, **kwargs: Any) -> Self:\n        def func(points: Point3D_Array) -> Point3D_Array:\n            points[:, dim] *= factor\n            return points\n\n        self.apply_points_function(func, works_on_bounding_box=True, **kwargs)\n        return self\n\n    def rotate_about_origin(self, angle: float, axis: Vector3DLike = OUT) -> Self:\n        return self.rotate(angle, axis, about_point=ORIGIN)\n\n    def rotate(\n        self,\n        angle: float,\n        axis: Vector3DLike = OUT,\n        about_point: Point3DLike | None = None,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Rotates the :class:`~.OpenGLMobject` about a certain point.\"\"\"\n        rot_matrix_T = rotation_matrix_transpose(angle, axis)\n        self.apply_points_function(\n            lambda points: np.dot(points, rot_matrix_T),\n            about_point=about_point,\n            **kwargs,\n        )\n        return self\n\n    def flip(self, axis: Vector3DLike = UP, **kwargs: Any) -> Self:\n        \"\"\"Flips/Mirrors an mobject about its center.\n\n        Examples\n        --------\n\n        .. manim:: FlipExample\n            :save_last_frame:\n\n            class FlipExample(Scene):\n                def construct(self):\n                    s= Line(LEFT, RIGHT+UP).shift(4*LEFT)\n                    self.add(s)\n                    s2= s.copy().flip()\n                    self.add(s2)\n\n        \"\"\"\n        return self.rotate(TAU / 2, axis, **kwargs)\n\n    def apply_function(self, function: MappingFunction, **kwargs: Any) -> Self:\n        # Default to applying matrix about the origin, not mobjects center\n        if len(kwargs) == 0:\n            kwargs[\"about_point\"] = ORIGIN\n\n        def multi_mapping_function(points: Point3D_Array) -> Point3D_Array:\n            result: Point3D_Array = np.apply_along_axis(function, 1, points)\n            return result\n\n        self.apply_points_function(multi_mapping_function, **kwargs)\n        return self\n\n    def apply_function_to_position(self, function: MappingFunction) -> Self:\n        self.move_to(function(self.get_center()))\n        return self\n\n    def apply_function_to_submobject_positions(self, function: MappingFunction) -> Self:\n        for submob in self.submobjects:\n            submob.apply_function_to_position(function)\n        return self\n\n    def apply_matrix(self, matrix: MatrixMN, **kwargs: Any) -> Self:\n        # Default to applying matrix about the origin, not mobjects center\n        if (\"about_point\" not in kwargs) and (\"about_edge\" not in kwargs):\n            kwargs[\"about_point\"] = ORIGIN\n        full_matrix = np.identity(self.dim)\n        matrix = np.array(matrix)\n        full_matrix[: matrix.shape[0], : matrix.shape[1]] = matrix\n        self.apply_points_function(\n            lambda points: np.dot(points, full_matrix.T), **kwargs\n        )\n        return self\n\n    def apply_complex_function(\n        self, function: Callable[[complex], complex], **kwargs: Any\n    ) -> Self:\n        \"\"\"Applies a complex function to a :class:`OpenGLMobject`.\n        The x and y coordinates correspond to the real and imaginary parts respectively.\n\n        Example\n        -------\n\n        .. manim:: ApplyFuncExample\n\n            class ApplyFuncExample(Scene):\n                def construct(self):\n                    circ = Circle().scale(1.5)\n                    circ_ref = circ.copy()\n                    circ.apply_complex_function(\n                        lambda x: np.exp(x*1j)\n                    )\n                    t = ValueTracker(0)\n                    circ.add_updater(\n                        lambda x: x.become(circ_ref.copy().apply_complex_function(\n                            lambda x: np.exp(x+t.get_value()*1j)\n                        )).set_color(BLUE)\n                    )\n                    self.add(circ_ref)\n                    self.play(TransformFromCopy(circ_ref, circ))\n                    self.play(t.animate.set_value(TAU), run_time=3)\n        \"\"\"\n\n        def R3_func(point: Point3D) -> Point3D:\n            x, y, z = point\n            xy_complex = function(complex(x, y))\n            return np.array([xy_complex.real, xy_complex.imag, z])\n\n        return self.apply_function(R3_func, **kwargs)\n\n    def hierarchical_model_matrix(self) -> MatrixMN:\n        if self.parent is None:\n            return self.model_matrix\n\n        model_matrices = [self.model_matrix]\n        current_object = self\n        while current_object.parent is not None:\n            model_matrices.append(current_object.parent.model_matrix)\n            current_object = current_object.parent\n        return np.linalg.multi_dot(list(reversed(model_matrices)))\n\n    def wag(\n        self,\n        direction: Vector3DLike = RIGHT,\n        axis: Vector3DLike = DOWN,\n        wag_factor: float = 1.0,\n    ) -> Self:\n        for mob in self.family_members_with_points():\n            alphas = np.dot(mob.points, np.transpose(axis))\n            alphas -= min(alphas)\n            alphas /= max(alphas)\n            alphas = alphas**wag_factor\n            mob.set_points(\n                mob.points\n                + np.dot(\n                    alphas.reshape((len(alphas), 1)),\n                    np.array(direction).reshape((1, mob.dim)),\n                ),\n            )\n        return self\n\n    # Positioning methods\n\n    def center(self) -> Self:\n        \"\"\"Moves the mobject to the center of the Scene.\"\"\"\n        self.shift(-self.get_center())\n        return self\n\n    def align_on_border(\n        self,\n        direction: Vector3DLike,\n        buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER,\n    ) -> Self:\n        \"\"\"\n        Direction just needs to be a vector pointing towards side or\n        corner in the 2d plane.\n        \"\"\"\n        target_point = np.sign(direction) * (\n            config[\"frame_x_radius\"],\n            config[\"frame_y_radius\"],\n            0,\n        )\n        point_to_align = self.get_bounding_box_point(direction)\n        shift_val = target_point - point_to_align - buff * np.asarray(direction)\n        shift_val = shift_val * abs(np.sign(direction))\n        self.shift(shift_val)\n        return self\n\n    def to_corner(\n        self,\n        corner: Vector3DLike = LEFT + DOWN,\n        buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER,\n    ) -> Self:\n        return self.align_on_border(corner, buff)\n\n    def to_edge(\n        self,\n        edge: Vector3DLike = LEFT,\n        buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER,\n    ) -> Self:\n        return self.align_on_border(edge, buff)\n\n    def next_to(\n        self,\n        mobject_or_point: OpenGLMobject | Point3DLike,\n        direction: Vector3DLike = RIGHT,\n        buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,\n        aligned_edge: Vector3DLike = ORIGIN,\n        submobject_to_align: OpenGLMobject | None = None,\n        index_of_submobject_to_align: int | None = None,\n        coor_mask: Vector3DLike = np.array([1, 1, 1]),\n    ) -> Self:\n        \"\"\"Move this :class:`~.OpenGLMobject` next to another's :class:`~.OpenGLMobject` or coordinate.\n\n        Examples\n        --------\n\n        .. manim:: GeometricShapes\n            :save_last_frame:\n\n            class GeometricShapes(Scene):\n                def construct(self):\n                    d = Dot()\n                    c = Circle()\n                    s = Square()\n                    t = Triangle()\n                    d.next_to(c, RIGHT)\n                    s.next_to(c, LEFT)\n                    t.next_to(c, DOWN)\n                    self.add(d, c, s, t)\n\n        \"\"\"\n        np_direction = np.asarray(direction)\n        np_aligned_edge = np.asarray(aligned_edge)\n\n        target_point: Point3DLike\n        if isinstance(mobject_or_point, OpenGLMobject):\n            mob = mobject_or_point\n            if index_of_submobject_to_align is not None:\n                target_aligner = mob[index_of_submobject_to_align]\n            else:\n                target_aligner = mob\n            target_point = target_aligner.get_bounding_box_point(\n                np_aligned_edge + np_direction,\n            )\n        else:\n            target_point = mobject_or_point\n        if submobject_to_align is not None:\n            aligner = submobject_to_align\n        elif index_of_submobject_to_align is not None:\n            aligner = self[index_of_submobject_to_align]\n        else:\n            aligner = self\n        point_to_align = aligner.get_bounding_box_point(np_aligned_edge - np_direction)\n        self.shift((target_point - point_to_align + buff * np_direction) * coor_mask)\n        return self\n\n    def shift_onto_screen(self, **kwargs: Any) -> Self:\n        space_lengths: list[float] = [\n            config[\"frame_x_radius\"],\n            config[\"frame_y_radius\"],\n        ]\n        for vect in UP, DOWN, LEFT, RIGHT:\n            dim = np.argmax(np.abs(vect))\n            buff: float = kwargs.get(\"buff\", DEFAULT_MOBJECT_TO_EDGE_BUFFER)\n            max_val = space_lengths[dim] - buff\n            edge_center = self.get_edge_center(vect)\n            if np.dot(edge_center, vect) > max_val:\n                self.to_edge(vect, buff=buff)\n        return self\n\n    def is_off_screen(self) -> bool:\n        if self.get_left()[0] > config.frame_x_radius:\n            return True\n        if self.get_right()[0] < config.frame_x_radius:\n            return True\n        if self.get_bottom()[1] > config.frame_y_radius:\n            return True\n        return cast(float, self.get_top()[1]) < -config.frame_y_radius\n\n    def stretch_about_point(self, factor: float, dim: int, point: Point3DLike) -> Self:\n        return self.stretch(factor, dim, about_point=point)\n\n    def rescale_to_fit(\n        self,\n        length: float,\n        dim: int,\n        stretch: bool = False,\n        **kwargs: Any,\n    ) -> Self:\n        old_length = self.length_over_dim(dim)\n        if old_length == 0:\n            return self\n        if stretch:\n            self.stretch(length / old_length, dim, **kwargs)\n        else:\n            self.scale(length / old_length, **kwargs)\n        return self\n\n    def stretch_to_fit_width(self, width: float, **kwargs: Any) -> Self:\n        \"\"\"Stretches the :class:`~.OpenGLMobject` to fit a width, not keeping height/depth proportional.\n\n        Returns\n        -------\n        :class:`OpenGLMobject`\n            ``self``\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import *\n            >>> import numpy as np\n            >>> sq = Square()\n            >>> sq.height\n            np.float64(2.0)\n            >>> sq.stretch_to_fit_width(5)\n            Square\n            >>> sq.width\n            np.float64(5.0)\n            >>> sq.height\n            np.float64(2.0)\n        \"\"\"\n        return self.rescale_to_fit(width, 0, stretch=True, **kwargs)\n\n    def stretch_to_fit_height(self, height: float, **kwargs: Any) -> Self:\n        \"\"\"Stretches the :class:`~.OpenGLMobject` to fit a height, not keeping width/height proportional.\"\"\"\n        return self.rescale_to_fit(height, 1, stretch=True, **kwargs)\n\n    def stretch_to_fit_depth(self, depth: float, **kwargs: Any) -> Self:\n        \"\"\"Stretches the :class:`~.OpenGLMobject` to fit a depth, not keeping width/height proportional.\"\"\"\n        return self.rescale_to_fit(depth, 1, stretch=True, **kwargs)\n\n    def set_width(\n        self,\n        width: float,\n        stretch: bool = False,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Scales the :class:`~.OpenGLMobject` to fit a width while keeping height/depth proportional.\n\n        Returns\n        -------\n        :class:`OpenGLMobject`\n            ``self``\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import *\n            >>> import numpy as np\n            >>> sq = Square()\n            >>> sq.height\n            np.float64(2.0)\n            >>> sq.scale_to_fit_width(5)\n            Square\n            >>> sq.width\n            np.float64(5.0)\n            >>> sq.height\n            np.float64(5.0)\n        \"\"\"\n        return self.rescale_to_fit(width, 0, stretch=stretch, **kwargs)\n\n    scale_to_fit_width = set_width\n\n    def set_height(\n        self,\n        height: float,\n        stretch: bool = False,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Scales the :class:`~.OpenGLMobject` to fit a height while keeping width/depth proportional.\"\"\"\n        return self.rescale_to_fit(height, 1, stretch=stretch, **kwargs)\n\n    scale_to_fit_height = set_height\n\n    def set_depth(\n        self,\n        depth: float,\n        stretch: bool = False,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Scales the :class:`~.OpenGLMobject` to fit a depth while keeping width/height proportional.\"\"\"\n        return self.rescale_to_fit(depth, 2, stretch=stretch, **kwargs)\n\n    scale_to_fit_depth = set_depth\n\n    def set_coord(\n        self, value: float, dim: int, direction: Vector3DLike = ORIGIN\n    ) -> Self:\n        curr = self.get_coord(dim, direction)\n        shift_vect = np.zeros(self.dim)\n        shift_vect[dim] = value - curr\n        self.shift(shift_vect)\n        return self\n\n    def set_x(self, x: float, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Set x value of the center of the :class:`~.OpenGLMobject` (``int`` or ``float``)\"\"\"\n        return self.set_coord(x, 0, direction)\n\n    def set_y(self, y: float, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Set y value of the center of the :class:`~.OpenGLMobject` (``int`` or ``float``)\"\"\"\n        return self.set_coord(y, 1, direction)\n\n    def set_z(self, z: float, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Set z value of the center of the :class:`~.OpenGLMobject` (``int`` or ``float``)\"\"\"\n        return self.set_coord(z, 2, direction)\n\n    def space_out_submobjects(self, factor: float = 1.5, **kwargs: Any) -> Self:\n        self.scale(factor, **kwargs)\n        for submob in self.submobjects:\n            submob.scale(1.0 / factor)\n        return self\n\n    def move_to(\n        self,\n        point_or_mobject: Point3DLike | OpenGLMobject,\n        aligned_edge: Vector3DLike = ORIGIN,\n        coor_mask: Vector3DLike = np.array([1, 1, 1]),\n    ) -> Self:\n        \"\"\"Move center of the :class:`~.OpenGLMobject` to certain coordinate.\"\"\"\n        target: Point3DLike\n        if isinstance(point_or_mobject, OpenGLMobject):\n            target = point_or_mobject.get_bounding_box_point(aligned_edge)\n        else:\n            target = point_or_mobject\n        point_to_align = self.get_bounding_box_point(aligned_edge)\n        self.shift((target - point_to_align) * coor_mask)\n        return self\n\n    def replace(\n        self,\n        mobject: OpenGLMobject,\n        dim_to_match: int = 0,\n        stretch: bool = False,\n    ) -> Self:\n        if not mobject.get_num_points() and not mobject.submobjects:\n            self.scale(0)\n            return self\n        if stretch:\n            for i in range(self.dim):\n                self.rescale_to_fit(mobject.length_over_dim(i), i, stretch=True)\n        else:\n            self.rescale_to_fit(\n                mobject.length_over_dim(dim_to_match),\n                dim_to_match,\n                stretch=False,\n            )\n        self.shift(mobject.get_center() - self.get_center())\n        return self\n\n    def surround(\n        self,\n        mobject: OpenGLMobject,\n        dim_to_match: int = 0,\n        stretch: bool = False,\n        buff: float = MED_SMALL_BUFF,\n    ) -> Self:\n        self.replace(mobject, dim_to_match, stretch)\n        length = mobject.length_over_dim(dim_to_match)\n        self.scale((length + buff) / length)\n        return self\n\n    def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self:\n        curr_start, curr_end = self.get_start_and_end()\n        curr_vect = curr_end - curr_start\n        if np.all(curr_vect == 0):\n            raise Exception(\"Cannot position endpoints of closed loop\")\n        target_vect = np.array(end) - np.array(start)\n        axis = (\n            normalize(np.cross(curr_vect, target_vect))\n            if np.linalg.norm(np.cross(curr_vect, target_vect)) != 0\n            else OUT\n        )\n        self.scale(\n            float(np.linalg.norm(target_vect) / np.linalg.norm(curr_vect)),\n            about_point=curr_start,\n        )\n        self.rotate(\n            angle_between_vectors(curr_vect, target_vect),\n            about_point=curr_start,\n            axis=axis,\n        )\n        self.shift(start - curr_start)\n        return self\n\n    # Color functions\n\n    def set_rgba_array(\n        self,\n        color: ParsableManimColor | Iterable[ParsableManimColor] | None = None,\n        opacity: float | Iterable[float] | None = None,\n        name: str = \"rgbas\",\n        recurse: bool = True,\n    ) -> Self:\n        if color is not None:\n            rgbs: FloatRGB_Array = np.array([color_to_rgb(c) for c in listify(color)])\n        if opacity is not None:\n            opacities = listify(opacity)\n\n        # Color only\n        if color is not None and opacity is None:\n            for mob in self.get_family(recurse):\n                mob.data[name] = resize_array(\n                    mob.data[name] if name in mob.data else np.empty((1, 3)), len(rgbs)\n                )\n                mob.data[name][:, :3] = rgbs\n\n        # Opacity only\n        if color is None and opacity is not None:\n            for mob in self.get_family(recurse):\n                mob.data[name] = resize_array(\n                    mob.data[name] if name in mob.data else np.empty((1, 3)),\n                    len(opacities),\n                )\n                mob.data[name][:, 3] = opacities\n\n        # Color and opacity\n        if color is not None and opacity is not None:\n            rgbas: FloatRGBA_Array = np.array(\n                [[*rgb, o] for rgb, o in zip(*make_even(rgbs, opacities), strict=True)]\n            )\n            for mob in self.get_family(recurse):\n                mob.data[name] = rgbas.copy()\n        return self\n\n    def set_rgba_array_direct(\n        self,\n        rgbas: FloatRGBA_Array,\n        name: str = \"rgbas\",\n        recurse: bool = True,\n    ) -> Self:\n        \"\"\"Directly set rgba data from `rgbas` and optionally do the same recursively\n        with submobjects. This can be used if the `rgbas` have already been generated\n        with the correct shape and simply need to be set.\n\n        Parameters\n        ----------\n        rgbas\n            the rgba to be set as data\n        name\n            the name of the data attribute to be set\n        recurse\n            set to true to recursively apply this method to submobjects\n        \"\"\"\n        for mob in self.get_family(recurse):\n            mob.data[name] = rgbas.copy()\n        return self\n\n    def set_color(\n        self,\n        color: ParsableManimColor | Sequence[ParsableManimColor] | None,\n        opacity: float | Iterable[float] | None = None,\n        recurse: bool = True,\n    ) -> Self:\n        self.set_rgba_array(color, opacity, recurse=False)\n        # Recurse to submobjects differently from how set_rgba_array\n        # in case they implement set_color differently\n        if color is not None:\n            self.color = ManimColor.parse(color)\n        if opacity is not None:\n            self.opacity = opacity\n        if recurse:\n            for submob in self.submobjects:\n                submob.set_color(color, recurse=True)\n        return self\n\n    def set_opacity(\n        self, opacity: float | Iterable[float] | None, recurse: bool = True\n    ) -> Self:\n        self.set_rgba_array(color=None, opacity=opacity, recurse=False)\n        if recurse:\n            for submob in self.submobjects:\n                submob.set_opacity(opacity, recurse=True)\n        return self\n\n    def get_color(self) -> str:\n        return rgb_to_hex(self.rgbas[0, :3])\n\n    def get_opacity(self) -> float:\n        rv: float = self.rgbas[0, 3]\n        return rv\n\n    def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self:\n        return self.set_submobject_colors_by_gradient(*colors)\n\n    def set_submobject_colors_by_gradient(self, *colors: ParsableManimColor) -> Self:\n        if len(colors) == 0:\n            raise Exception(\"Need at least one color\")\n        elif len(colors) == 1:\n            return self.set_color(*colors)\n\n        # mobs = self.family_members_with_points()\n        mobs = self.submobjects\n        new_colors = color_gradient(colors, len(mobs))\n\n        for mob, color in zip(mobs, new_colors, strict=True):\n            mob.set_color(color)\n        return self\n\n    def fade(self, darkness: float = 0.5, recurse: bool = True) -> Self:\n        return self.set_opacity(1.0 - darkness, recurse=recurse)\n\n    def get_gloss(self) -> float:\n        return self.gloss\n\n    def set_gloss(self, gloss: float, recurse: bool = True) -> Self:\n        for mob in self.get_family(recurse):\n            mob.gloss = gloss\n        return self\n\n    def get_shadow(self) -> float:\n        return self.shadow\n\n    def set_shadow(self, shadow: float, recurse: bool = True) -> Self:\n        for mob in self.get_family(recurse):\n            mob.shadow = shadow\n        return self\n\n    # Background rectangle\n\n    def add_background_rectangle(\n        self,\n        color: ParsableManimColor | None = None,\n        opacity: float = 0.75,\n        **kwargs: Any,\n    ) -> Self:\n        # TODO, this does not behave well when the mobject has points,\n        # since it gets displayed on top\n        \"\"\"Add a BackgroundRectangle as submobject.\n\n        The BackgroundRectangle is added behind other submobjects.\n\n        This can be used to increase the mobjects visibility in front of a noisy background.\n\n        Parameters\n        ----------\n        color\n            The color of the BackgroundRectangle\n        opacity\n            The opacity of the BackgroundRectangle\n        kwargs\n            Additional keyword arguments passed to the BackgroundRectangle constructor\n\n\n        Returns\n        -------\n        :class:`OpenGLMobject`\n            ``self``\n\n        See Also\n        --------\n        :meth:`add_to_back`\n        :class:`~.BackgroundRectangle`\n\n        \"\"\"\n        from manim.mobject.geometry.shape_matchers import BackgroundRectangle\n\n        self.background_rectangle: BackgroundRectangle = BackgroundRectangle(\n            self,  # type: ignore[arg-type]\n            color=color,\n            fill_opacity=opacity,\n            **kwargs,\n        )\n        self.add_to_back(self.background_rectangle)  # type: ignore[arg-type]\n        return self\n\n    def add_background_rectangle_to_submobjects(self, **kwargs: Any) -> Self:\n        for submobject in self.submobjects:\n            submobject.add_background_rectangle(**kwargs)\n        return self\n\n    def add_background_rectangle_to_family_members_with_points(\n        self, **kwargs: Any\n    ) -> Self:\n        for mob in self.family_members_with_points():\n            mob.add_background_rectangle(**kwargs)\n        return self\n\n    # Getters\n\n    def get_bounding_box_point(self, direction: Vector3DLike) -> Point3D:\n        bb = self.get_bounding_box()\n        indices = (np.sign(direction) + 1).astype(int)\n        return np.array([bb[indices[i]][i] for i in range(3)])\n\n    def get_edge_center(self, direction: Vector3DLike) -> Point3D:\n        \"\"\"Get edge coordinates for certain direction.\"\"\"\n        return self.get_bounding_box_point(direction)\n\n    def get_corner(self, direction: Vector3DLike) -> Point3D:\n        \"\"\"Get corner coordinates for certain direction.\"\"\"\n        return self.get_bounding_box_point(direction)\n\n    def get_center(self) -> Point3D:\n        \"\"\"Get center coordinates.\"\"\"\n        return self.get_bounding_box()[1]\n\n    def get_center_of_mass(self) -> Point3D:\n        return self.get_all_points().mean(0)\n\n    def get_boundary_point(self, direction: Vector3DLike) -> Point3D:\n        all_points = self.get_all_points()\n        boundary_directions = all_points - self.get_center()\n        norms = np.linalg.norm(boundary_directions, axis=1)\n        boundary_directions /= np.repeat(norms, 3).reshape((len(norms), 3))\n        index = np.argmax(np.dot(boundary_directions, direction))\n        return all_points[index]\n\n    def get_continuous_bounding_box_point(self, direction: Vector3DLike) -> Point3D:\n        _dl, center, ur = self.get_bounding_box()\n        corner_vect = ur - center\n        np_direction = np.asarray(direction)\n        return center + np_direction / np.max(\n            np.abs(\n                np.true_divide(\n                    np_direction,\n                    corner_vect,\n                    out=np.zeros(len(np_direction)),\n                    where=((corner_vect) != 0),\n                ),\n            ),\n        )\n\n    def get_top(self) -> Point3D:\n        \"\"\"Get top coordinates of a box bounding the :class:`~.OpenGLMobject`\"\"\"\n        return self.get_edge_center(UP)\n\n    def get_bottom(self) -> Point3D:\n        \"\"\"Get bottom coordinates of a box bounding the :class:`~.OpenGLMobject`\"\"\"\n        return self.get_edge_center(DOWN)\n\n    def get_right(self) -> Point3D:\n        \"\"\"Get right coordinates of a box bounding the :class:`~.OpenGLMobject`\"\"\"\n        return self.get_edge_center(RIGHT)\n\n    def get_left(self) -> Point3D:\n        \"\"\"Get left coordinates of a box bounding the :class:`~.OpenGLMobject`\"\"\"\n        return self.get_edge_center(LEFT)\n\n    def get_zenith(self) -> Point3D:\n        \"\"\"Get zenith coordinates of a box bounding a 3D :class:`~.OpenGLMobject`.\"\"\"\n        return self.get_edge_center(OUT)\n\n    def get_nadir(self) -> Point3D:\n        \"\"\"Get nadir (opposite the zenith) coordinates of a box bounding a 3D :class:`~.OpenGLMobject`.\"\"\"\n        return self.get_edge_center(IN)\n\n    def length_over_dim(self, dim: int) -> float:\n        bb = self.get_bounding_box()\n        rv: float = abs((bb[2] - bb[0])[dim])\n        return rv\n\n    def get_width(self) -> float:\n        \"\"\"Returns the width of the mobject.\"\"\"\n        return self.length_over_dim(0)\n\n    def get_height(self) -> float:\n        \"\"\"Returns the height of the mobject.\"\"\"\n        return self.length_over_dim(1)\n\n    def get_depth(self) -> float:\n        \"\"\"Returns the depth of the mobject.\"\"\"\n        return self.length_over_dim(2)\n\n    def get_coord(self, dim: int, direction: Vector3DLike = ORIGIN) -> ManimFloat:\n        \"\"\"Meant to generalize ``get_x``, ``get_y`` and ``get_z``\"\"\"\n        return self.get_bounding_box_point(direction)[dim]\n\n    def get_x(self, direction: Vector3DLike = ORIGIN) -> ManimFloat:\n        \"\"\"Returns x coordinate of the center of the :class:`~.OpenGLMobject` as ``float``\"\"\"\n        return self.get_coord(0, direction)\n\n    def get_y(self, direction: Vector3DLike = ORIGIN) -> ManimFloat:\n        \"\"\"Returns y coordinate of the center of the :class:`~.OpenGLMobject` as ``float``\"\"\"\n        return self.get_coord(1, direction)\n\n    def get_z(self, direction: Vector3DLike = ORIGIN) -> ManimFloat:\n        \"\"\"Returns z coordinate of the center of the :class:`~.OpenGLMobject` as ``float``\"\"\"\n        return self.get_coord(2, direction)\n\n    def get_start(self) -> Point3D:\n        \"\"\"Returns the point, where the stroke that surrounds the :class:`~.OpenGLMobject` starts.\"\"\"\n        self.throw_error_if_no_points()\n        return np.array(self.points[0])\n\n    def get_end(self) -> Point3D:\n        \"\"\"Returns the point, where the stroke that surrounds the :class:`~.OpenGLMobject` ends.\"\"\"\n        self.throw_error_if_no_points()\n        return np.array(self.points[-1])\n\n    def get_start_and_end(self) -> tuple[Point3D, Point3D]:\n        \"\"\"Returns starting and ending point of a stroke as a ``tuple``.\"\"\"\n        return self.get_start(), self.get_end()\n\n    def point_from_proportion(self, alpha: float) -> Point3D:\n        points = self.points\n        i, subalpha = integer_interpolate(0, len(points) - 1, alpha)\n        return interpolate(points[i], points[i + 1], subalpha)\n\n    def pfp(self, alpha: float) -> Point3D:\n        \"\"\"Abbreviation for point_from_proportion\"\"\"\n        return self.point_from_proportion(alpha)\n\n    def get_pieces(self, n_pieces: int) -> OpenGLMobject:\n        template = self.copy()\n        template.submobjects = []\n        alphas = np.linspace(0, 1, n_pieces + 1)\n        return OpenGLGroup(\n            *(\n                template.copy().pointwise_become_partial(self, a1, a2)\n                for a1, a2 in zip(alphas[:-1], alphas[1:], strict=True)\n            )\n        )\n\n    def get_z_index_reference_point(self) -> Point3D:\n        # TODO, better place to define default z_index_group?\n        z_index_group = getattr(self, \"z_index_group\", self)\n        return z_index_group.get_center()\n\n    # Match other mobject properties\n\n    def match_color(self, mobject: OpenGLMobject) -> Self:\n        \"\"\"Match the color with the color of another :class:`~.OpenGLMobject`.\"\"\"\n        return self.set_color(mobject.get_color())\n\n    def match_dim_size(\n        self,\n        mobject: OpenGLMobject,\n        dim: int,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Match the specified dimension with the dimension of another :class:`~.OpenGLMobject`.\"\"\"\n        return self.rescale_to_fit(mobject.length_over_dim(dim), dim, **kwargs)\n\n    def match_width(self, mobject: OpenGLMobject, **kwargs: Any) -> Self:\n        \"\"\"Match the width with the width of another :class:`~.OpenGLMobject`.\"\"\"\n        return self.match_dim_size(mobject, 0, **kwargs)\n\n    def match_height(self, mobject: OpenGLMobject, **kwargs: Any) -> Self:\n        \"\"\"Match the height with the height of another :class:`~.OpenGLMobject`.\"\"\"\n        return self.match_dim_size(mobject, 1, **kwargs)\n\n    def match_depth(self, mobject: OpenGLMobject, **kwargs: Any) -> Self:\n        \"\"\"Match the depth with the depth of another :class:`~.OpenGLMobject`.\"\"\"\n        return self.match_dim_size(mobject, 2, **kwargs)\n\n    def match_coord(\n        self, mobject: OpenGLMobject, dim: int, direction: Vector3DLike = ORIGIN\n    ) -> Self:\n        \"\"\"Match the coordinates with the coordinates of another :class:`~.OpenGLMobject`.\"\"\"\n        return self.set_coord(\n            mobject.get_coord(dim, direction),\n            dim=dim,\n            direction=direction,\n        )\n\n    def match_x(self, mobject: OpenGLMobject, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Match x coord. to the x coord. of another :class:`~.OpenGLMobject`.\"\"\"\n        return self.match_coord(mobject, 0, direction)\n\n    def match_y(self, mobject: OpenGLMobject, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Match y coord. to the x coord. of another :class:`~.OpenGLMobject`.\"\"\"\n        return self.match_coord(mobject, 1, direction)\n\n    def match_z(self, mobject: OpenGLMobject, direction: Vector3DLike = ORIGIN) -> Self:\n        \"\"\"Match z coord. to the x coord. of another :class:`~.OpenGLMobject`.\"\"\"\n        return self.match_coord(mobject, 2, direction)\n\n    def align_to(\n        self,\n        mobject_or_point: OpenGLMobject | Point3DLike,\n        direction: Vector3DLike = ORIGIN,\n    ) -> Self:\n        \"\"\"\n        Examples:\n        mob1.align_to(mob2, UP) moves mob1 vertically so that its\n        top edge lines ups with mob2's top edge.\n\n        mob1.align_to(mob2, alignment_vect = RIGHT) moves mob1\n        horizontally so that it's center is directly above/below\n        the center of mob2\n        \"\"\"\n        point: Point3DLike\n        if isinstance(mobject_or_point, OpenGLMobject):\n            point = mobject_or_point.get_bounding_box_point(direction)\n        else:\n            point = mobject_or_point\n\n        for dim in range(self.dim):\n            if direction[dim] != 0:\n                self.set_coord(point[dim], dim, direction)\n        return self\n\n    def get_group_class(self) -> type[OpenGLGroup]:\n        return OpenGLGroup\n\n    @staticmethod\n    def get_mobject_type_class() -> type[OpenGLMobject]:\n        \"\"\"Return the base class of this mobject type.\"\"\"\n        return OpenGLMobject\n\n    # Alignment\n\n    def align_data_and_family(self, mobject: OpenGLMobject) -> Self:\n        self.align_family(mobject)\n        self.align_data(mobject)\n        return self\n\n    def align_data(self, mobject: OpenGLMobject) -> Self:\n        # In case any data arrays get resized when aligned to shader data\n        # self.refresh_shader_data()\n        for mob1, mob2 in zip(self.get_family(), mobject.get_family(), strict=False):\n            # Separate out how points are treated so that subclasses\n            # can handle that case differently if they choose\n            mob1.align_points(mob2)\n            for key in mob1.data.keys() & mob2.data.keys():\n                if key == \"points\":\n                    continue\n                arr1 = mob1.data[key]\n                arr2 = mob2.data[key]\n                if len(arr2) > len(arr1):\n                    mob1.data[key] = resize_preserving_order(arr1, len(arr2))\n                elif len(arr1) > len(arr2):\n                    mob2.data[key] = resize_preserving_order(arr2, len(arr1))\n        return self\n\n    def align_points(self, mobject: OpenGLMobject) -> Self:\n        max_len = max(self.get_num_points(), mobject.get_num_points())\n        for mob in (self, mobject):\n            mob.resize_points(max_len, resize_func=resize_preserving_order)\n        return self\n\n    def align_family(self, mobject: OpenGLMobject) -> Self:\n        mob1 = self\n        mob2 = mobject\n        n1 = len(mob1)\n        n2 = len(mob2)\n        if n1 != n2:\n            mob1.add_n_more_submobjects(max(0, n2 - n1))\n            mob2.add_n_more_submobjects(max(0, n1 - n2))\n        # Recurse\n        for sm1, sm2 in zip(mob1.submobjects, mob2.submobjects, strict=True):\n            sm1.align_family(sm2)\n        return self\n\n    def push_self_into_submobjects(self) -> Self:\n        copy = self.deepcopy()\n        copy.submobjects = []\n        self.resize_points(0)\n        self.add(copy)\n        return self\n\n    def add_n_more_submobjects(self, n: int) -> Self:\n        if n == 0:\n            return self\n\n        curr = len(self.submobjects)\n        if curr == 0:\n            # If empty, simply add n point mobjects\n            null_mob = self.copy()\n            null_mob.set_points([self.get_center()])\n            self.submobjects = [null_mob.copy() for k in range(n)]\n            return self\n        target = curr + n\n        repeat_indices = (np.arange(target) * curr) // target\n        split_factors = [(repeat_indices == i).sum() for i in range(curr)]\n        new_submobs = []\n        for submob, sf in zip(self.submobjects, split_factors, strict=True):\n            new_submobs.append(submob)\n            for _ in range(1, sf):\n                new_submob = submob.copy()\n                # If the submobject is at all transparent, then\n                # make the copy completely transparent\n                if submob.get_opacity() < 1:\n                    new_submob.set_opacity(0)\n                new_submobs.append(new_submob)\n        self.submobjects = new_submobs\n        return self\n\n    # Interpolate\n\n    def interpolate(\n        self,\n        mobject1: OpenGLMobject,\n        mobject2: OpenGLMobject,\n        alpha: float,\n        path_func: PathFuncType = straight_path(),\n    ) -> Self:\n        \"\"\"Turns this :class:`~.OpenGLMobject` into an interpolation between ``mobject1``\n        and ``mobject2``.\n\n        Examples\n        --------\n\n        .. manim:: DotInterpolation\n            :save_last_frame:\n\n            class DotInterpolation(Scene):\n                def construct(self):\n                    dotR = Dot(color=DARK_GREY)\n                    dotR.shift(2 * RIGHT)\n                    dotL = Dot(color=WHITE)\n                    dotL.shift(2 * LEFT)\n\n                    dotMiddle = OpenGLVMobject().interpolate(dotL, dotR, alpha=0.3)\n\n                    self.add(dotL, dotR, dotMiddle)\n        \"\"\"\n        for key in self.data:\n            if key in self.locked_data_keys:\n                continue\n            if len(self.data[key]) == 0:\n                continue\n            if key not in mobject1.data or key not in mobject2.data:\n                continue\n\n            func = path_func if key in (\"points\", \"bounding_box\") else interpolate\n\n            self.data[key][:] = func(mobject1.data[key], mobject2.data[key], alpha)\n\n        for key in self.uniforms:\n            if key != \"fixed_orientation_center\":\n                self.uniforms[key] = interpolate(\n                    mobject1.uniforms[key],\n                    mobject2.uniforms[key],\n                    alpha,\n                )\n            else:\n                self.uniforms[\"fixed_orientation_center\"] = tuple(\n                    interpolate(\n                        np.array(mobject1.uniforms[\"fixed_orientation_center\"]),\n                        np.array(mobject2.uniforms[\"fixed_orientation_center\"]),\n                        alpha,\n                    )\n                )\n        return self\n\n    def pointwise_become_partial(\n        self, mobject: OpenGLMobject, a: float, b: float\n    ) -> Self:\n        \"\"\"\n        Set points in such a way as to become only\n        part of mobject.\n        Inputs 0 <= a < b <= 1 determine what portion\n        of mobject to become.\n\n        Returns `self` to allow method chaining.\n        \"\"\"\n        return self  # To implement in subclass\n\n    def become(\n        self,\n        mobject: OpenGLMobject,\n        match_height: bool = False,\n        match_width: bool = False,\n        match_depth: bool = False,\n        match_center: bool = False,\n        stretch: bool = False,\n    ) -> Self:\n        \"\"\"Edit all data and submobjects to be identical\n        to another :class:`~.OpenGLMobject`\n\n        .. note::\n\n            If both match_height and match_width are ``True`` then the transformed :class:`~.OpenGLMobject`\n            will match the height first and then the width\n\n        Parameters\n        ----------\n        match_height\n            If ``True``, then the transformed :class:`~.OpenGLMobject` will match the height of the original\n        match_width\n            If ``True``, then the transformed :class:`~.OpenGLMobject` will match the width of the original\n        match_depth\n            If ``True``, then the transformed :class:`~.OpenGLMobject` will match the depth of the original\n        match_center\n            If ``True``, then the transformed :class:`~.OpenGLMobject` will match the center of the original\n        stretch\n            If ``True``, then the transformed :class:`~.OpenGLMobject` will stretch to fit the proportions of the original\n\n        Examples\n        --------\n        .. manim:: BecomeScene\n\n            class BecomeScene(Scene):\n                def construct(self):\n                    circ = Circle(fill_color=RED, fill_opacity=0.8)\n                    square = Square(fill_color=BLUE, fill_opacity=0.2)\n                    self.add(circ)\n                    self.wait(0.5)\n                    circ.become(square)\n                    self.wait(0.5)\n        \"\"\"\n        if stretch:\n            mobject.stretch_to_fit_height(self.height)\n            mobject.stretch_to_fit_width(self.width)\n            mobject.stretch_to_fit_depth(self.depth)\n        else:\n            if match_height:\n                mobject.match_height(self)\n            if match_width:\n                mobject.match_width(self)\n            if match_depth:\n                mobject.match_depth(self)\n\n        if match_center:\n            mobject.move_to(self.get_center())\n\n        self.align_family(mobject)\n        for sm1, sm2 in zip(self.get_family(), mobject.get_family(), strict=True):\n            sm1.set_data(sm2.data)\n            sm1.set_uniforms(sm2.uniforms)\n        self.refresh_bounding_box(recurse_down=True)\n        return self\n\n    # Locking data\n\n    def lock_data(self, keys: Iterable[str]) -> None:\n        \"\"\"\n        To speed up some animations, particularly transformations,\n        it can be handy to acknowledge which pieces of data\n        won't change during the animation so that calls to\n        interpolate can skip this, and so that it's not\n        read into the shader_wrapper objects needlessly\n        \"\"\"\n        if self.has_updaters:\n            return\n        # Be sure shader data has most up to date information\n        self.refresh_shader_data()\n        self.locked_data_keys = set(keys)\n\n    def lock_matching_data(\n        self, mobject1: OpenGLMobject, mobject2: OpenGLMobject\n    ) -> Self:\n        for sm, sm1, sm2 in zip(\n            self.get_family(),\n            mobject1.get_family(),\n            mobject2.get_family(),\n            strict=False,\n        ):\n            keys = sm.data.keys() & sm1.data.keys() & sm2.data.keys()\n            sm.lock_data(\n                list(\n                    filter(\n                        lambda key: np.all(sm1.data[key] == sm2.data[key]),\n                        keys,\n                    ),\n                ),\n            )\n        return self\n\n    def unlock_data(self) -> None:\n        for mob in self.get_family():\n            mob.locked_data_keys = set()\n\n    # Operations touching shader uniforms\n\n    @affects_shader_info_id\n    def fix_in_frame(self) -> Self:\n        self.is_fixed_in_frame = 1.0\n        return self\n\n    @affects_shader_info_id\n    def fix_orientation(self) -> Self:\n        self.is_fixed_orientation = 1.0\n        self.fixed_orientation_center = tuple(self.get_center())\n        self.depth_test = True\n        return self\n\n    @affects_shader_info_id\n    def unfix_from_frame(self) -> Self:\n        self.is_fixed_in_frame = 0.0\n        return self\n\n    @affects_shader_info_id\n    def unfix_orientation(self) -> Self:\n        self.is_fixed_orientation = 0.0\n        self.fixed_orientation_center = (0, 0, 0)\n        self.depth_test = False\n        return self\n\n    @affects_shader_info_id\n    def apply_depth_test(self) -> Self:\n        self.depth_test = True\n        return self\n\n    @affects_shader_info_id\n    def deactivate_depth_test(self) -> Self:\n        self.depth_test = False\n        return self\n\n    # Shader code manipulation\n\n    def replace_shader_code(self, old_code: str, new_code: str) -> Self:\n        # TODO, will this work with VMobject structure, given\n        # that it does not simpler return shader_wrappers of\n        # family?\n        for wrapper in self.get_shader_wrapper_list():\n            wrapper.replace_code(old_code, new_code)\n        return self\n\n    def set_color_by_code(self, glsl_code: str) -> Self:\n        \"\"\"\n        Takes a snippet of code and inserts it into a\n        context which has the following variables:\n        vec4 color, vec3 point, vec3 unit_normal.\n        The code should change the color variable\n        \"\"\"\n        self.replace_shader_code(\"///// INSERT COLOR FUNCTION HERE /////\", glsl_code)\n        return self\n\n    def set_color_by_xyz_func(\n        self,\n        glsl_snippet: str,\n        min_value: float = -5.0,\n        max_value: float = 5.0,\n        colormap: str = \"viridis\",\n    ) -> Self:\n        \"\"\"\n        Pass in a glsl expression in terms of x, y and z which returns\n        a float.\n        \"\"\"\n        # TODO, add a version of this which changes the point data instead\n        # of the shader code\n        for char in \"xyz\":\n            glsl_snippet = glsl_snippet.replace(char, \"point.\" + char)\n        # TODO: get_colormap_list does not exist\n        #   See https://github.com/ManimCommunity/manim/issues/4176\n        rgb_list = get_colormap_list(colormap)  # type: ignore[name-defined]\n        self.set_color_by_code(\n            f\"color.rgb = float_to_color({glsl_snippet}, {float(min_value)}, {float(max_value)}, {get_colormap_code(rgb_list)});\",\n        )\n        return self\n\n    # For shader data\n\n    def refresh_shader_wrapper_id(self) -> Self:\n        self.get_shader_wrapper().refresh_id()\n        return self\n\n    def get_shader_wrapper(self) -> \"ShaderWrapper\":  # noqa: UP037\n        from manim.renderer.shader_wrapper import ShaderWrapper\n\n        # if hasattr(self, \"shader_wrapper\"):\n        #     return self.shader_wrapper\n\n        self.shader_wrapper: ShaderWrapper = ShaderWrapper(\n            vert_data=self.get_shader_data(),\n            vert_indices=self.get_shader_vert_indices(),\n            uniforms=self.get_shader_uniforms(),\n            depth_test=self.depth_test,\n            texture_paths=self.texture_paths,\n            render_primitive=self.render_primitive,\n            shader_folder=self.__class__.shader_folder,\n        )\n        return self.shader_wrapper\n\n    def get_shader_wrapper_list(self) -> Sequence[\"ShaderWrapper\"]:  # noqa: UP037\n        shader_wrappers = it.chain(\n            [self.get_shader_wrapper()],\n            *(sm.get_shader_wrapper_list() for sm in self.submobjects),\n        )\n        batches = batch_by_property(shader_wrappers, lambda sw: sw.get_id())\n\n        result: list[\"ShaderWrapper\"] = []  # noqa: UP037\n        for wrapper_group, _ in batches:\n            shader_wrapper = wrapper_group[0]\n            if not shader_wrapper.is_valid():\n                continue\n            shader_wrapper.combine_with(*wrapper_group[1:])\n            if len(shader_wrapper.vert_data) > 0:\n                result.append(shader_wrapper)\n        return result\n\n    def check_data_alignment(self, array: _ShaderData, data_key: str) -> Self:\n        # Makes sure that self.data[key] can be broadcast into\n        # the given array, meaning its length has to be either 1\n        # or the length of the array\n        d_len = len(self.data[data_key])\n        if d_len != 1 and d_len != len(array):\n            self.data[data_key] = resize_with_interpolation(\n                self.data[data_key],\n                len(array),\n            )\n        return self\n\n    def get_resized_shader_data_array(self, length: float) -> _ShaderData:\n        # If possible, try to populate an existing array, rather\n        # than recreating it each frame\n        points = self.points\n        shader_data = cast(_ShaderData, np.zeros(len(points), dtype=self.shader_dtype))\n        return shader_data\n\n    def read_data_to_shader(\n        self,\n        shader_data: _ShaderData,  # has structured data type, ex. (\"point\", np.float32, (3,))\n        shader_data_key: str,\n        data_key: str,\n    ) -> None:\n        if data_key in self.locked_data_keys:\n            return\n        self.check_data_alignment(shader_data, data_key)\n        shader_data[shader_data_key] = self.data[data_key]\n\n    def get_shader_data(self) -> _ShaderData:\n        shader_data = self.get_resized_shader_data_array(self.get_num_points())\n        self.read_data_to_shader(shader_data, \"point\", \"points\")\n        return shader_data\n\n    def refresh_shader_data(self) -> None:\n        self.get_shader_data()\n\n    def get_shader_uniforms(self) -> dict[str, Any]:\n        return self.uniforms\n\n    def get_shader_vert_indices(self) -> Sequence[int] | None:\n        return self.shader_indices\n\n    @property\n    def submobjects(self) -> list[OpenGLMobject]:\n        return self._submobjects if hasattr(self, \"_submobjects\") else []\n\n    @submobjects.setter\n    def submobjects(self, submobject_list: Iterable[OpenGLMobject]) -> None:\n        self.remove(*self.submobjects)\n        self.add(*submobject_list)\n\n    # Errors\n\n    def throw_error_if_no_points(self) -> None:\n        if not self.has_points():\n            message = (\n                \"Cannot call OpenGLMobject.{} \" + \"for a OpenGLMobject with no points\"\n            )\n            caller_name = sys._getframe(1).f_code.co_name\n            raise Exception(message.format(caller_name))\n\n\nclass OpenGLGroup(OpenGLMobject):\n    def __init__(self, *mobjects: OpenGLMobject, **kwargs: Any) -> None:\n        super().__init__(**kwargs)\n        self.add(*mobjects)\n\n\nclass OpenGLPoint(OpenGLMobject):\n    def __init__(\n        self,\n        location: Point3DLike = ORIGIN,\n        artificial_width: float = 1e-6,\n        artificial_height: float = 1e-6,\n        **kwargs: Any,\n    ) -> None:\n        self.artificial_width: float = artificial_width\n        self.artificial_height: float = artificial_height\n        super().__init__(**kwargs)\n        self.set_location(location)\n\n    @override\n    def get_width(self) -> float:\n        return self.artificial_width\n\n    @override\n    def get_height(self) -> float:\n        return self.artificial_height\n\n    def get_location(self) -> Point3D:\n        return cast(\"Point3D\", self.points[0]).copy()\n\n    @override\n    def get_bounding_box_point(self, *args: object, **kwargs: Any) -> Point3D:\n        return self.get_location()\n\n    def set_location(self, new_loc: Point3DLike) -> None:\n        self.set_points(np.array(new_loc, ndmin=2, dtype=float))\n\n\nclass _AnimationBuilder:\n    def __init__(self, mobject: OpenGLMobject) -> None:\n        self.mobject: OpenGLMobject = mobject\n        self.mobject.generate_target()\n\n        self.overridden_animation: Animation | None = None\n        self.is_chaining: bool = False\n        self.methods: list[MethodWithArgs] = []\n\n        # Whether animation args can be passed\n        self.cannot_pass_args: bool = False\n        self.anim_args: dict[str, object] = {}\n\n    def __call__(self, **kwargs: Any) -> Self:\n        if self.cannot_pass_args:\n            raise ValueError(\n                \"Animation arguments must be passed before accessing methods and can only be passed once\",\n            )\n\n        self.anim_args = kwargs\n        self.cannot_pass_args = True\n\n        return self\n\n    def __getattr__(self, method_name: str) -> Callable[..., Self]:\n        method = getattr(self.mobject.target, method_name)\n        has_overridden_animation = hasattr(method, \"_override_animate\")\n\n        if (self.is_chaining and has_overridden_animation) or self.overridden_animation:\n            raise NotImplementedError(\n                \"Method chaining is currently not supported for overridden animations\",\n            )\n\n        # NOTE: using `Self` here should not be a problem, because it's equivalent to a `TypeVar` introduced in `__getattr__`.\n        #   For this reason, here it's still in scope and can be used (that's why pyright does not flag this as an error).\n        #   However, mypy currently does not seem to understand this: hence the `type: ignore` comment.\n        def update_target(*method_args: object, **method_kwargs: object) -> Self:  # type: ignore[type-var, misc]\n            if has_overridden_animation:\n                self.overridden_animation = cast(\n                    \"Callable[..., Animation]\", method._override_animate\n                )(\n                    self.mobject,\n                    *method_args,\n                    anim_args=self.anim_args,\n                    **method_kwargs,\n                )\n            else:\n                self.methods.append(MethodWithArgs(method, method_args, method_kwargs))\n                method(*method_args, **method_kwargs)\n            return self\n\n        self.is_chaining = True\n        self.cannot_pass_args = True\n\n        return update_target\n\n    def build(self) -> \"Animation\":  # noqa: UP037\n        from manim.animation.transform import _MethodAnimation\n\n        # NOTE: To fix this mypy error, we'll need to update `_MethodAnimation` to accept `Mobject | OpenGLMobject` instead of `Mobject`.\n        #   Once that is done, the `type: ignore` comment below won't be necessary anymore and mypy will emit a corresponding warning.\n        anim = self.overridden_animation or _MethodAnimation(self.mobject, self.methods)  # type: ignore[arg-type]\n\n        for attr, value in self.anim_args.items():\n            setattr(anim, attr, value)\n\n        return anim\n\n\n_Decorated = TypeVar(\"_Decorated\", bound=Callable[..., \"Animation\"])\n\n\nclass _OverrideAnimateDecorator(Protocol):\n    # The slash divider on the next line prevents a mypy error in line 3176.\n    def __call__(self, decorated: _Decorated, /) -> _Decorated: ...\n\n\ndef override_animate(method: types.FunctionType) -> _OverrideAnimateDecorator:\n    r\"\"\"Decorator for overriding method animations.\n\n    This allows to specify a method (returning an :class:`~.Animation`)\n    which is called when the decorated method is used with the ``.animate`` syntax\n    for animating the application of a method.\n\n    .. seealso::\n\n        :attr:`OpenGLMobject.animate`\n\n    .. note::\n\n        Overridden methods cannot be combined with normal or other overridden\n        methods using method chaining with the ``.animate`` syntax.\n\n\n    Examples\n    --------\n\n    .. manim:: AnimationOverrideExample\n\n        class CircleWithContent(VGroup):\n            def __init__(self, content):\n                super().__init__()\n                self.circle = Circle()\n                self.content = content\n                self.add(self.circle, content)\n                content.move_to(self.circle.get_center())\n\n            def clear_content(self):\n                self.remove(self.content)\n                self.content = None\n\n            @override_animate(clear_content)\n            def _clear_content_animation(self, anim_args=None):\n                if anim_args is None:\n                    anim_args = {}\n                anim = Uncreate(self.content, **anim_args)\n                self.clear_content()\n                return anim\n\n        class AnimationOverrideExample(Scene):\n            def construct(self):\n                t = Text(\"hello!\")\n                my_mobject = CircleWithContent(t)\n                self.play(Create(my_mobject))\n                self.play(my_mobject.animate.clear_content())\n                self.wait()\n\n    \"\"\"\n\n    def decorator(animation_method: _Decorated) -> _Decorated:\n        method._override_animate = animation_method  # type: ignore[attr-defined]\n        return animation_method\n\n    return decorator\n"
  },
  {
    "path": "manim/mobject/opengl/opengl_point_cloud_mobject.py",
    "content": "from __future__ import annotations\n\n__all__ = [\"OpenGLPMobject\", \"OpenGLPGroup\", \"OpenGLPMPoint\"]\n\nfrom typing import TYPE_CHECKING\n\nimport moderngl\nimport numpy as np\n\nfrom manim.constants import *\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.utils.bezier import interpolate\nfrom manim.utils.color import (\n    BLACK,\n    PURE_YELLOW,\n    WHITE,\n    ParsableManimColor,\n    color_gradient,\n    color_to_rgba,\n)\nfrom manim.utils.config_ops import _Uniforms\nfrom manim.utils.iterables import resize_with_interpolation\n\nif TYPE_CHECKING:\n    from typing import Self\n\n    from manim.typing import (\n        FloatRGBA_Array,\n        FloatRGBALike_Array,\n        Point3D_Array,\n        Point3DLike_Array,\n    )\n\n__all__ = [\"OpenGLPMobject\", \"OpenGLPGroup\", \"OpenGLPMPoint\"]\n\n\nclass OpenGLPMobject(OpenGLMobject):\n    shader_folder = \"true_dot\"\n    # Scale for consistency with cairo units\n    OPENGL_POINT_RADIUS_SCALE_FACTOR = 0.01\n    shader_dtype = [\n        (\"point\", np.float32, (3,)),\n        (\"color\", np.float32, (4,)),\n    ]\n\n    point_radius = _Uniforms()\n\n    def __init__(\n        self,\n        stroke_width: float = 2.0,\n        color: ParsableManimColor = PURE_YELLOW,\n        render_primitive: int = moderngl.POINTS,\n        **kwargs,\n    ):\n        self.stroke_width = stroke_width\n        super().__init__(color=color, render_primitive=render_primitive, **kwargs)\n        self.point_radius = (\n            self.stroke_width * OpenGLPMobject.OPENGL_POINT_RADIUS_SCALE_FACTOR\n        )\n\n    def reset_points(self) -> Self:\n        self.rgbas: FloatRGBA_Array = np.zeros((1, 4))\n        self.points: Point3D_Array = np.zeros((0, 3))\n        return self\n\n    def get_array_attrs(self):\n        return [\"points\", \"rgbas\"]\n\n    def add_points(\n        self,\n        points: Point3DLike_Array,\n        rgbas: FloatRGBALike_Array | None = None,\n        color: ParsableManimColor | None = None,\n        opacity: float | None = None,\n    ) -> Self:\n        \"\"\"Add points.\n\n        Points must be a Nx3 numpy array.\n        Rgbas must be a Nx4 numpy array if it is not None.\n        \"\"\"\n        if rgbas is None and color is None:\n            color = PURE_YELLOW\n        self.append_points(points)\n        # rgbas array will have been resized with points\n        if color is not None:\n            if opacity is None:\n                opacity = self.rgbas[-1, 3]\n            new_rgbas = np.repeat([color_to_rgba(color, opacity)], len(points), axis=0)\n        elif rgbas is not None:\n            new_rgbas = rgbas\n        elif len(rgbas) != len(points):\n            raise ValueError(\"points and rgbas must have same length\")\n        self.rgbas = np.append(self.rgbas, new_rgbas, axis=0)\n        return self\n\n    def thin_out(self, factor=5):\n        \"\"\"Removes all but every nth point for n = factor\"\"\"\n        for mob in self.family_members_with_points():\n            num_points = mob.get_num_points()\n\n            def thin_func(num_points=num_points):\n                return np.arange(0, num_points, factor)\n\n            if len(mob.points) == len(mob.rgbas):\n                mob.set_rgba_array_direct(mob.rgbas[thin_func()])\n            mob.set_points(mob.points[thin_func()])\n\n        return self\n\n    def set_color_by_gradient(self, *colors):\n        self.rgbas = np.array(\n            list(map(color_to_rgba, color_gradient(*colors, self.get_num_points()))),\n        )\n        return self\n\n    def set_colors_by_radial_gradient(\n        self,\n        center=None,\n        radius=1,\n        inner_color=WHITE,\n        outer_color=BLACK,\n    ):\n        start_rgba, end_rgba = list(map(color_to_rgba, [inner_color, outer_color]))\n        if center is None:\n            center = self.get_center()\n        for mob in self.family_members_with_points():\n            distances = np.abs(self.points - center)\n            alphas = np.linalg.norm(distances, axis=1) / radius\n\n            mob.rgbas = np.array(\n                np.array(\n                    [interpolate(start_rgba, end_rgba, alpha) for alpha in alphas],\n                ),\n            )\n        return self\n\n    def match_colors(self, pmobject):\n        self.rgbas[:] = resize_with_interpolation(pmobject.rgbas, self.get_num_points())\n        return self\n\n    def fade_to(self, color, alpha, family=True):\n        rgbas = interpolate(self.rgbas, color_to_rgba(color), alpha)\n        for mob in self.submobjects:\n            mob.fade_to(color, alpha, family)\n        self.set_rgba_array_direct(rgbas)\n        return self\n\n    def filter_out(self, condition):\n        for mob in self.family_members_with_points():\n            to_keep = ~np.apply_along_axis(condition, 1, mob.points)\n            for key in mob.data:\n                mob.data[key] = mob.data[key][to_keep]\n        return self\n\n    def sort_points(self, function=lambda p: p[0]):\n        \"\"\"function is any map from R^3 to R\"\"\"\n        for mob in self.family_members_with_points():\n            indices = np.argsort(np.apply_along_axis(function, 1, mob.points))\n            for key in mob.data:\n                mob.data[key] = mob.data[key][indices]\n        return self\n\n    def ingest_submobjects(self):\n        for key in self.data:\n            self.data[key] = np.vstack([sm.data[key] for sm in self.get_family()])\n        return self\n\n    def point_from_proportion(self, alpha):\n        index = alpha * (self.get_num_points() - 1)\n        return self.points[int(index)]\n\n    def pointwise_become_partial(self, pmobject, a, b):\n        lower_index = int(a * pmobject.get_num_points())\n        upper_index = int(b * pmobject.get_num_points())\n        for key in self.data:\n            self.data[key] = pmobject.data[key][lower_index:upper_index]\n        return self\n\n    def get_shader_data(self):\n        shader_data = np.zeros(len(self.points), dtype=self.shader_dtype)\n        self.read_data_to_shader(shader_data, \"point\", \"points\")\n        self.read_data_to_shader(shader_data, \"color\", \"rgbas\")\n        return shader_data\n\n    @staticmethod\n    def get_mobject_type_class():\n        return OpenGLPMobject\n\n\nclass OpenGLPGroup(OpenGLPMobject):\n    def __init__(self, *pmobs, **kwargs):\n        if not all(isinstance(m, OpenGLPMobject) for m in pmobs):\n            raise Exception(\"All submobjects must be of type OpenglPMObject\")\n        super().__init__(**kwargs)\n        self.add(*pmobs)\n\n    def fade_to(self, color, alpha, family=True):\n        if family:\n            for mob in self.submobjects:\n                mob.fade_to(color, alpha, family)\n\n\nclass OpenGLPMPoint(OpenGLPMobject):\n    def __init__(self, location=ORIGIN, stroke_width=4.0, **kwargs):\n        self.location = location\n        super().__init__(stroke_width=stroke_width, **kwargs)\n\n    def init_points(self):\n        self.points = np.array([self.location], dtype=np.float32)\n"
  },
  {
    "path": "manim/mobject/opengl/opengl_surface.py",
    "content": "from __future__ import annotations\n\nfrom collections.abc import Iterable\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING\n\nimport moderngl\nimport numpy as np\nfrom PIL import Image\n\nfrom manim.constants import *\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.utils.bezier import integer_interpolate, interpolate\nfrom manim.utils.color import *\nfrom manim.utils.config_ops import _Data, _Uniforms\nfrom manim.utils.images import change_to_rgba_array, get_full_raster_image_path\nfrom manim.utils.iterables import listify\nfrom manim.utils.space_ops import normalize_along_axis\n\nif TYPE_CHECKING:\n    import numpy.typing as npt\n\n    from manim.typing import Point3D_Array, Vector3D_Array\n\n__all__ = [\"OpenGLSurface\", \"OpenGLTexturedSurface\"]\n\n\nclass OpenGLSurface(OpenGLMobject):\n    r\"\"\"Creates a Surface.\n\n    Parameters\n    ----------\n    uv_func\n        The function that defines the surface.\n    u_range\n        The range of the ``u`` variable: ``(u_min, u_max)``.\n    v_range\n        The range of the ``v`` variable: ``(v_min, v_max)``.\n    resolution\n        The number of samples taken of the surface.\n    axes\n        Axes on which the surface is to be drawn. Optional\n        parameter used when coloring a surface by z-value.\n    color\n        Color of the surface. Defaults to grey.\n    colorscale\n        Colors of the surface. Optional parameter used when\n        coloring a surface by values. Passing a list of\n        colors and an axes will color the surface by z-value.\n        Passing a list of tuples in the form ``(color, pivot)``\n        allows user-defined pivots where the color transitions.\n    colorscale_axis\n        Defines the axis on which the colorscale is applied\n        (0 = x, 1 = y, 2 = z), default is z-axis (2).\n    opacity\n        Opacity of the surface from 0 being fully transparent\n        to 1 being fully opaque. Defaults to 1.\n    \"\"\"\n\n    shader_dtype = [\n        (\"point\", np.float32, (3,)),\n        (\"du_point\", np.float32, (3,)),\n        (\"dv_point\", np.float32, (3,)),\n        (\"color\", np.float32, (4,)),\n    ]\n    shader_folder = \"surface\"\n\n    def __init__(\n        self,\n        uv_func=None,\n        u_range=None,\n        v_range=None,\n        # Resolution counts number of points sampled, which for\n        # each coordinate is one more than the the number of\n        # rows/columns of approximating squares\n        resolution=None,\n        axes=None,\n        color=GREY,\n        colorscale=None,\n        colorscale_axis=2,\n        opacity=1.0,\n        gloss=0.3,\n        shadow=0.4,\n        prefered_creation_axis=1,\n        # For du and dv steps.  Much smaller and numerical error\n        # can crop up in the shaders.\n        epsilon=1e-5,\n        render_primitive=moderngl.TRIANGLES,\n        depth_test=True,\n        shader_folder=None,\n        **kwargs: Any,\n    ):\n        self.passed_uv_func = uv_func\n        self.u_range = u_range if u_range is not None else (0, 1)\n        self.v_range = v_range if v_range is not None else (0, 1)\n        # Resolution counts number of points sampled, which for\n        # each coordinate is one more than the the number of\n        # rows/columns of approximating squares\n        self.resolution = resolution if resolution is not None else (101, 101)\n        self.axes = axes\n        self.colorscale = colorscale\n        self.colorscale_axis = colorscale_axis\n        self.prefered_creation_axis = prefered_creation_axis\n        # For du and dv steps.  Much smaller and numerical error\n        # can crop up in the shaders.\n        self.epsilon = epsilon\n\n        self.triangle_indices = None\n        super().__init__(\n            color=color,\n            opacity=opacity,\n            gloss=gloss,\n            shadow=shadow,\n            shader_folder=shader_folder if shader_folder is not None else \"surface\",\n            render_primitive=render_primitive,\n            depth_test=depth_test,\n            **kwargs,\n        )\n        self.compute_triangle_indices()\n\n    def uv_func(self, u, v):\n        # To be implemented in subclasses\n        if self.passed_uv_func:\n            return self.passed_uv_func(u, v)\n        return (u, v, 0.0)\n\n    def init_points(self):\n        dim = self.dim\n        nu, nv = self.resolution\n        u_range = np.linspace(*self.u_range, nu)\n        v_range = np.linspace(*self.v_range, nv)\n\n        # Get three lists:\n        # - Points generated by pure uv values\n        # - Those generated by values nudged by du\n        # - Those generated by values nudged by dv\n        point_lists = []\n        for du, dv in [(0, 0), (self.epsilon, 0), (0, self.epsilon)]:\n            uv_grid = np.array([[[u + du, v + dv] for v in v_range] for u in u_range])\n            point_grid = np.apply_along_axis(lambda p: self.uv_func(*p), 2, uv_grid)\n            point_lists.append(point_grid.reshape((nu * nv, dim)))\n        # Rather than tracking normal vectors, the points list will hold on to the\n        # infinitesimal nudged values alongside the original values.  This way, one\n        # can perform all the manipulations they'd like to the surface, and normals\n        # are still easily recoverable.\n        self.set_points(np.vstack(point_lists))\n\n    def compute_triangle_indices(self):\n        # TODO, if there is an event which changes\n        # the resolution of the surface, make sure\n        # this is called.\n        nu, nv = self.resolution\n        if nu == 0 or nv == 0:\n            self.triangle_indices = np.zeros(0, dtype=int)\n            return\n        index_grid = np.arange(nu * nv).reshape((nu, nv))\n        indices = np.zeros(6 * (nu - 1) * (nv - 1), dtype=int)\n        indices[0::6] = index_grid[:-1, :-1].flatten()  # Top left\n        indices[1::6] = index_grid[+1:, :-1].flatten()  # Bottom left\n        indices[2::6] = index_grid[:-1, +1:].flatten()  # Top right\n        indices[3::6] = index_grid[:-1, +1:].flatten()  # Top right\n        indices[4::6] = index_grid[+1:, :-1].flatten()  # Bottom left\n        indices[5::6] = index_grid[+1:, +1:].flatten()  # Bottom right\n        self.triangle_indices = indices\n\n    def get_triangle_indices(self):\n        return self.triangle_indices\n\n    def get_surface_points_and_nudged_points(\n        self,\n    ) -> tuple[Point3D_Array, Point3D_Array, Point3D_Array]:\n        points = self.points\n        k = len(points) // 3\n        return points[:k], points[k : 2 * k], points[2 * k :]\n\n    def get_unit_normals(self) -> Vector3D_Array:\n        s_points, du_points, dv_points = self.get_surface_points_and_nudged_points()\n        normals = np.cross(\n            (du_points - s_points) / self.epsilon,\n            (dv_points - s_points) / self.epsilon,\n        )\n        return normalize_along_axis(normals, 1)\n\n    def pointwise_become_partial(self, smobject, a, b, axis=None):\n        assert isinstance(smobject, OpenGLSurface)\n        if axis is None:\n            axis = self.prefered_creation_axis\n        if a <= 0 and b >= 1:\n            self.match_points(smobject)\n            return self\n\n        nu, nv = smobject.resolution\n        self.set_points(\n            np.vstack(\n                [\n                    self.get_partial_points_array(\n                        arr.copy(),\n                        a,\n                        b,\n                        (nu, nv, 3),\n                        axis=axis,\n                    )\n                    for arr in smobject.get_surface_points_and_nudged_points()\n                ],\n            ),\n        )\n        return self\n\n    def get_partial_points_array(self, points, a, b, resolution, axis):\n        if len(points) == 0:\n            return points\n        nu, nv = resolution[:2]\n        points = points.reshape(resolution)\n        max_index = resolution[axis] - 1\n        lower_index, lower_residue = integer_interpolate(0, max_index, a)\n        upper_index, upper_residue = integer_interpolate(0, max_index, b)\n        if axis == 0:\n            points[:lower_index] = interpolate(\n                points[lower_index],\n                points[lower_index + 1],\n                lower_residue,\n            )\n            points[upper_index + 1 :] = interpolate(\n                points[upper_index],\n                points[upper_index + 1],\n                upper_residue,\n            )\n        else:\n            shape = (nu, 1, resolution[2])\n            points[:, :lower_index] = interpolate(\n                points[:, lower_index],\n                points[:, lower_index + 1],\n                lower_residue,\n            ).reshape(shape)\n            points[:, upper_index + 1 :] = interpolate(\n                points[:, upper_index],\n                points[:, upper_index + 1],\n                upper_residue,\n            ).reshape(shape)\n        return points.reshape((nu * nv, *resolution[2:]))\n\n    def sort_faces_back_to_front(self, vect=OUT):\n        tri_is = self.triangle_indices\n        indices = list(range(len(tri_is) // 3))\n        points = self.points\n\n        def index_dot(index):\n            return np.dot(points[tri_is[3 * index]], vect)\n\n        indices.sort(key=index_dot)\n        for k in range(3):\n            tri_is[k::3] = tri_is[k::3][indices]\n        return self\n\n    # For shaders\n    def get_shader_data(self):\n        \"\"\"Called by parent Mobject to calculate and return\n        the shader data.\n\n        Returns\n        -------\n        shader_dtype\n            An array containing the shader data (vertices and\n            color of each vertex)\n        \"\"\"\n        s_points, du_points, dv_points = self.get_surface_points_and_nudged_points()\n        shader_data = np.zeros(len(s_points), dtype=self.shader_dtype)\n        if \"points\" not in self.locked_data_keys:\n            shader_data[\"point\"] = s_points\n            shader_data[\"du_point\"] = du_points\n            shader_data[\"dv_point\"] = dv_points\n            if self.colorscale:\n                if not hasattr(self, \"color_by_val\"):\n                    self.color_by_val = self._get_color_by_value(s_points)\n                shader_data[\"color\"] = self.color_by_val\n            else:\n                self.fill_in_shader_color_info(shader_data)\n        return shader_data\n\n    def fill_in_shader_color_info(self, shader_data):\n        \"\"\"Fills in the shader color data when the surface\n        is all one color.\n\n        Parameters\n        ----------\n        shader_data\n            The vertices of the surface.\n\n        Returns\n        -------\n        shader_dtype\n            An array containing the shader data (vertices and\n            color of each vertex)\n        \"\"\"\n        self.read_data_to_shader(shader_data, \"color\", \"rgbas\")\n        return shader_data\n\n    def _get_color_by_value(self, s_points):\n        \"\"\"Matches each vertex to a color associated to it's z-value.\n\n        Parameters\n        ----------\n        s_points\n           The vertices of the surface.\n\n        Returns\n        -------\n        List\n            A list of colors matching the vertex inputs.\n        \"\"\"\n        if type(self.colorscale[0]) in (list, tuple):\n            new_colors, pivots = [\n                [i for i, j in self.colorscale],\n                [j for i, j in self.colorscale],\n            ]\n        else:\n            new_colors = self.colorscale\n\n            pivot_min = self.axes.z_range[0]\n            pivot_max = self.axes.z_range[1]\n            pivot_frequency = (pivot_max - pivot_min) / (len(new_colors) - 1)\n            pivots = np.arange(\n                start=pivot_min,\n                stop=pivot_max + pivot_frequency,\n                step=pivot_frequency,\n            )\n\n        return_colors = []\n        for point in s_points:\n            axis_value = self.axes.point_to_coords(point)[self.colorscale_axis]\n            if axis_value <= pivots[0]:\n                return_colors.append(color_to_rgba(new_colors[0], self.opacity))\n            elif axis_value >= pivots[-1]:\n                return_colors.append(color_to_rgba(new_colors[-1], self.opacity))\n            else:\n                for i, pivot in enumerate(pivots):\n                    if pivot > axis_value:\n                        color_index = (axis_value - pivots[i - 1]) / (\n                            pivots[i] - pivots[i - 1]\n                        )\n                        color_index = max(min(color_index, 1), 0)\n                        temp_color = interpolate_color(\n                            new_colors[i - 1],\n                            new_colors[i],\n                            color_index,\n                        )\n                        break\n                return_colors.append(color_to_rgba(temp_color, self.opacity))\n\n        return return_colors\n\n    def get_shader_vert_indices(self):\n        return self.get_triangle_indices()\n\n\nclass OpenGLSurfaceGroup(OpenGLSurface):\n    def __init__(self, *parametric_surfaces, resolution=None, **kwargs):\n        self.resolution = (0, 0) if resolution is None else resolution\n        super().__init__(uv_func=None, **kwargs)\n        self.add(*parametric_surfaces)\n\n    def init_points(self):\n        pass  # Needed?\n\n\nclass OpenGLTexturedSurface(OpenGLSurface):\n    shader_dtype = [\n        (\"point\", np.float32, (3,)),\n        (\"du_point\", np.float32, (3,)),\n        (\"dv_point\", np.float32, (3,)),\n        (\"im_coords\", np.float32, (2,)),\n        (\"opacity\", np.float32, (1,)),\n    ]\n    shader_folder = \"textured_surface\"\n    im_coords = _Data()\n    opacity = _Data()\n    num_textures = _Uniforms()\n\n    def __init__(\n        self,\n        uv_surface: OpenGLSurface,\n        image_file: str | Path | npt.NDArray,\n        dark_image_file: str | Path = None,\n        image_mode: str | Iterable[str] = \"RGBA\",\n        shader_folder: str | Path = None,\n        **kwargs,\n    ):\n        self.uniforms = {}\n\n        if not isinstance(uv_surface, OpenGLSurface):\n            raise Exception(\"uv_surface must be of type OpenGLSurface\")\n        if isinstance(image_file, np.ndarray):\n            image_file = change_to_rgba_array(image_file)\n\n        # Set texture information\n        if isinstance(image_mode, (str, Path)):\n            image_mode = [image_mode] * 2\n        image_mode_light, image_mode_dark = image_mode\n        texture_paths = {\n            \"LightTexture\": self.get_image_from_file(\n                image_file,\n                image_mode_light,\n            ),\n            \"DarkTexture\": self.get_image_from_file(\n                dark_image_file or image_file,\n                image_mode_dark,\n            ),\n        }\n        if dark_image_file:\n            self.num_textures = 2\n\n        self.uv_surface = uv_surface\n        self.uv_func = uv_surface.uv_func\n        self.u_range = uv_surface.u_range\n        self.v_range = uv_surface.v_range\n        self.resolution = uv_surface.resolution\n        self.gloss = self.uv_surface.gloss\n        super().__init__(texture_paths=texture_paths, **kwargs)\n\n    def get_image_from_file(\n        self,\n        image_file: str | Path,\n        image_mode: str,\n    ) -> Image.Image:\n        image_file = get_full_raster_image_path(image_file)\n        return Image.open(image_file).convert(image_mode)\n\n    def init_data(self):\n        super().init_data()\n        self.im_coords = np.zeros((0, 2))\n        self.opacity = np.zeros((0, 1))\n\n    def init_points(self):\n        nu, nv = self.uv_surface.resolution\n        self.set_points(self.uv_surface.points)\n        self.im_coords = np.array(\n            [\n                [u, v]\n                for u in np.linspace(0, 1, nu)\n                for v in np.linspace(1, 0, nv)  # Reverse y-direction\n            ],\n        )\n\n    def init_colors(self):\n        self.opacity = np.array([self.uv_surface.rgbas[:, 3]])\n\n    def set_opacity(self, opacity, recurse=True):\n        for mob in self.get_family(recurse):\n            mob.opacity = np.array([[o] for o in listify(opacity)])\n        return self\n\n    def pointwise_become_partial(self, tsmobject, a, b, axis=1):\n        super().pointwise_become_partial(tsmobject, a, b, axis)\n        im_coords = self.im_coords\n        im_coords[:] = tsmobject.im_coords\n        if a <= 0 and b >= 1:\n            return self\n        nu, nv = tsmobject.resolution\n        im_coords[:] = self.get_partial_points_array(im_coords, a, b, (nu, nv, 2), axis)\n        return self\n\n    def fill_in_shader_color_info(self, shader_data):\n        self.read_data_to_shader(shader_data, \"opacity\", \"opacity\")\n        self.read_data_to_shader(shader_data, \"im_coords\", \"im_coords\")\n        return shader_data\n"
  },
  {
    "path": "manim/mobject/opengl/opengl_three_dimensions.py",
    "content": "from __future__ import annotations\n\nfrom typing import Any\n\nimport numpy as np\n\nfrom manim.mobject.opengl.opengl_surface import OpenGLSurface\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVGroup, OpenGLVMobject\n\n__all__ = [\"OpenGLSurfaceMesh\"]\n\n\nclass OpenGLSurfaceMesh(OpenGLVGroup):\n    def __init__(\n        self,\n        uv_surface: OpenGLSurface,\n        resolution: tuple[int, int] | None = None,\n        stroke_width: float = 1,\n        normal_nudge: float = 1e-2,\n        depth_test: bool = True,\n        flat_stroke: bool = False,\n        **kwargs: Any,\n    ):\n        if not isinstance(uv_surface, OpenGLSurface):\n            raise Exception(\"uv_surface must be of type OpenGLSurface\")\n        self.uv_surface = uv_surface\n        self.resolution = resolution if resolution is not None else (21, 21)\n        self.normal_nudge = normal_nudge\n        super().__init__(\n            stroke_width=stroke_width,\n            depth_test=depth_test,\n            flat_stroke=flat_stroke,\n            **kwargs,\n        )\n\n    def init_points(self) -> None:\n        uv_surface = self.uv_surface\n\n        full_nu, full_nv = uv_surface.resolution\n        part_nu, part_nv = self.resolution\n        u_indices = np.linspace(0, full_nu, part_nu).astype(int)\n        v_indices = np.linspace(0, full_nv, part_nv).astype(int)\n\n        points, du_points, dv_points = uv_surface.get_surface_points_and_nudged_points()\n        normals = uv_surface.get_unit_normals()\n        nudged_points = points + self.normal_nudge * normals\n\n        for ui in u_indices:\n            path = OpenGLVMobject()\n            full_ui = full_nv * ui\n            path.set_points_smoothly(nudged_points[full_ui : full_ui + full_nv])\n            self.add(path)\n        for vi in v_indices:\n            path = OpenGLVMobject()\n            path.set_points_smoothly(nudged_points[vi::full_nv])\n            self.add(path)\n"
  },
  {
    "path": "manim/mobject/opengl/opengl_vectorized_mobject.py",
    "content": "from __future__ import annotations\n\nimport itertools as it\nimport operator as op\nfrom collections.abc import Callable, Iterable, Sequence\nfrom functools import reduce, wraps\nfrom typing import Any, Self\n\nimport moderngl\nimport numpy as np\n\nfrom manim import config\nfrom manim.constants import *\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject, OpenGLPoint\nfrom manim.renderer.shader_wrapper import ShaderWrapper\nfrom manim.typing import Point3D, Point3DLike, Point3DLike_Array\nfrom manim.utils.bezier import (\n    bezier,\n    bezier_remap,\n    get_quadratic_approximation_of_cubic,\n    get_smooth_cubic_bezier_handle_points,\n    integer_interpolate,\n    interpolate,\n    partial_bezier_points,\n    proportions_along_bezier_curve_for_point,\n)\nfrom manim.utils.color import BLACK, WHITE, ManimColor, ParsableManimColor\nfrom manim.utils.config_ops import _Data\nfrom manim.utils.iterables import make_even, resize_with_interpolation, tuplify\nfrom manim.utils.space_ops import (\n    angle_between_vectors,\n    cross2d,\n    earclip_triangulation,\n    get_unit_normal,\n    shoelace_direction,\n    z_to_vector,\n)\n\n__all__ = [\n    \"triggers_refreshed_triangulation\",\n    \"OpenGLVMobject\",\n    \"OpenGLVGroup\",\n    \"OpenGLVectorizedPoint\",\n    \"OpenGLCurvesAsSubmobjects\",\n    \"OpenGLDashedVMobject\",\n]\n\n\ndef triggers_refreshed_triangulation(func):\n    @wraps(func)\n    def wrapper(self, *args, **kwargs):\n        old_points = np.empty((0, 3))\n        for mob in self.family_members_with_points():\n            old_points = np.concatenate((old_points, mob.points), axis=0)\n        func(self, *args, **kwargs)\n        new_points = np.empty((0, 3))\n        for mob in self.family_members_with_points():\n            new_points = np.concatenate((new_points, mob.points), axis=0)\n        if not np.array_equal(new_points, old_points):\n            self.refresh_triangulation()\n            self.refresh_unit_normal()\n        return self\n\n    return wrapper\n\n\nclass OpenGLVMobject(OpenGLMobject):\n    \"\"\"A vectorized mobject.\"\"\"\n\n    fill_dtype = [\n        (\"point\", np.float32, (3,)),\n        (\"unit_normal\", np.float32, (3,)),\n        (\"color\", np.float32, (4,)),\n        (\"vert_index\", np.float32, (1,)),\n    ]\n    stroke_dtype = [\n        (\"point\", np.float32, (3,)),\n        (\"prev_point\", np.float32, (3,)),\n        (\"next_point\", np.float32, (3,)),\n        (\"unit_normal\", np.float32, (3,)),\n        (\"stroke_width\", np.float32, (1,)),\n        (\"color\", np.float32, (4,)),\n    ]\n    stroke_shader_folder = \"quadratic_bezier_stroke\"\n    fill_shader_folder = \"quadratic_bezier_fill\"\n\n    # TODO: although these are called \"rgba\" in singular, they are used as\n    # FloatRGBA_Arrays and should be called instead \"rgbas\" in plural for consistency.\n    # The same should probably apply for \"stroke_width\" and \"unit_normal\".\n    fill_rgba = _Data()\n    stroke_rgba = _Data()\n    stroke_width = _Data()\n    unit_normal = _Data()\n\n    def __init__(\n        self,\n        fill_color: ParsableManimColor | None = None,\n        fill_opacity: float = 0.0,\n        stroke_color: ParsableManimColor | None = None,\n        stroke_opacity: float = 1.0,\n        stroke_width: float = DEFAULT_STROKE_WIDTH,\n        draw_stroke_behind_fill: bool = False,\n        # Indicates that it will not be displayed, but\n        # that it should count in parent mobject's path\n        pre_function_handle_to_anchor_scale_factor: float = 0.01,\n        make_smooth_after_applying_functions: float = False,\n        background_image_file: str | None = None,\n        # This is within a pixel\n        # TODO, do we care about accounting for\n        # varying zoom levels?\n        tolerance_for_point_equality: float = 1e-8,\n        n_points_per_curve: int = 3,\n        long_lines: bool = False,\n        should_subdivide_sharp_curves: bool = False,\n        should_remove_null_curves: bool = False,\n        # Could also be \"bevel\", \"miter\", \"round\"\n        joint_type: LineJointType | None = None,\n        flat_stroke: bool = True,\n        render_primitive=moderngl.TRIANGLES,\n        triangulation_locked: bool = False,\n        **kwargs,\n    ):\n        self.data = {}\n        self.fill_opacity = fill_opacity\n        self.stroke_opacity = stroke_opacity\n        self.stroke_width = stroke_width\n        self.draw_stroke_behind_fill = draw_stroke_behind_fill\n        # Indicates that it will not be displayed, but\n        # that it should count in parent mobject's path\n        self.pre_function_handle_to_anchor_scale_factor = (\n            pre_function_handle_to_anchor_scale_factor\n        )\n        self.make_smooth_after_applying_functions = make_smooth_after_applying_functions\n        self.background_image_file = background_image_file\n        # This is within a pixel\n        # TODO, do we care about accounting for\n        # varying zoom levels?\n        self.tolerance_for_point_equality = tolerance_for_point_equality\n        self.n_points_per_curve = n_points_per_curve\n        self.long_lines = long_lines\n        self.should_subdivide_sharp_curves = should_subdivide_sharp_curves\n        self.should_remove_null_curves = should_remove_null_curves\n        if joint_type is None:\n            joint_type = LineJointType.AUTO\n        self.joint_type = joint_type\n        self.flat_stroke = flat_stroke\n        self.render_primitive = render_primitive\n        self.triangulation_locked = triangulation_locked\n\n        self.needs_new_triangulation = True\n        self.triangulation = np.zeros(0, dtype=\"i4\")\n        self.orientation = 1\n\n        self.fill_data = None\n        self.stroke_data = None\n        self.fill_shader_wrapper = None\n        self.stroke_shader_wrapper = None\n        self.init_shader_data()\n\n        super().__init__(**kwargs)\n        self.refresh_unit_normal()\n\n        if fill_color is not None:\n            self.fill_color = ManimColor.parse(fill_color)\n        if stroke_color is not None:\n            self.stroke_color = ManimColor.parse(stroke_color)\n\n    def _assert_valid_submobjects(self, submobjects: Iterable[OpenGLVMobject]) -> Self:\n        return self._assert_valid_submobjects_internal(submobjects, OpenGLVMobject)\n\n    def get_group_class(self):\n        return OpenGLVGroup\n\n    @staticmethod\n    def get_mobject_type_class():\n        return OpenGLVMobject\n\n    @property\n    def submobjects(self) -> Sequence[OpenGLVMobject]:\n        return self._submobjects if hasattr(self, \"_submobjects\") else []\n\n    @submobjects.setter\n    def submobjects(self, submobject_list: Iterable[OpenGLVMobject]) -> None:\n        self.remove(*self.submobjects)\n        self.add(*submobject_list)\n\n    def init_data(self):\n        super().init_data()\n        self.data.pop(\"rgbas\")\n        self.fill_rgba = np.zeros((1, 4))\n        self.stroke_rgba = np.zeros((1, 4))\n        self.unit_normal = np.zeros((1, 3))\n        # stroke_width belongs to self.data, but is defined through init_colors+set_stroke\n\n    # Colors\n    def init_colors(self):\n        self.set_fill(\n            color=self.fill_color or self.color,\n            opacity=self.fill_opacity,\n        )\n        self.set_stroke(\n            color=self.stroke_color or self.color,\n            width=self.stroke_width,\n            opacity=self.stroke_opacity,\n            background=self.draw_stroke_behind_fill,\n        )\n        self.set_gloss(self.gloss)\n        self.set_flat_stroke(self.flat_stroke)\n        return self\n\n    def set_fill(\n        self,\n        color: ParsableManimColor | None = None,\n        opacity: float | None = None,\n        recurse: bool = True,\n    ) -> OpenGLVMobject:\n        \"\"\"Set the fill color and fill opacity of a :class:`OpenGLVMobject`.\n\n        Parameters\n        ----------\n        color\n            Fill color of the :class:`OpenGLVMobject`.\n        opacity\n            Fill opacity of the :class:`OpenGLVMobject`.\n        recurse\n            If ``True``, the fill color of all submobjects is also set.\n\n        Returns\n        -------\n        OpenGLVMobject\n            self. For chaining purposes.\n\n        Examples\n        --------\n        .. manim:: SetFill\n            :save_last_frame:\n\n            class SetFill(Scene):\n                def construct(self):\n                    square = Square().scale(2).set_fill(WHITE,1)\n                    circle1 = Circle().set_fill(GREEN,0.8)\n                    circle2 = Circle().set_fill(YELLOW) # No fill_opacity\n                    circle3 = Circle().set_fill(color = '#FF2135', opacity = 0.2)\n                    group = Group(circle1,circle2,circle3).arrange()\n                    self.add(square)\n                    self.add(group)\n\n        See Also\n        --------\n        :meth:`~.OpenGLVMobject.set_style`\n        \"\"\"\n        if opacity is not None:\n            self.fill_opacity = opacity\n        if recurse:\n            for submobject in self.submobjects:\n                submobject.set_fill(color, opacity, recurse)\n\n        self.set_rgba_array(color, opacity, \"fill_rgba\", recurse)\n        return self\n\n    def set_stroke(\n        self,\n        color=None,\n        width=None,\n        opacity=None,\n        background=None,\n        recurse=True,\n    ):\n        if opacity is not None:\n            self.stroke_opacity = opacity\n        if recurse:\n            for submobject in self.submobjects:\n                submobject.set_stroke(\n                    color=color,\n                    width=width,\n                    opacity=opacity,\n                    background=background,\n                    recurse=recurse,\n                )\n\n        self.set_rgba_array(color, opacity, \"stroke_rgba\", recurse)\n\n        if width is not None:\n            for mob in self.get_family(recurse):\n                if isinstance(width, np.ndarray):\n                    mob.stroke_width = width\n                else:\n                    mob.stroke_width = np.array([[width] for width in tuplify(width)])\n\n        if background is not None:\n            for mob in self.get_family(recurse):\n                mob.draw_stroke_behind_fill = background\n        return self\n\n    def set_style(\n        self,\n        fill_color=None,\n        fill_opacity=None,\n        fill_rgba=None,\n        stroke_color=None,\n        stroke_opacity=None,\n        stroke_rgba=None,\n        stroke_width=None,\n        gloss=None,\n        shadow=None,\n        recurse=True,\n    ):\n        if fill_rgba is not None:\n            self.fill_rgba = resize_with_interpolation(fill_rgba, len(fill_rgba))\n        else:\n            self.set_fill(color=fill_color, opacity=fill_opacity, recurse=recurse)\n\n        if stroke_rgba is not None:\n            self.stroke_rgba = resize_with_interpolation(stroke_rgba, len(fill_rgba))\n            self.set_stroke(width=stroke_width)\n        else:\n            self.set_stroke(\n                color=stroke_color,\n                width=stroke_width,\n                opacity=stroke_opacity,\n                recurse=recurse,\n            )\n\n        if gloss is not None:\n            self.set_gloss(gloss, recurse=recurse)\n        if shadow is not None:\n            self.set_shadow(shadow, recurse=recurse)\n        return self\n\n    def get_style(self):\n        return {\n            \"fill_rgba\": self.fill_rgba,\n            \"stroke_rgba\": self.stroke_rgba,\n            \"stroke_width\": self.stroke_width,\n            \"gloss\": self.gloss,\n            \"shadow\": self.shadow,\n        }\n\n    def match_style(self, vmobject, recurse=True):\n        vmobject_style = vmobject.get_style()\n        if config.renderer == RendererType.OPENGL:\n            vmobject_style[\"stroke_width\"] = vmobject_style[\"stroke_width\"][0][0]\n            vmobject_style[\"fill_opacity\"] = self.get_fill_opacity()\n        self.set_style(**vmobject_style, recurse=False)\n        if recurse:\n            # Does its best to match up submobject lists, and\n            # match styles accordingly\n            submobs1, submobs2 = self.submobjects, vmobject.submobjects\n            if len(submobs1) == 0:\n                return self\n            elif len(submobs2) == 0:\n                submobs2 = [vmobject]\n            for sm1, sm2 in zip(*make_even(submobs1, submobs2), strict=True):\n                sm1.match_style(sm2)\n        return self\n\n    def set_color(self, color, opacity=None, recurse=True):\n        if opacity is not None:\n            self.opacity = opacity\n\n        self.set_fill(color, opacity=opacity, recurse=recurse)\n        self.set_stroke(color, opacity=opacity, recurse=recurse)\n        return self\n\n    def set_opacity(self, opacity, recurse=True):\n        self.set_fill(opacity=opacity, recurse=recurse)\n        self.set_stroke(opacity=opacity, recurse=recurse)\n        return self\n\n    def fade(self, darkness=0.5, recurse=True):\n        factor = 1.0 - darkness\n        self.set_fill(\n            opacity=factor * self.get_fill_opacity(),\n            recurse=False,\n        )\n        self.set_stroke(\n            opacity=factor * self.get_stroke_opacity(),\n            recurse=False,\n        )\n        super().fade(darkness, recurse)\n        return self\n\n    # Todo im not quite sure why we are doing this\n    def get_fill_colors(self):\n        return [ManimColor.from_rgb(rgba[:3]) for rgba in self.fill_rgba]\n\n    def get_fill_opacities(self):\n        return self.fill_rgba[:, 3]\n\n    def get_stroke_colors(self):\n        return [ManimColor.from_rgb(rgba[:3]) for rgba in self.stroke_rgba]\n\n    def get_stroke_opacities(self):\n        return self.stroke_rgba[:, 3]\n\n    def get_stroke_widths(self):\n        return self.stroke_width\n\n    # TODO, it's weird for these to return the first of various lists\n    # rather than the full information\n    def get_fill_color(self):\n        \"\"\"\n        If there are multiple colors (for gradient)\n        this returns the first one\n        \"\"\"\n        return self.get_fill_colors()[0]\n\n    def get_fill_opacity(self):\n        \"\"\"\n        If there are multiple opacities, this returns the\n        first\n        \"\"\"\n        return self.get_fill_opacities()[0]\n\n    def get_stroke_color(self):\n        return self.get_stroke_colors()[0]\n\n    def get_stroke_width(self):\n        return self.get_stroke_widths()[0]\n\n    def get_stroke_opacity(self):\n        return self.get_stroke_opacities()[0]\n\n    def get_color(self):\n        if not self.has_fill():\n            return self.get_stroke_color()\n        return self.get_fill_color()\n\n    def get_colors(self):\n        if self.has_stroke():\n            return self.get_stroke_colors()\n        return self.get_fill_colors()\n\n    stroke_color = property(get_stroke_color, set_stroke)\n    color = property(get_color, set_color)\n    fill_color = property(get_fill_color, set_fill)\n\n    def has_stroke(self):\n        stroke_widths = self.get_stroke_widths()\n        stroke_opacities = self.get_stroke_opacities()\n        return (\n            stroke_widths is not None\n            and stroke_opacities is not None\n            and any(stroke_widths)\n            and any(stroke_opacities)\n        )\n\n    def has_fill(self):\n        fill_opacities = self.get_fill_opacities()\n        return fill_opacities is not None and any(fill_opacities)\n\n    def get_opacity(self):\n        if self.has_fill():\n            return self.get_fill_opacity()\n        return self.get_stroke_opacity()\n\n    def set_flat_stroke(self, flat_stroke=True, recurse=True):\n        for mob in self.get_family(recurse):\n            mob.flat_stroke = flat_stroke\n        return self\n\n    def get_flat_stroke(self):\n        return self.flat_stroke\n\n    # Points\n    def set_anchors_and_handles(self, anchors1, handles, anchors2):\n        assert len(anchors1) == len(handles) == len(anchors2)\n        nppc = self.n_points_per_curve\n        new_points = np.zeros((nppc * len(anchors1), self.dim))\n        arrays = [anchors1, handles, anchors2]\n        for index, array in enumerate(arrays):\n            new_points[index::nppc] = array\n        self.set_points(new_points)\n        return self\n\n    def start_new_path(self, point):\n        assert self.get_num_points() % self.n_points_per_curve == 0\n        self.append_points([point])\n        return self\n\n    def add_cubic_bezier_curve(\n        self,\n        anchor1: Point3DLike,\n        handle1: Point3DLike,\n        handle2: Point3DLike,\n        anchor2: Point3DLike,\n    ):\n        new_points = get_quadratic_approximation_of_cubic(\n            anchor1,\n            handle1,\n            handle2,\n            anchor2,\n        )\n        self.append_points(new_points)\n\n    def add_cubic_bezier_curve_to(self, handle1, handle2, anchor):\n        \"\"\"Add cubic bezier curve to the path.\"\"\"\n        self.throw_error_if_no_points()\n        quadratic_approx = get_quadratic_approximation_of_cubic(\n            self.get_last_point(),\n            handle1,\n            handle2,\n            anchor,\n        )\n        if self.has_new_path_started():\n            self.append_points(quadratic_approx[1:])\n        else:\n            self.append_points(quadratic_approx)\n\n    def add_quadratic_bezier_curve_to(self, handle, anchor):\n        self.throw_error_if_no_points()\n        if self.has_new_path_started():\n            self.append_points([handle, anchor])\n        else:\n            self.append_points([self.get_last_point(), handle, anchor])\n\n    def add_line_to(self, point: Sequence[float]) -> OpenGLVMobject:\n        \"\"\"Add a straight line from the last point of OpenGLVMobject to the given point.\n\n        Parameters\n        ----------\n\n        point\n            end of the straight line.\n        \"\"\"\n        end = self.points[-1]\n        alphas = np.linspace(0, 1, self.n_points_per_curve)\n        if self.long_lines:\n            halfway = interpolate(end, point, 0.5)\n            points = [interpolate(end, halfway, a) for a in alphas] + [\n                interpolate(halfway, point, a) for a in alphas\n            ]\n        else:\n            points = [interpolate(end, point, a) for a in alphas]\n        if self.has_new_path_started():\n            points = points[1:]\n        self.append_points(points)\n        return self\n\n    def add_smooth_curve_to(self, point):\n        if self.has_new_path_started():\n            self.add_line_to(point)\n        else:\n            self.throw_error_if_no_points()\n            new_handle = self.get_reflection_of_last_handle()\n            self.add_quadratic_bezier_curve_to(new_handle, point)\n        return self\n\n    def add_smooth_cubic_curve_to(self, handle, point):\n        self.throw_error_if_no_points()\n        new_handle = self.get_reflection_of_last_handle()\n        self.add_cubic_bezier_curve_to(new_handle, handle, point)\n\n    def has_new_path_started(self):\n        return self.get_num_points() % self.n_points_per_curve == 1\n\n    def get_last_point(self):\n        return self.points[-1]\n\n    def get_reflection_of_last_handle(self):\n        points = self.points\n        return 2 * points[-1] - points[-2]\n\n    def close_path(self):\n        if not self.is_closed():\n            self.add_line_to(self.get_subpaths()[-1][0])\n\n    def is_closed(self):\n        return self.consider_points_equals(self.points[0], self.points[-1])\n\n    def subdivide_sharp_curves(self, angle_threshold=30 * DEGREES, recurse=True):\n        vmobs = [vm for vm in self.get_family(recurse) if vm.has_points()]\n        for vmob in vmobs:\n            new_points = []\n            for tup in vmob.get_bezier_tuples():\n                angle = angle_between_vectors(tup[1] - tup[0], tup[2] - tup[1])\n                if angle > angle_threshold:\n                    n = int(np.ceil(angle / angle_threshold))\n                    alphas = np.linspace(0, 1, n + 1)\n                    new_points.extend(\n                        [\n                            partial_bezier_points(tup, a1, a2)\n                            for a1, a2 in zip(alphas[:-1], alphas[1:], strict=True)\n                        ],\n                    )\n                else:\n                    new_points.append(tup)\n            vmob.set_points(np.vstack(new_points))\n        return self\n\n    def add_points_as_corners(self, points):\n        for point in points:\n            self.add_line_to(point)\n        return points\n\n    def set_points_as_corners(self, points: Point3DLike_Array) -> OpenGLVMobject:\n        \"\"\"Given an array of points, set them as corner of the vmobject.\n\n        To achieve that, this algorithm sets handles aligned with the anchors such that the resultant bezier curve will be the segment\n        between the two anchors.\n\n        Parameters\n        ----------\n        points\n            Array of points that will be set as corners.\n\n        Returns\n        -------\n        OpenGLVMobject\n            self. For chaining purposes.\n        \"\"\"\n        nppc = self.n_points_per_curve\n        points = np.array(points)\n        self.set_anchors_and_handles(\n            *(interpolate(points[:-1], points[1:], a) for a in np.linspace(0, 1, nppc))\n        )\n        return self\n\n    def set_points_smoothly(\n        self, points: Point3DLike_Array, true_smooth: bool = False\n    ) -> Self:\n        self.set_points_as_corners(points)\n        self.make_smooth()\n        return self\n\n    def change_anchor_mode(self, mode):\n        \"\"\"Changes the anchor mode of the bezier curves. This will modify the handles.\n\n        There can be only three modes, \"jagged\", \"approx_smooth\"  and \"true_smooth\".\n\n        Returns\n        -------\n        OpenGLVMobject\n            For chaining purposes.\n        \"\"\"\n        assert mode in (\"jagged\", \"approx_smooth\", \"true_smooth\")\n        nppc = self.n_points_per_curve\n        for submob in self.family_members_with_points():\n            subpaths = submob.get_subpaths()\n            submob.clear_points()\n            for subpath in subpaths:\n                anchors = np.vstack([subpath[::nppc], subpath[-1:]])\n                new_subpath = np.array(subpath)\n                if mode == \"approx_smooth\":\n                    # TODO: get_smooth_quadratic_bezier_handle_points is not defined\n                    new_subpath[1::nppc] = get_smooth_quadratic_bezier_handle_points(\n                        anchors,\n                    )\n                elif mode == \"true_smooth\":\n                    h1, h2 = get_smooth_cubic_bezier_handle_points(anchors)\n                    new_subpath = get_quadratic_approximation_of_cubic(\n                        anchors[:-1],\n                        h1,\n                        h2,\n                        anchors[1:],\n                    )\n                elif mode == \"jagged\":\n                    new_subpath[1::nppc] = 0.5 * (anchors[:-1] + anchors[1:])\n                submob.append_points(new_subpath)\n            submob.refresh_triangulation()\n        return self\n\n    def make_smooth(self):\n        \"\"\"\n        This will double the number of points in the mobject,\n        so should not be called repeatedly.  It also means\n        transforming between states before and after calling\n        this might have strange artifacts\n        \"\"\"\n        self.change_anchor_mode(\"true_smooth\")\n        return self\n\n    def make_approximately_smooth(self):\n        \"\"\"\n        Unlike make_smooth, this will not change the number of\n        points, but it also does not result in a perfectly smooth\n        curve.  It's most useful when the points have been\n        sampled at a not-too-low rate from a continuous function,\n        as in the case of ParametricCurve\n        \"\"\"\n        self.change_anchor_mode(\"approx_smooth\")\n        return self\n\n    def make_jagged(self):\n        self.change_anchor_mode(\"jagged\")\n        return self\n\n    def add_subpath(self, points):\n        assert len(points) % self.n_points_per_curve == 0\n        self.append_points(points)\n        return self\n\n    def append_vectorized_mobject(self, vectorized_mobject):\n        new_points = list(vectorized_mobject.points)\n\n        if self.has_new_path_started():\n            # Remove last point, which is starting\n            # a new path\n            self.resize_data(len(self.points - 1))\n        self.append_points(new_points)\n        return self\n\n    #\n    def consider_points_equals(self, p0, p1):\n        return np.linalg.norm(p1 - p0) < self.tolerance_for_point_equality\n\n    # Information about the curve\n    def force_direction(self, target_direction: str):\n        \"\"\"Makes sure that points are either directed clockwise or\n        counterclockwise.\n\n        Parameters\n        ----------\n        target_direction\n            Either ``\"CW\"`` or ``\"CCW\"``.\n        \"\"\"\n        if target_direction not in (\"CW\", \"CCW\"):\n            raise ValueError('Invalid input for force_direction. Use \"CW\" or \"CCW\"')\n\n        if self.get_direction() != target_direction:\n            self.reverse_points()\n\n        return self\n\n    def reverse_direction(self):\n        \"\"\"Reverts the point direction by inverting the point order.\n\n        Returns\n        -------\n        :class:`OpenGLVMobject`\n            Returns self.\n\n        Examples\n        --------\n        .. manim:: ChangeOfDirection\n\n            class ChangeOfDirection(Scene):\n                def construct(self):\n                    ccw = RegularPolygon(5)\n                    ccw.shift(LEFT)\n                    cw = RegularPolygon(5)\n                    cw.shift(RIGHT).reverse_direction()\n\n                    self.play(Create(ccw), Create(cw),\n                    run_time=4)\n        \"\"\"\n        self.set_points(self.points[::-1])\n        return self\n\n    def get_bezier_tuples_from_points(self, points):\n        nppc = self.n_points_per_curve\n        remainder = len(points) % nppc\n        points = points[: len(points) - remainder]\n        return points.reshape((-1, nppc, 3))\n\n    def get_bezier_tuples(self):\n        return self.get_bezier_tuples_from_points(self.points)\n\n    def get_subpaths_from_points(self, points):\n        nppc = self.n_points_per_curve\n        diffs = points[nppc - 1 : -1 : nppc] - points[nppc::nppc]\n        splits = (diffs * diffs).sum(1) > self.tolerance_for_point_equality\n        split_indices = np.arange(nppc, len(points), nppc, dtype=int)[splits]\n\n        # split_indices = filter(\n        #     lambda n: not self.consider_points_equals(points[n - 1], points[n]),\n        #     range(nppc, len(points), nppc)\n        # )\n        split_indices = [0, *split_indices, len(points)]\n        return [\n            points[i1:i2]\n            for i1, i2 in zip(split_indices[:-1], split_indices[1:], strict=True)\n            if (i2 - i1) >= nppc\n        ]\n\n    def get_subpaths(self):\n        \"\"\"Returns subpaths formed by the curves of the OpenGLVMobject.\n\n        Subpaths are ranges of curves with each pair of consecutive\n        curves having their end/start points coincident.\n\n        Returns\n        -------\n        Tuple\n            subpaths.\n        \"\"\"\n        return self.get_subpaths_from_points(self.points)\n\n    def get_nth_curve_points(self, n: int) -> np.ndarray:\n        \"\"\"Returns the points defining the nth curve of the vmobject.\n\n        Parameters\n        ----------\n        n\n            index of the desired bezier curve.\n\n        Returns\n        -------\n        np.ndarray\n            points defininf the nth bezier curve (anchors, handles)\n        \"\"\"\n        assert n < self.get_num_curves()\n        nppc = self.n_points_per_curve\n        return self.points[nppc * n : nppc * (n + 1)]\n\n    def get_nth_curve_function(self, n: int) -> Callable[[float], np.ndarray]:\n        \"\"\"Returns the expression of the nth curve.\n\n        Parameters\n        ----------\n        n\n            index of the desired curve.\n\n        Returns\n        -------\n        typing.Callable[float]\n            expression of the nth bezier curve.\n        \"\"\"\n        return bezier(self.get_nth_curve_points(n))\n\n    def get_nth_curve_function_with_length(\n        self,\n        n: int,\n        sample_points: int | None = None,\n    ) -> tuple[Callable[[float], np.ndarray], float]:\n        \"\"\"Returns the expression of the nth curve along with its (approximate) length.\n\n        Parameters\n        ----------\n        n\n            The index of the desired curve.\n        sample_points\n            The number of points to sample to find the length.\n\n        Returns\n        -------\n        curve : Callable[[float], np.ndarray]\n            The function for the nth curve.\n        length : :class:`float`\n            The length of the nth curve.\n        \"\"\"\n        if sample_points is None:\n            sample_points = 10\n\n        curve = self.get_nth_curve_function(n)\n        norms = self.get_nth_curve_length_pieces(n, sample_points)\n\n        length = np.sum(norms)\n\n        return curve, length\n\n    def get_num_curves(self) -> int:\n        \"\"\"Returns the number of curves of the vmobject.\n\n        Returns\n        -------\n        int\n            number of curves. of the vmobject.\n        \"\"\"\n        return self.get_num_points() // self.n_points_per_curve\n\n    def get_nth_curve_length(\n        self,\n        n: int,\n        sample_points: int | None = None,\n    ) -> float:\n        \"\"\"Returns the (approximate) length of the nth curve.\n\n        Parameters\n        ----------\n        n\n            The index of the desired curve.\n        sample_points\n            The number of points to sample to find the length.\n\n        Returns\n        -------\n        length : :class:`float`\n            The length of the nth curve.\n        \"\"\"\n        _, length = self.get_nth_curve_function_with_length(n, sample_points)\n\n        return length\n\n    def get_curve_functions(\n        self,\n    ) -> Iterable[Callable[[float], np.ndarray]]:\n        \"\"\"Gets the functions for the curves of the mobject.\n\n        Returns\n        -------\n        Iterable[Callable[[float], np.ndarray]]\n            The functions for the curves.\n        \"\"\"\n        num_curves = self.get_num_curves()\n\n        for n in range(num_curves):\n            yield self.get_nth_curve_function(n)\n\n    def get_nth_curve_length_pieces(\n        self,\n        n: int,\n        sample_points: int | None = None,\n    ) -> np.ndarray:\n        \"\"\"Returns the array of short line lengths used for length approximation.\n\n        Parameters\n        ----------\n        n\n            The index of the desired curve.\n        sample_points\n            The number of points to sample to find the length.\n\n        Returns\n        -------\n        np.ndarray\n            The short length-pieces of the nth curve.\n        \"\"\"\n        if sample_points is None:\n            sample_points = 10\n\n        curve = self.get_nth_curve_function(n)\n        points = np.array([curve(a) for a in np.linspace(0, 1, sample_points)])\n        diffs = points[1:] - points[:-1]\n        norms = np.apply_along_axis(np.linalg.norm, 1, diffs)\n\n        return norms\n\n    def get_curve_functions_with_lengths(\n        self, **kwargs\n    ) -> Iterable[tuple[Callable[[float], np.ndarray], float]]:\n        \"\"\"Gets the functions and lengths of the curves for the mobject.\n\n        Parameters\n        ----------\n        **kwargs\n            The keyword arguments passed to :meth:`get_nth_curve_function_with_length`\n\n        Returns\n        -------\n        Iterable[Tuple[Callable[[float], np.ndarray], float]]\n            The functions and lengths of the curves.\n        \"\"\"\n        num_curves = self.get_num_curves()\n\n        for n in range(num_curves):\n            yield self.get_nth_curve_function_with_length(n, **kwargs)\n\n    def point_from_proportion(self, alpha: float) -> Point3D:\n        \"\"\"Gets the point at a proportion along the path of the :class:`OpenGLVMobject`.\n\n        Parameters\n        ----------\n        alpha\n            The proportion along the the path of the :class:`OpenGLVMobject`.\n\n        Returns\n        -------\n        :class:`Point3D`\n            The point on the :class:`OpenGLVMobject`.\n\n        Raises\n        ------\n        :exc:`ValueError`\n            If ``alpha`` is not between 0 and 1.\n        :exc:`Exception`\n            If the :class:`OpenGLVMobject` has no points.\n        \"\"\"\n        if alpha < 0 or alpha > 1:\n            raise ValueError(f\"Alpha {alpha} not between 0 and 1.\")\n\n        self.throw_error_if_no_points()\n        if alpha == 1:\n            return self.points[-1]\n\n        curves_and_lengths = tuple(self.get_curve_functions_with_lengths())\n\n        target_length = alpha * np.sum(\n            np.fromiter((length for _, length in curves_and_lengths), dtype=np.float64)\n        )\n        current_length = 0\n\n        for curve, length in curves_and_lengths:\n            if current_length + length >= target_length:\n                if length != 0:\n                    residue = (target_length - current_length) / length\n                else:\n                    residue = 0\n\n                return curve(residue)\n\n            current_length += length\n\n    def proportion_from_point(\n        self,\n        point: Point3DLike,\n    ) -> float:\n        \"\"\"Returns the proportion along the path of the :class:`OpenGLVMobject`\n        a particular given point is at.\n\n        Parameters\n        ----------\n        point\n            The Cartesian coordinates of the point which may or may not lie on the :class:`OpenGLVMobject`\n\n        Returns\n        -------\n        float\n            The proportion along the path of the :class:`OpenGLVMobject`.\n\n        Raises\n        ------\n        :exc:`ValueError`\n            If ``point`` does not lie on the curve.\n        :exc:`Exception`\n            If the :class:`OpenGLVMobject` has no points.\n        \"\"\"\n        self.throw_error_if_no_points()\n\n        # Iterate over each bezier curve that the ``VMobject`` is composed of, checking\n        # if the point lies on that curve. If it does not lie on that curve, add\n        # the whole length of the curve to ``target_length`` and move onto the next\n        # curve. If the point does lie on the curve, add how far along the curve\n        # the point is to ``target_length``.\n        # Then, divide ``target_length`` by the total arc length of the shape to get\n        # the proportion along the ``VMobject`` the point is at.\n\n        num_curves = self.get_num_curves()\n        total_length = self.get_arc_length()\n        target_length = 0\n        for n in range(num_curves):\n            control_points = self.get_nth_curve_points(n)\n            length = self.get_nth_curve_length(n)\n            proportions_along_bezier = proportions_along_bezier_curve_for_point(\n                point,\n                control_points,\n            )\n            if len(proportions_along_bezier) > 0:\n                proportion_along_nth_curve = max(proportions_along_bezier)\n                target_length += length * proportion_along_nth_curve\n                break\n            target_length += length\n        else:\n            raise ValueError(f\"Point {point} does not lie on this curve.\")\n\n        alpha = target_length / total_length\n\n        return alpha\n\n    def get_anchors_and_handles(self) -> Iterable[np.ndarray]:\n        \"\"\"\n        Returns anchors1, handles, anchors2,\n        where (anchors1[i], handles[i], anchors2[i])\n        will be three points defining a quadratic bezier curve\n        for any i in range(0, len(anchors1))\n        \"\"\"\n        nppc = self.n_points_per_curve\n        points = self.points\n        return [points[i::nppc] for i in range(nppc)]\n\n    def get_start_anchors(self) -> np.ndarray:\n        \"\"\"Returns the start anchors of the bezier curves.\n\n        Returns\n        -------\n        np.ndarray\n            Starting anchors\n        \"\"\"\n        return self.points[0 :: self.n_points_per_curve]\n\n    def get_end_anchors(self) -> np.ndarray:\n        \"\"\"Return the starting anchors of the bezier curves.\n\n        Returns\n        -------\n        np.ndarray\n            Starting anchors\n        \"\"\"\n        nppc = self.n_points_per_curve\n        return self.points[nppc - 1 :: nppc]\n\n    def get_anchors(self) -> Iterable[np.ndarray]:\n        \"\"\"Returns the anchors of the curves forming the OpenGLVMobject.\n\n        Returns\n        -------\n        Iterable[np.ndarray]\n            The anchors.\n        \"\"\"\n        points = self.points\n        if len(points) == 1:\n            return points\n\n        s = self.get_start_anchors()\n        e = self.get_end_anchors()\n        return list(it.chain.from_iterable(zip(s, e, strict=True)))\n\n    def get_points_without_null_curves(self, atol=1e-9):\n        nppc = self.n_points_per_curve\n        points = self.points\n        distinct_curves = reduce(\n            op.or_,\n            [\n                (abs(points[i::nppc] - points[0::nppc]) > atol).any(1)\n                for i in range(1, nppc)\n            ],\n        )\n        return points[distinct_curves.repeat(nppc)]\n\n    def get_arc_length(self, sample_points_per_curve: int | None = None) -> float:\n        \"\"\"Return the approximated length of the whole curve.\n\n        Parameters\n        ----------\n        sample_points_per_curve\n            Number of sample points per curve used to approximate the length. More points result in a better approximation.\n\n        Returns\n        -------\n        float\n            The length of the :class:`OpenGLVMobject`.\n        \"\"\"\n        return np.sum(\n            length\n            for _, length in self.get_curve_functions_with_lengths(\n                sample_points=sample_points_per_curve,\n            )\n        )\n\n    def get_area_vector(self):\n        # Returns a vector whose length is the area bound by\n        # the polygon formed by the anchor points, pointing\n        # in a direction perpendicular to the polygon according\n        # to the right hand rule.\n        if not self.has_points():\n            return np.zeros(3)\n\n        nppc = self.n_points_per_curve\n        points = self.points\n        p0 = points[0::nppc]\n        p1 = points[nppc - 1 :: nppc]\n\n        # Each term goes through all edges [(x1, y1, z1), (x2, y2, z2)]\n        return 0.5 * np.array(\n            [\n                sum(\n                    (p0[:, 1] + p1[:, 1]) * (p1[:, 2] - p0[:, 2]),\n                ),  # Add up (y1 + y2)*(z2 - z1)\n                sum(\n                    (p0[:, 2] + p1[:, 2]) * (p1[:, 0] - p0[:, 0]),\n                ),  # Add up (z1 + z2)*(x2 - x1)\n                sum(\n                    (p0[:, 0] + p1[:, 0]) * (p1[:, 1] - p0[:, 1]),\n                ),  # Add up (x1 + x2)*(y2 - y1)\n            ],\n        )\n\n    def get_direction(self):\n        \"\"\"Uses :func:`~.space_ops.shoelace_direction` to calculate the direction.\n        The direction of points determines in which direction the\n        object is drawn, clockwise or counterclockwise.\n\n        Examples\n        --------\n        The default direction of a :class:`~.Circle` is counterclockwise::\n\n            >>> from manim import Circle\n            >>> Circle().get_direction()\n            'CCW'\n\n        Returns\n        -------\n        :class:`str`\n            Either ``\"CW\"`` or ``\"CCW\"``.\n        \"\"\"\n        return shoelace_direction(self.get_start_anchors())\n\n    def get_unit_normal(self, recompute=False):\n        if not recompute:\n            return self.unit_normal[0]\n\n        if len(self.points) < 3:\n            return OUT\n\n        area_vect = self.get_area_vector()\n        area = np.linalg.norm(area_vect)\n        if area > 0:\n            return area_vect / area\n        else:\n            points = self.points\n            return get_unit_normal(\n                points[1] - points[0],\n                points[2] - points[1],\n            )\n\n    def refresh_unit_normal(self):\n        for mob in self.get_family():\n            mob.unit_normal[:] = mob.get_unit_normal(recompute=True)\n        return self\n\n    # Alignment\n    def align_points(self, vmobject):\n        # TODO: This shortcut can be a bit over eager. What if they have the same length, but different subpath lengths?\n        if self.get_num_points() == len(vmobject.points):\n            return\n\n        for mob in self, vmobject:\n            # If there are no points, add one to\n            # where the \"center\" is\n            if not mob.has_points():\n                mob.start_new_path(mob.get_center())\n            # If there's only one point, turn it into\n            # a null curve\n            if mob.has_new_path_started():\n                mob.add_line_to(mob.points[0])\n\n        # Figure out what the subpaths are, and align\n        subpaths1 = self.get_subpaths()\n        subpaths2 = vmobject.get_subpaths()\n        n_subpaths = max(len(subpaths1), len(subpaths2))\n        # Start building new ones\n        new_subpaths1 = []\n        new_subpaths2 = []\n\n        nppc = self.n_points_per_curve\n\n        def get_nth_subpath(path_list, n):\n            if n >= len(path_list):\n                # Create a null path at the very end\n                if len(path_list) == 0:\n                    return np.tile(np.zeros(3), (nppc, 1))\n                return np.tile(path_list[-1][-1], (nppc, 1))\n            path = path_list[n]\n            # Check for useless points at the end of the path and remove them\n            # https://github.com/ManimCommunity/manim/issues/1959\n            while len(path) > nppc:\n                # If the last nppc points are all equal to the preceding point\n                if self.consider_points_equals(path[-nppc:], path[-nppc - 1]):\n                    path = path[:-nppc]\n                else:\n                    break\n            return path\n\n        for n in range(n_subpaths):\n            sp1 = np.asarray(get_nth_subpath(subpaths1, n))\n            sp2 = np.asarray(get_nth_subpath(subpaths2, n))\n            diff1 = max(0, (len(sp2) - len(sp1)) // nppc)\n            diff2 = max(0, (len(sp1) - len(sp2)) // nppc)\n            sp1 = self.insert_n_curves_to_point_list(diff1, sp1)\n            sp2 = self.insert_n_curves_to_point_list(diff2, sp2)\n            new_subpaths1.append(sp1)\n            new_subpaths2.append(sp2)\n        self.set_points(np.vstack(new_subpaths1))\n        vmobject.set_points(np.vstack(new_subpaths2))\n        return self\n\n    def insert_n_curves(self, n: int, recurse=True) -> OpenGLVMobject:\n        \"\"\"Inserts n curves to the bezier curves of the vmobject.\n\n        Parameters\n        ----------\n        n\n            Number of curves to insert.\n\n        Returns\n        -------\n        OpenGLVMobject\n            for chaining.\n        \"\"\"\n        for mob in self.get_family(recurse):\n            if mob.get_num_curves() > 0:\n                new_points = mob.insert_n_curves_to_point_list(n, mob.points)\n                # TODO, this should happen in insert_n_curves_to_point_list\n                if mob.has_new_path_started():\n                    new_points = np.vstack([new_points, mob.get_last_point()])\n                mob.set_points(new_points)\n        return self\n\n    def insert_n_curves_to_point_list(self, n: int, points: np.ndarray) -> np.ndarray:\n        \"\"\"Given an array of k points defining a bezier curves\n         (anchors and handles), returns points defining exactly\n        k + n bezier curves.\n\n        Parameters\n        ----------\n        n\n            Number of desired curves.\n        points\n            Starting points.\n\n        Returns\n        -------\n        np.ndarray\n            Points generated.\n        \"\"\"\n        nppc = self.n_points_per_curve\n        if len(points) == 1:\n            return np.repeat(points, nppc * n, 0)\n\n        bezier_tuples = self.get_bezier_tuples_from_points(points)\n        current_number_of_curves = len(bezier_tuples)\n        new_number_of_curves = current_number_of_curves + n\n        new_bezier_tuples = bezier_remap(bezier_tuples, new_number_of_curves)\n        new_points = new_bezier_tuples.reshape(-1, 3)\n        return new_points\n\n    def interpolate(self, mobject1, mobject2, alpha, *args, **kwargs):\n        super().interpolate(mobject1, mobject2, alpha, *args, **kwargs)\n        if config[\"use_projection_fill_shaders\"]:\n            self.refresh_triangulation()\n        else:\n            if self.has_fill():\n                tri1 = mobject1.get_triangulation()\n                tri2 = mobject2.get_triangulation()\n                if len(tri1) != len(tri2) or not np.all(tri1 == tri2):\n                    self.refresh_triangulation()\n        return self\n\n    def pointwise_become_partial(\n        self, vmobject: OpenGLVMobject, a: float, b: float, remap: bool = True\n    ) -> OpenGLVMobject:\n        \"\"\"Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject\n        passed as parameter with respect to the bounds. Points here stand for control points of the bezier curves (anchors and handles)\n\n        Parameters\n        ----------\n        vmobject\n            The vmobject that will serve as a model.\n        a\n            upper-bound.\n        b\n            lower-bound\n        remap\n            if the point amount should be kept the same (True)\n            This option should be manually set to False if keeping the number of points is not needed\n        \"\"\"\n        assert isinstance(vmobject, OpenGLVMobject)\n        # Partial curve includes three portions:\n        # - A middle section, which matches the curve exactly\n        # - A start, which is some ending portion of an inner cubic\n        # - An end, which is the starting portion of a later inner cubic\n        if a <= 0 and b >= 1:\n            self.set_points(vmobject.points)\n            return self\n        bezier_triplets = vmobject.get_bezier_tuples()\n        num_quadratics = len(bezier_triplets)\n\n        # The following two lines will compute which bezier curves of the given mobject need to be processed.\n        # The residue basically indicates the proportion of the selected Bèzier curve.\n        # Ex: if lower_index is 3, and lower_residue is 0.4, then the algorithm will append to the points 0.4 of the third bezier curve\n        lower_index, lower_residue = integer_interpolate(0, num_quadratics, a)\n        upper_index, upper_residue = integer_interpolate(0, num_quadratics, b)\n        self.clear_points()\n        if num_quadratics == 0:\n            return self\n        if lower_index == upper_index:\n            self.append_points(\n                partial_bezier_points(\n                    bezier_triplets[lower_index],\n                    lower_residue,\n                    upper_residue,\n                ),\n            )\n        else:\n            self.append_points(\n                partial_bezier_points(bezier_triplets[lower_index], lower_residue, 1),\n            )\n            inner_points = bezier_triplets[lower_index + 1 : upper_index]\n            if len(inner_points) > 0:\n                if remap:\n                    new_triplets = bezier_remap(inner_points, num_quadratics - 2)\n                else:\n                    new_triplets = bezier_triplets\n\n                self.append_points(np.asarray(new_triplets).reshape(-1, 3))\n            self.append_points(\n                partial_bezier_points(bezier_triplets[upper_index], 0, upper_residue),\n            )\n        return self\n\n    def get_subcurve(self, a: float, b: float) -> OpenGLVMobject:\n        \"\"\"Returns the subcurve of the OpenGLVMobject between the interval [a, b].\n        The curve is a OpenGLVMobject itself.\n\n        Parameters\n        ----------\n\n        a\n            The lower bound.\n        b\n            The upper bound.\n\n        Returns\n        -------\n        OpenGLVMobject\n            The subcurve between of [a, b]\n        \"\"\"\n        vmob = self.copy()\n        vmob.pointwise_become_partial(self, a, b)\n        return vmob\n\n    # Related to triangulation\n\n    def refresh_triangulation(self) -> Self:\n        for mob in self.get_family():\n            mob.needs_new_triangulation = True\n        return self\n\n    def get_triangulation(self, normal_vector=None):\n        # Figure out how to triangulate the interior to know\n        # how to send the points as to the vertex shader.\n        # First triangles come directly from the points\n        if normal_vector is None:\n            normal_vector = self.get_unit_normal()\n\n        if not self.needs_new_triangulation:\n            return self.triangulation\n\n        points = self.points\n\n        if len(points) <= 1:\n            self.triangulation = np.zeros(0, dtype=\"i4\")\n            self.needs_new_triangulation = False\n            return self.triangulation\n\n        if not np.isclose(normal_vector, OUT).all():\n            # Rotate points such that unit normal vector is OUT\n            points = np.dot(points, z_to_vector(normal_vector))\n        indices = np.arange(len(points), dtype=int)\n\n        b0s = points[0::3]\n        b1s = points[1::3]\n        b2s = points[2::3]\n        v01s = b1s - b0s\n        v12s = b2s - b1s\n\n        crosses = cross2d(v01s, v12s)\n        convexities = np.sign(crosses)\n\n        atol = self.tolerance_for_point_equality\n        end_of_loop = np.zeros(len(b0s), dtype=bool)\n        end_of_loop[:-1] = (np.abs(b2s[:-1] - b0s[1:]) > atol).any(1)\n        end_of_loop[-1] = True\n\n        concave_parts = convexities < 0\n\n        # These are the vertices to which we'll apply a polygon triangulation\n        inner_vert_indices = np.hstack(\n            [\n                indices[0::3],\n                indices[1::3][concave_parts],\n                indices[2::3][end_of_loop],\n            ],\n        )\n        inner_vert_indices.sort()\n        rings = np.arange(1, len(inner_vert_indices) + 1)[inner_vert_indices % 3 == 2]\n\n        # Triangulate\n        inner_verts = points[inner_vert_indices]\n        inner_tri_indices = inner_vert_indices[\n            earclip_triangulation(inner_verts, rings)\n        ]\n\n        tri_indices = np.hstack([indices, inner_tri_indices])\n        self.triangulation = tri_indices\n        self.needs_new_triangulation = False\n        return tri_indices\n\n    @triggers_refreshed_triangulation\n    def set_points(self, points):\n        super().set_points(points)\n        return self\n\n    @triggers_refreshed_triangulation\n    def set_data(self, data):\n        super().set_data(data)\n        return self\n\n    # TODO, how to be smart about tangents here?\n    @triggers_refreshed_triangulation\n    def apply_function(self, function, make_smooth=False, **kwargs):\n        super().apply_function(function, **kwargs)\n        if self.make_smooth_after_applying_functions or make_smooth:\n            self.make_approximately_smooth()\n        return self\n\n    @triggers_refreshed_triangulation\n    def apply_points_function(self, *args, **kwargs):\n        super().apply_points_function(*args, **kwargs)\n        return self\n\n    @triggers_refreshed_triangulation\n    def flip(self, *args, **kwargs):\n        super().flip(*args, **kwargs)\n        return self\n\n    # For shaders\n    def init_shader_data(self):\n        self.fill_data = np.zeros(0, dtype=self.fill_dtype)\n        self.stroke_data = np.zeros(0, dtype=self.stroke_dtype)\n        self.fill_shader_wrapper = ShaderWrapper(\n            vert_data=self.fill_data,\n            vert_indices=np.zeros(0, dtype=\"i4\"),\n            shader_folder=self.fill_shader_folder,\n            render_primitive=self.render_primitive,\n        )\n        self.stroke_shader_wrapper = ShaderWrapper(\n            vert_data=self.stroke_data,\n            shader_folder=self.stroke_shader_folder,\n            render_primitive=self.render_primitive,\n        )\n\n    def refresh_shader_wrapper_id(self):\n        for wrapper in [self.fill_shader_wrapper, self.stroke_shader_wrapper]:\n            wrapper.refresh_id()\n        return self\n\n    def get_fill_shader_wrapper(self):\n        self.update_fill_shader_wrapper()\n        return self.fill_shader_wrapper\n\n    def update_fill_shader_wrapper(self):\n        self.fill_shader_wrapper.vert_data = self.get_fill_shader_data()\n        self.fill_shader_wrapper.vert_indices = self.get_triangulation()\n        self.fill_shader_wrapper.uniforms = self.get_fill_uniforms()\n        self.fill_shader_wrapper.depth_test = self.depth_test\n\n    def get_stroke_shader_wrapper(self):\n        self.update_stroke_shader_wrapper()\n        return self.stroke_shader_wrapper\n\n    def update_stroke_shader_wrapper(self):\n        self.stroke_shader_wrapper.vert_data = self.get_stroke_shader_data()\n        self.stroke_shader_wrapper.uniforms = self.get_stroke_uniforms()\n        self.stroke_shader_wrapper.depth_test = self.depth_test\n\n    def get_shader_wrapper_list(self):\n        # Build up data lists\n        fill_shader_wrappers = []\n        stroke_shader_wrappers = []\n        back_stroke_shader_wrappers = []\n        for submob in self.family_members_with_points():\n            if submob.has_fill() and not config[\"use_projection_fill_shaders\"]:\n                fill_shader_wrappers.append(submob.get_fill_shader_wrapper())\n            if submob.has_stroke() and not config[\"use_projection_stroke_shaders\"]:\n                ssw = submob.get_stroke_shader_wrapper()\n                if submob.draw_stroke_behind_fill:\n                    back_stroke_shader_wrappers.append(ssw)\n                else:\n                    stroke_shader_wrappers.append(ssw)\n\n        # Combine data lists\n        wrapper_lists = [\n            back_stroke_shader_wrappers,\n            fill_shader_wrappers,\n            stroke_shader_wrappers,\n        ]\n        result = []\n        for wlist in wrapper_lists:\n            if wlist:\n                wrapper = wlist[0]\n                wrapper.combine_with(*wlist[1:])\n                result.append(wrapper)\n        return result\n\n    def get_stroke_uniforms(self):\n        result = dict(super().get_shader_uniforms())\n        result[\"joint_type\"] = self.joint_type.value\n        result[\"flat_stroke\"] = float(self.flat_stroke)\n        return result\n\n    def get_fill_uniforms(self):\n        return {\n            \"is_fixed_in_frame\": float(self.is_fixed_in_frame),\n            \"is_fixed_orientation\": float(self.is_fixed_orientation),\n            \"fixed_orientation_center\": self.fixed_orientation_center,\n            \"gloss\": self.gloss,\n            \"shadow\": self.shadow,\n        }\n\n    def get_stroke_shader_data(self):\n        points = self.points\n        if len(self.stroke_data) != len(points):\n            self.stroke_data = np.zeros(len(points), dtype=OpenGLVMobject.stroke_dtype)\n\n        if \"points\" not in self.locked_data_keys:\n            nppc = self.n_points_per_curve\n            self.stroke_data[\"point\"] = points\n            self.stroke_data[\"prev_point\"][:nppc] = points[-nppc:]\n            self.stroke_data[\"prev_point\"][nppc:] = points[:-nppc]\n            self.stroke_data[\"next_point\"][:-nppc] = points[nppc:]\n            self.stroke_data[\"next_point\"][-nppc:] = points[:nppc]\n\n        self.read_data_to_shader(self.stroke_data, \"color\", \"stroke_rgba\")\n        self.read_data_to_shader(self.stroke_data, \"stroke_width\", \"stroke_width\")\n        self.read_data_to_shader(self.stroke_data, \"unit_normal\", \"unit_normal\")\n\n        return self.stroke_data\n\n    def get_fill_shader_data(self):\n        points = self.points\n        if len(self.fill_data) != len(points):\n            self.fill_data = np.zeros(len(points), dtype=OpenGLVMobject.fill_dtype)\n            self.fill_data[\"vert_index\"][:, 0] = range(len(points))\n\n        self.read_data_to_shader(self.fill_data, \"point\", \"points\")\n        self.read_data_to_shader(self.fill_data, \"color\", \"fill_rgba\")\n        self.read_data_to_shader(self.fill_data, \"unit_normal\", \"unit_normal\")\n\n        return self.fill_data\n\n    def refresh_shader_data(self):\n        self.get_fill_shader_data()\n        self.get_stroke_shader_data()\n\n    def get_fill_shader_vert_indices(self):\n        return self.get_triangulation()\n\n\nclass OpenGLVGroup(OpenGLVMobject):\n    \"\"\"A group of vectorized mobjects.\n\n    This can be used to group multiple :class:`~.OpenGLVMobject` instances together\n    in order to scale, move, ... them together.\n\n    Examples\n    --------\n\n    To add :class:`~.OpenGLVMobject`s to a :class:`~.OpenGLVGroup`, you can either use the\n    :meth:`~.OpenGLVGroup.add` method, or use the `+` and `+=` operators. Similarly, you\n    can subtract elements of a OpenGLVGroup via :meth:`~.OpenGLVGroup.remove` method, or\n    `-` and `-=` operators:\n\n    .. doctest::\n\n        >>> from manim import config\n        >>> original_renderer = config.renderer\n        >>> config.renderer = \"opengl\"\n\n        >>> from manim import Triangle, Square\n        >>> from manim.opengl import OpenGLVGroup\n        >>> config.renderer\n        <RendererType.OPENGL: 'opengl'>\n        >>> vg = OpenGLVGroup()\n        >>> triangle, square = Triangle(), Square()\n        >>> vg.add(triangle)\n        OpenGLVGroup(Triangle)\n        >>> vg + square  # a new OpenGLVGroup is constructed\n        OpenGLVGroup(Triangle, Square)\n        >>> vg  # not modified\n        OpenGLVGroup(Triangle)\n        >>> vg += square  # modifies vg\n        >>> vg\n        OpenGLVGroup(Triangle, Square)\n        >>> vg.remove(triangle)\n        OpenGLVGroup(Square)\n        >>> vg - square  # a new OpenGLVGroup is constructed\n        OpenGLVGroup()\n        >>> vg  # not modified\n        OpenGLVGroup(Square)\n        >>> vg -= square  # modifies vg\n        >>> vg\n        OpenGLVGroup()\n\n        >>> config.renderer = original_renderer\n\n    .. manim:: ArcShapeIris\n        :save_last_frame:\n\n        class ArcShapeIris(Scene):\n            def construct(self):\n                colors = [DARK_BROWN, BLUE_E, BLUE_D, BLUE_A, TEAL_B, GREEN_B, YELLOW_E]\n                radius = [1 + rad * 0.1 for rad in range(len(colors))]\n\n                circles_group = OpenGLVGroup()\n\n                # zip(radius, color) makes the iterator [(radius[i], color[i]) for i in range(radius)]\n                circles_group.add(*[Circle(radius=rad, stroke_width=10, color=col)\n                                    for rad, col in zip(radius, colors)])\n                self.add(circles_group)\n    \"\"\"\n\n    def __init__(self, *vmobjects: OpenGLVMobject, **kwargs: Any):\n        super().__init__(**kwargs)\n        self.add(*vmobjects)\n\n    def __repr__(self):\n        return (\n            self.__class__.__name__\n            + \"(\"\n            + \", \".join(str(mob) for mob in self.submobjects)\n            + \")\"\n        )\n\n    def __str__(self):\n        return (\n            f\"{self.__class__.__name__} of {len(self.submobjects)} \"\n            f\"submobject{'s' if len(self.submobjects) > 0 else ''}\"\n        )\n\n    def add(self, *vmobjects: OpenGLVMobject):\n        \"\"\"Checks if all passed elements are an instance of OpenGLVMobject and then add them to submobjects\n\n        Parameters\n        ----------\n        vmobjects\n            List of OpenGLVMobject to add\n\n        Returns\n        -------\n        :class:`OpenGLVGroup`\n\n        Raises\n        ------\n        TypeError\n            If one element of the list is not an instance of OpenGLVMobject\n\n        Examples\n        --------\n        .. manim:: AddToOpenGLVGroup\n\n            class AddToOpenGLVGroup(Scene):\n                def construct(self):\n                    circle_red = Circle(color=RED)\n                    circle_green = Circle(color=GREEN)\n                    circle_blue = Circle(color=BLUE)\n                    circle_red.shift(LEFT)\n                    circle_blue.shift(RIGHT)\n                    gr = OpenGLVGroup(circle_red, circle_green)\n                    gr2 = OpenGLVGroup(circle_blue) # Constructor uses add directly\n                    self.add(gr,gr2)\n                    self.wait()\n                    gr += gr2 # Add group to another\n                    self.play(\n                        gr.animate.shift(DOWN),\n                    )\n                    gr -= gr2 # Remove group\n                    self.play( # Animate groups separately\n                        gr.animate.shift(LEFT),\n                        gr2.animate.shift(UP),\n                    )\n                    self.play( #Animate groups without modification\n                        (gr+gr2).animate.shift(RIGHT)\n                    )\n                    self.play( # Animate group without component\n                        (gr-circle_red).animate.shift(RIGHT)\n                    )\n        \"\"\"\n        return super().add(*vmobjects)\n\n    def __add__(self, vmobject):\n        return OpenGLVGroup(*self.submobjects, vmobject)\n\n    def __iadd__(self, vmobject):\n        return self.add(vmobject)\n\n    def __sub__(self, vmobject):\n        copy = OpenGLVGroup(*self.submobjects)\n        copy.remove(vmobject)\n        return copy\n\n    def __isub__(self, vmobject):\n        return self.remove(vmobject)\n\n    def __setitem__(self, key: int, value: OpenGLVMobject | Sequence[OpenGLVMobject]):\n        \"\"\"Override the [] operator for item assignment.\n\n        Parameters\n        ----------\n        key\n            The index of the submobject to be assigned\n        value\n            The vmobject value to assign to the key\n\n        Returns\n        -------\n        None\n\n        Tests\n        -----\n\n        .. doctest::\n\n            >>> from manim import config\n            >>> original_renderer = config.renderer\n            >>> config.renderer = \"opengl\"\n\n            >>> vgroup = OpenGLVGroup(OpenGLVMobject())\n            >>> new_obj = OpenGLVMobject()\n            >>> vgroup[0] = new_obj\n\n            >>> config.renderer = original_renderer\n        \"\"\"\n        self._assert_valid_submobjects(tuplify(value))\n        self.submobjects[key] = value\n\n\nclass OpenGLVectorizedPoint(OpenGLPoint, OpenGLVMobject):\n    def __init__(\n        self,\n        location=ORIGIN,\n        color=BLACK,\n        fill_opacity=0,\n        stroke_width=0,\n        artificial_width=0.01,\n        artificial_height=0.01,\n        **kwargs,\n    ):\n        self.artificial_width = artificial_width\n        self.artificial_height = artificial_height\n\n        super().__init__(\n            color=color, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs\n        )\n        self.set_points(np.array([location]))\n\n\nclass OpenGLCurvesAsSubmobjects(OpenGLVGroup):\n    \"\"\"Convert a curve's elements to submobjects.\n\n    Examples\n    --------\n    .. manim:: LineGradientExample\n        :save_last_frame:\n\n        class LineGradientExample(Scene):\n            def construct(self):\n                curve = ParametricFunction(lambda t: [t, np.sin(t), 0], t_range=[-PI, PI, 0.01], stroke_width=10)\n                new_curve = CurvesAsSubmobjects(curve)\n                new_curve.set_color_by_gradient(BLUE, RED)\n                self.add(new_curve.shift(UP), curve)\n\n    \"\"\"\n\n    def __init__(self, vmobject, **kwargs):\n        super().__init__(**kwargs)\n        for tup in vmobject.get_bezier_tuples():\n            part = OpenGLVMobject()\n            part.set_points(tup)\n            part.match_style(vmobject)\n            self.add(part)\n\n\nclass OpenGLDashedVMobject(OpenGLVMobject):\n    \"\"\"A :class:`OpenGLVMobject` composed of dashes instead of lines.\n\n    Examples\n    --------\n    .. manim:: DashedVMobjectExample\n        :save_last_frame:\n\n        class DashedVMobjectExample(Scene):\n            def construct(self):\n                r = 0.5\n\n                top_row = OpenGLVGroup()  # Increasing num_dashes\n                for dashes in range(2, 12):\n                    circ = DashedVMobject(Circle(radius=r, color=WHITE), num_dashes=dashes)\n                    top_row.add(circ)\n\n                middle_row = OpenGLVGroup()  # Increasing dashed_ratio\n                for ratio in np.arange(1 / 11, 1, 1 / 11):\n                    circ = DashedVMobject(\n                        Circle(radius=r, color=WHITE), dashed_ratio=ratio\n                    )\n                    middle_row.add(circ)\n\n                sq = DashedVMobject(Square(1.5, color=RED))\n                penta = DashedVMobject(RegularPolygon(5, color=BLUE))\n                bottom_row = OpenGLVGroup(sq, penta)\n\n                top_row.arrange(buff=0.4)\n                middle_row.arrange()\n                bottom_row.arrange(buff=1)\n                everything = OpenGLVGroup(top_row, middle_row, bottom_row).arrange(DOWN, buff=1)\n                self.add(everything)\n    \"\"\"\n\n    def __init__(\n        self,\n        vmobject: OpenGLVMobject,\n        num_dashes: int = 15,\n        dashed_ratio: float = 0.5,\n        color: ParsableManimColor = WHITE,\n        **kwargs,\n    ):\n        self.dashed_ratio = dashed_ratio\n        self.num_dashes = num_dashes\n        super().__init__(color=color, **kwargs)\n        r = self.dashed_ratio\n        n = self.num_dashes\n        if num_dashes > 0:\n            # Assuming total length is 1\n            dash_len = r / n\n            void_len = (1 - r) / n if vmobject.is_closed() else (1 - r) / (n - 1)\n\n            self.add(\n                *(\n                    vmobject.get_subcurve(\n                        i * (dash_len + void_len),\n                        i * (dash_len + void_len) + dash_len,\n                    )\n                    for i in range(n)\n                )\n            )\n        # Family is already taken care of by get_subcurve\n        # implementation\n        self.match_style(vmobject, recurse=False)\n"
  },
  {
    "path": "manim/mobject/svg/__init__.py",
    "content": "\"\"\"Mobjects related to SVG images.\n\nModules\n=======\n\n.. autosummary::\n    :toctree: ../reference\n\n    ~brace\n    ~svg_mobject\n\"\"\"\n"
  },
  {
    "path": "manim/mobject/svg/brace.py",
    "content": "\"\"\"Mobject representing curly braces.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"Brace\", \"BraceLabel\", \"ArcBrace\", \"BraceText\", \"BraceBetweenPoints\"]\n\nfrom typing import TYPE_CHECKING, Any, Self\n\nimport numpy as np\nimport svgelements as se\n\nfrom manim._config import config\nfrom manim.mobject.geometry.arc import Arc\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.text.tex_mobject import MathTex, SingleStringMathTex, Tex\nfrom manim.mobject.text.text_mobject import Text\n\nfrom ...animation.animation import Animation\nfrom ...animation.composition import AnimationGroup\nfrom ...animation.fading import FadeIn\nfrom ...animation.growing import GrowFromCenter\nfrom ...constants import *\nfrom ...mobject.types.vectorized_mobject import VMobject\nfrom ...utils.color import BLACK\nfrom ..svg.svg_mobject import VMobjectFromSVGPath\n\nif TYPE_CHECKING:\n    from manim.typing import Point3D, Point3DLike, Vector3D, Vector3DLike\n    from manim.utils.color.core import ParsableManimColor\n\n\nclass Brace(VMobjectFromSVGPath):\n    \"\"\"Takes a mobject and draws a brace adjacent to it.\n\n    Passing a direction vector determines the direction from which the\n    brace is drawn. By default it is drawn from below.\n\n    Parameters\n    ----------\n    mobject\n        The mobject adjacent to which the brace is placed.\n    direction :\n        The direction from which the brace faces the mobject.\n\n    See Also\n    --------\n    :class:`BraceBetweenPoints`\n\n    Examples\n    --------\n    .. manim:: BraceExample\n        :save_last_frame:\n\n        class BraceExample(Scene):\n            def construct(self):\n                s = Square()\n                self.add(s)\n                for i in np.linspace(0.1,1.0,4):\n                    br = Brace(s, sharpness=i)\n                    t = Text(f\"sharpness= {i}\").next_to(br, RIGHT)\n                    self.add(t)\n                    self.add(br)\n                VGroup(*self.mobjects).arrange(DOWN, buff=0.2)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        mobject: Mobject,\n        direction: Vector3DLike = DOWN,\n        buff: float = 0.2,\n        sharpness: float = 2,\n        stroke_width: float = 0,\n        fill_opacity: float = 1.0,\n        background_stroke_width: float = 0,\n        background_stroke_color: ParsableManimColor = BLACK,\n        **kwargs: Any,\n    ):\n        path_string_template = (\n            \"m0.01216 0c-0.01152 0-0.01216 6.103e-4 -0.01216 0.01311v0.007762c0.06776 \"\n            \"0.122 0.1799 0.1455 0.2307 0.1455h{0}c0.03046 3.899e-4 0.07964 0.00449 \"\n            \"0.1246 0.02636 0.0537 0.02695 0.07418 0.05816 0.08648 0.07769 0.001562 \"\n            \"0.002538 0.004539 0.002563 0.01098 0.002563 0.006444-2e-8 0.009421-2.47e-\"\n            \"5 0.01098-0.002563 0.0123-0.01953 0.03278-0.05074 0.08648-0.07769 0.04491\"\n            \"-0.02187 0.09409-0.02597 0.1246-0.02636h{0}c0.05077 0 0.1629-0.02346 \"\n            \"0.2307-0.1455v-0.007762c-1.78e-6 -0.0125-6.365e-4 -0.01311-0.01216-0.0131\"\n            \"1-0.006444-3.919e-8 -0.009348 2.448e-5 -0.01091 0.002563-0.0123 0.01953-\"\n            \"0.03278 0.05074-0.08648 0.07769-0.04491 0.02187-0.09416 0.02597-0.1246 \"\n            \"0.02636h{1}c-0.04786 0-0.1502 0.02094-0.2185 0.1256-0.06833-0.1046-0.1706\"\n            \"-0.1256-0.2185-0.1256h{1}c-0.03046-3.899e-4 -0.07972-0.004491-0.1246-0.02\"\n            \"636-0.0537-0.02695-0.07418-0.05816-0.08648-0.07769-0.001562-0.002538-\"\n            \"0.004467-0.002563-0.01091-0.002563z\"\n        )\n        default_min_width = 0.90552\n\n        self.buff = buff\n\n        angle = -np.arctan2(*direction[:2]) + np.pi\n        mobject.rotate(-angle, about_point=ORIGIN)\n        left = mobject.get_corner(DOWN + LEFT)\n        right = mobject.get_corner(DOWN + RIGHT)\n        target_width = right[0] - left[0]\n        linear_section_length = max(\n            0,\n            (target_width * sharpness - default_min_width) / 2,\n        )\n\n        path = se.Path(\n            path_string_template.format(\n                linear_section_length,\n                -linear_section_length,\n            )\n        )\n\n        super().__init__(\n            path_obj=path,\n            stroke_width=stroke_width,\n            fill_opacity=fill_opacity,\n            background_stroke_width=background_stroke_width,\n            background_stroke_color=background_stroke_color,\n            **kwargs,\n        )\n        self.flip(RIGHT)\n        self.stretch_to_fit_width(target_width)\n        self.shift(left - self.get_corner(UP + LEFT) + self.buff * DOWN)\n\n        for mob in mobject, self:\n            mob.rotate(angle, about_point=ORIGIN)\n\n    def put_at_tip(self, mob: Mobject, use_next_to: bool = True, **kwargs: Any) -> Self:\n        \"\"\"Puts the given mobject at the brace tip.\n\n        Parameters\n        ----------\n        mob\n            The mobject to be placed at the tip.\n        use_next_to\n            If true, then :meth:`next_to` is used to place the mobject at the\n            tip.\n        kwargs\n            Any additional keyword arguments are passed to :meth:`next_to` which\n            is used to put the mobject next to the brace tip.\n        \"\"\"\n        if use_next_to:\n            mob.next_to(self.get_tip(), np.round(self.get_direction()), **kwargs)\n        else:\n            mob.move_to(self.get_tip())\n            buff = kwargs.get(\"buff\", DEFAULT_MOBJECT_TO_MOBJECT_BUFFER)\n            shift_distance = mob.width / 2.0 + buff\n            mob.shift(self.get_direction() * shift_distance)\n        return self\n\n    def get_text(self, *text: str, **kwargs: Any) -> Tex:\n        \"\"\"Places the text at the brace tip.\n\n        Parameters\n        ----------\n        text\n            The text to be placed at the brace tip.\n        kwargs\n            Any additional keyword arguments are passed to :meth:`.put_at_tip` which\n            is used to position the text at the brace tip.\n\n        Returns\n        -------\n        :class:`~.Tex`\n        \"\"\"\n        text_mob = Tex(*text)\n        self.put_at_tip(text_mob, **kwargs)\n        return text_mob\n\n    def get_tex(self, *tex: str, **kwargs: Any) -> MathTex:\n        \"\"\"Places the tex at the brace tip.\n\n        Parameters\n        ----------\n        tex\n            The tex to be placed at the brace tip.\n        kwargs\n            Any further keyword arguments are passed to :meth:`.put_at_tip` which\n            is used to position the tex at the brace tip.\n\n        Returns\n        -------\n        :class:`~.MathTex`\n        \"\"\"\n        tex_mob = MathTex(*tex)\n        self.put_at_tip(tex_mob, **kwargs)\n        return tex_mob\n\n    def get_tip(self) -> Point3D:\n        \"\"\"Returns the point at the brace tip.\"\"\"\n        # Returns the position of the seventh point in the path, which is the tip.\n        if config[\"renderer\"] == \"opengl\":\n            return self.points[34]\n\n        return self.points[28]  # = 7*4\n\n    def get_direction(self) -> Vector3D:\n        \"\"\"Returns the direction from the center to the brace tip.\"\"\"\n        vect = self.get_tip() - self.get_center()\n        return vect / np.linalg.norm(vect)\n\n\nclass BraceLabel(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"Create a brace with a label attached.\n\n    Parameters\n    ----------\n    obj\n        The mobject adjacent to which the brace is placed.\n    text\n        The label text.\n    brace_direction\n        The direction of the brace. By default ``DOWN``.\n    label_constructor\n        A class or function used to construct a mobject representing\n        the label. By default :class:`~.MathTex`.\n    font_size\n        The font size of the label, passed to the ``label_constructor``.\n    buff\n        The buffer between the mobject and the brace.\n    brace_config\n        Arguments to be passed to :class:`.Brace`.\n    kwargs\n        Additional arguments to be passed to :class:`~.VMobject`.\n    \"\"\"\n\n    def __init__(\n        self,\n        obj: Mobject,\n        text: str,\n        brace_direction: Vector3DLike = DOWN,\n        label_constructor: type[SingleStringMathTex | Text] = MathTex,\n        font_size: float = DEFAULT_FONT_SIZE,\n        buff: float = 0.2,\n        brace_config: dict[str, Any] | None = None,\n        **kwargs: Any,\n    ):\n        self.label_constructor = label_constructor\n        super().__init__(**kwargs)\n\n        self.brace_direction = brace_direction\n        if brace_config is None:\n            brace_config = {}\n        self.brace = Brace(obj, brace_direction, buff, **brace_config)\n\n        if isinstance(text, (tuple, list)):\n            self.label: VMobject = self.label_constructor(\n                *text, font_size=font_size, **kwargs\n            )\n        else:\n            self.label = self.label_constructor(str(text), font_size=font_size)\n\n        self.brace.put_at_tip(self.label)\n        self.add(self.brace, self.label)\n\n    def creation_anim(\n        self,\n        label_anim: type[Animation] = FadeIn,\n        brace_anim: type[Animation] = GrowFromCenter,\n    ) -> AnimationGroup:\n        return AnimationGroup(brace_anim(self.brace), label_anim(self.label))\n\n    def shift_brace(self, obj: Mobject, **kwargs: Any) -> Self:\n        if isinstance(obj, list):\n            obj = self.get_group_class()(*obj)\n        self.brace = Brace(obj, self.brace_direction, **kwargs)\n        self.brace.put_at_tip(self.label)\n        return self\n\n    def change_label(self, *text: str, **kwargs: Any) -> Self:\n        self.remove(self.label)\n        self.label = self.label_constructor(*text, **kwargs)  # type: ignore[arg-type]\n        self.brace.put_at_tip(self.label)\n        self.add(self.label)\n        return self\n\n    def change_brace_label(self, obj: Mobject, *text: str, **kwargs: Any) -> Self:\n        self.shift_brace(obj)\n        self.change_label(*text, **kwargs)\n        return self\n\n\nclass BraceText(BraceLabel):\n    \"\"\"Create a brace with a text label attached.\n\n    Parameters\n    ----------\n    obj\n        The mobject adjacent to which the brace is placed.\n    text\n        The label text.\n    brace_direction\n        The direction of the brace. By default ``DOWN``.\n    label_constructor\n        A class or function used to construct a mobject representing\n        the label. By default :class:`~.Text`.\n    font_size\n        The font size of the label, passed to the ``label_constructor``.\n    buff\n        The buffer between the mobject and the brace.\n    brace_config\n        Arguments to be passed to :class:`.Brace`.\n    kwargs\n        Additional arguments to be passed to :class:`~.VMobject`.\n\n\n    Examples\n    --------\n        .. manim:: BraceTextExample\n            :save_last_frame:\n\n            class BraceTextExample(Scene):\n                def construct(self):\n                    s1 = Square().move_to(2*LEFT)\n                    self.add(s1)\n                    br1 = BraceText(s1, \"Label\")\n                    self.add(br1)\n\n                    s2 = Square().move_to(2*RIGHT)\n                    self.add(s2)\n                    br2 = BraceText(s2, \"Label\")\n\n                    br2.change_label(\"new\")\n                    self.add(br2)\n                    self.wait(0.1)\n    \"\"\"\n\n    def __init__(\n        self,\n        obj: Mobject,\n        text: str,\n        label_constructor: type[SingleStringMathTex | Text] = Text,\n        **kwargs: Any,\n    ):\n        super().__init__(obj, text, label_constructor=label_constructor, **kwargs)\n\n\nclass BraceBetweenPoints(Brace):\n    \"\"\"Similar to Brace, but instead of taking a mobject it uses 2\n    points to place the brace.\n\n    A fitting direction for the brace is\n    computed, but it still can be manually overridden.\n    If the points go from left to right, the brace is drawn from below.\n    Swapping the points places the brace on the opposite side.\n\n    Parameters\n    ----------\n    point_1 :\n        The first point.\n    point_2 :\n        The second point.\n    direction :\n        The direction from which the brace faces towards the points.\n\n    Examples\n    --------\n        .. manim:: BraceBPExample\n\n            class BraceBPExample(Scene):\n                def construct(self):\n                    p1 = [0,0,0]\n                    p2 = [1,2,0]\n                    brace = BraceBetweenPoints(p1,p2)\n                    self.play(Create(NumberPlane()))\n                    self.play(Create(brace))\n                    self.wait(2)\n    \"\"\"\n\n    def __init__(\n        self,\n        point_1: Point3DLike,\n        point_2: Point3DLike,\n        direction: Vector3DLike = ORIGIN,\n        **kwargs: Any,\n    ):\n        if all(direction == ORIGIN):\n            line_vector = np.array(point_2) - np.array(point_1)\n            direction = np.array([line_vector[1], -line_vector[0], 0])\n        super().__init__(Line(point_1, point_2), direction=direction, **kwargs)\n\n\nclass ArcBrace(Brace):\n    \"\"\"Creates a :class:`~Brace` that wraps around an :class:`~.Arc`.\n\n    The direction parameter allows the brace to be applied\n    from outside or inside the arc.\n\n    .. warning::\n        The :class:`ArcBrace` is smaller for arcs with smaller radii.\n\n    .. note::\n        The :class:`ArcBrace` is initially a vertical :class:`Brace` defined by the\n        length of the :class:`~.Arc`, but is scaled down to match the start and end\n        angles. An exponential function is then applied after it is shifted based on\n        the radius of the arc.\n\n        The scaling effect is not applied for arcs with radii smaller than 1 to prevent\n        over-scaling.\n\n    Parameters\n    ----------\n    arc\n        The :class:`~.Arc` that wraps around the :class:`Brace` mobject.\n    direction\n        The direction from which the brace faces the arc.\n        ``LEFT`` for inside the arc, and ``RIGHT`` for the outside.\n\n    Example\n    -------\n        .. manim:: ArcBraceExample\n            :save_last_frame:\n            :ref_classes: Arc\n\n            class ArcBraceExample(Scene):\n                def construct(self):\n                    arc_1 = Arc(radius=1.5,start_angle=0,angle=2*PI/3).set_color(RED)\n                    brace_1 = ArcBrace(arc_1,LEFT)\n                    group_1 = VGroup(arc_1,brace_1)\n\n                    arc_2 = Arc(radius=3,start_angle=0,angle=5*PI/6).set_color(YELLOW)\n                    brace_2 = ArcBrace(arc_2)\n                    group_2 = VGroup(arc_2,brace_2)\n\n                    arc_3 = Arc(radius=0.5,start_angle=-0,angle=PI).set_color(BLUE)\n                    brace_3 = ArcBrace(arc_3)\n                    group_3 = VGroup(arc_3,brace_3)\n\n                    arc_4 = Arc(radius=0.2,start_angle=0,angle=3*PI/2).set_color(GREEN)\n                    brace_4 = ArcBrace(arc_4)\n                    group_4 = VGroup(arc_4,brace_4)\n\n                    arc_group = VGroup(group_1, group_2, group_3, group_4).arrange_in_grid(buff=1.5)\n                    self.add(arc_group.center())\n\n    \"\"\"\n\n    def __init__(\n        self,\n        arc: Arc | None = None,\n        direction: Vector3DLike = RIGHT,\n        **kwargs: Any,\n    ):\n        if arc is None:\n            arc = Arc(start_angle=-1, angle=2, radius=1)\n        arc_end_angle = arc.start_angle + arc.angle\n        line = Line(UP * arc.start_angle, UP * arc_end_angle)\n        scale_shift = RIGHT * np.log(arc.radius)\n\n        if arc.radius >= 1:\n            line.scale(arc.radius, about_point=ORIGIN)\n            super().__init__(line, direction=direction, **kwargs)\n            self.scale(1 / (arc.radius), about_point=ORIGIN)\n        else:\n            super().__init__(line, direction=direction, **kwargs)\n\n        if arc.radius >= 0.3:\n            self.shift(scale_shift)\n        else:\n            self.shift(RIGHT * np.log(0.3))\n\n        self.apply_complex_function(np.exp)\n        self.shift(arc.get_arc_center())\n"
  },
  {
    "path": "manim/mobject/svg/svg_mobject.py",
    "content": "\"\"\"Mobjects generated from an SVG file.\"\"\"\n\nfrom __future__ import annotations\n\nimport os\nfrom pathlib import Path\nfrom typing import Any\nfrom xml.etree import ElementTree as ET\n\nimport numpy as np\nimport svgelements as se\n\nfrom manim import config, logger\nfrom manim.utils.color import ManimColor, ParsableManimColor\n\nfrom ...constants import RIGHT\nfrom ...utils.bezier import get_quadratic_approximation_of_cubic\nfrom ...utils.images import get_full_vector_image_path\nfrom ...utils.iterables import hash_obj\nfrom ..geometry.arc import Circle\nfrom ..geometry.line import Line\nfrom ..geometry.polygram import Polygon, Rectangle, RoundedRectangle\nfrom ..opengl.opengl_compatibility import ConvertToOpenGL\nfrom ..types.vectorized_mobject import VGroup, VMobject\n\n__all__ = [\"SVGMobject\", \"VMobjectFromSVGPath\"]\n\n\nSVG_HASH_TO_MOB_MAP: dict[int, SVGMobject] = {}\n\n\ndef _convert_point_to_3d(x: float, y: float) -> np.ndarray:\n    return np.array([x, y, 0.0])\n\n\nclass SVGMobject(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A vectorized mobject created from importing an SVG file.\n\n    Parameters\n    ----------\n    file_name\n        The path to the SVG file.\n    should_center\n        Whether or not the mobject should be centered after\n        being imported.\n    height\n        The target height of the mobject, set to 2 Manim units by default.\n        If the height and width are both set to ``None``, the mobject\n        is imported without being scaled.\n    width\n        The target width of the mobject, set to ``None`` by default. If\n        the height and the width are both set to ``None``, the mobject\n        is imported without being scaled.\n    color\n        The color (both fill and stroke color) of the mobject. If\n        ``None`` (the default), the colors set in the SVG file\n        are used.\n    opacity\n        The opacity (both fill and stroke opacity) of the mobject.\n        If ``None`` (the default), the opacity set in the SVG file\n        is used.\n    fill_color\n        The fill color of the mobject. If ``None`` (the default),\n        the fill colors set in the SVG file are used.\n    fill_opacity\n        The fill opacity of the mobject. If ``None`` (the default),\n        the fill opacities set in the SVG file are used.\n    stroke_color\n        The stroke color of the mobject. If ``None`` (the default),\n        the stroke colors set in the SVG file are used.\n    stroke_opacity\n        The stroke opacity of the mobject. If ``None`` (the default),\n        the stroke opacities set in the SVG file are used.\n    stroke_width\n        The stroke width of the mobject. If ``None`` (the default),\n        the stroke width values set in the SVG file are used.\n    svg_default\n        A dictionary in which fallback values for unspecified\n        properties of elements in the SVG file are defined. If\n        ``None`` (the default), ``color``, ``opacity``, ``fill_color``\n        ``fill_opacity``, ``stroke_color``, and ``stroke_opacity``\n        are set to ``None``, and ``stroke_width`` is set to 0.\n    path_string_config\n        A dictionary with keyword arguments passed to\n        :class:`.VMobjectFromSVGPath` used for importing path elements.\n        If ``None`` (the default), no additional arguments are passed.\n    use_svg_cache\n        If True (default), the svg inputs (e.g. file_name, settings)\n        will be used as a key and a copy of the created mobject will\n        be saved using that key to be quickly retrieved if the same\n        inputs need be processed later. For large SVGs which are used\n        only once, this can be omitted to improve performance.\n    kwargs\n        Further arguments passed to the parent class.\n    \"\"\"\n\n    def __init__(\n        self,\n        file_name: str | os.PathLike | None = None,\n        should_center: bool = True,\n        height: float | None = 2,\n        width: float | None = None,\n        color: ParsableManimColor | None = None,\n        opacity: float | None = None,\n        fill_color: ParsableManimColor | None = None,\n        fill_opacity: float | None = None,\n        stroke_color: ParsableManimColor | None = None,\n        stroke_opacity: float | None = None,\n        stroke_width: float | None = None,\n        svg_default: dict | None = None,\n        path_string_config: dict | None = None,\n        use_svg_cache: bool = True,\n        **kwargs: Any,\n    ):\n        super().__init__(color=None, stroke_color=None, fill_color=None, **kwargs)\n\n        # process keyword arguments\n        self.file_name = Path(file_name) if file_name is not None else None\n\n        self.should_center = should_center\n        self.svg_height = height\n        self.svg_width = width\n        self.color = ManimColor(color)\n        self.opacity = opacity\n        self.fill_color = fill_color\n        self.fill_opacity = fill_opacity  # type: ignore[assignment]\n        self.stroke_color = stroke_color\n        self.stroke_opacity = stroke_opacity  # type: ignore[assignment]\n        self.stroke_width = stroke_width  # type: ignore[assignment]\n        self.id_to_vgroup_dict: dict[str, VGroup] = {}\n        if self.stroke_width is None:\n            self.stroke_width = 0\n\n        if svg_default is None:\n            svg_default = {\n                \"color\": None,\n                \"opacity\": None,\n                \"fill_color\": None,\n                \"fill_opacity\": None,\n                \"stroke_width\": 0,\n                \"stroke_color\": None,\n                \"stroke_opacity\": None,\n            }\n        self.svg_default = svg_default\n\n        if path_string_config is None:\n            path_string_config = {}\n        self.path_string_config = path_string_config\n\n        self.init_svg_mobject(use_svg_cache=use_svg_cache)\n\n        self.set_style(\n            fill_color=fill_color,\n            fill_opacity=fill_opacity,\n            stroke_color=stroke_color,\n            stroke_opacity=stroke_opacity,\n            stroke_width=stroke_width,\n        )\n        self.move_into_position()\n\n    def init_svg_mobject(self, use_svg_cache: bool) -> None:\n        \"\"\"Checks whether the SVG has already been imported and\n        generates it if not.\n\n        See also\n        --------\n        :meth:`.SVGMobject.generate_mobject`\n        \"\"\"\n        if use_svg_cache:\n            hash_val = hash_obj(self.hash_seed)\n            if hash_val in SVG_HASH_TO_MOB_MAP:\n                mob = SVG_HASH_TO_MOB_MAP[hash_val].copy()\n                self.add(*mob)\n                self.id_to_vgroup_dict = mob.id_to_vgroup_dict\n                return\n\n        self.generate_mobject()\n        if use_svg_cache:\n            SVG_HASH_TO_MOB_MAP[hash_val] = self.copy()\n\n    @property\n    def hash_seed(self) -> tuple:\n        \"\"\"A unique hash representing the result of the generated\n        mobject points.\n\n        Used as keys in the ``SVG_HASH_TO_MOB_MAP`` caching dictionary.\n        \"\"\"\n        return (\n            self.__class__.__name__,\n            self.svg_default,\n            self.path_string_config,\n            self.file_name,\n            config.renderer,\n        )\n\n    def generate_mobject(self) -> None:\n        \"\"\"Parse the SVG and translate its elements to submobjects.\"\"\"\n        file_path = self.get_file_path()\n        element_tree = ET.parse(file_path)\n        new_tree = self.modify_xml_tree(element_tree)  # type: ignore[arg-type]\n        # Create a temporary svg file to dump modified svg to be parsed\n        modified_file_path = file_path.with_name(f\"{file_path.stem}_{file_path.suffix}\")\n        new_tree.write(modified_file_path)\n\n        svg = se.SVG.parse(modified_file_path)\n        modified_file_path.unlink()\n\n        mobjects, mobject_dict = self.get_mobjects_from(svg)\n        self.add(*mobjects)\n        self.id_to_vgroup_dict = mobject_dict\n        self.flip(RIGHT)  # Flip y\n\n    def get_file_path(self) -> Path:\n        \"\"\"Search for an existing file based on the specified file name.\"\"\"\n        if self.file_name is None:\n            raise ValueError(\"Must specify file for SVGMobject\")\n        return get_full_vector_image_path(self.file_name)\n\n    def modify_xml_tree(self, element_tree: ET.ElementTree) -> ET.ElementTree:\n        \"\"\"Modifies the SVG element tree to include default\n        style information.\n\n        Parameters\n        ----------\n        element_tree\n            The parsed element tree from the SVG file.\n        \"\"\"\n        config_style_dict = self.generate_config_style_dict()\n        style_keys = (\n            \"fill\",\n            \"fill-opacity\",\n            \"stroke\",\n            \"stroke-opacity\",\n            \"stroke-width\",\n            \"style\",\n        )\n        root = element_tree.getroot()\n        root_style_dict = {k: v for k, v in root.attrib.items() if k in style_keys}  # type: ignore[union-attr]\n\n        new_root = ET.Element(\"svg\", {})\n        config_style_node = ET.SubElement(new_root, \"g\", config_style_dict)\n        root_style_node = ET.SubElement(config_style_node, \"g\", root_style_dict)\n        root_style_node.extend(root)  # type: ignore[arg-type]\n        return ET.ElementTree(new_root)\n\n    def generate_config_style_dict(self) -> dict[str, str]:\n        \"\"\"Generate a dictionary holding the default style information.\"\"\"\n        keys_converting_dict = {\n            \"fill\": (\"color\", \"fill_color\"),\n            \"fill-opacity\": (\"opacity\", \"fill_opacity\"),\n            \"stroke\": (\"color\", \"stroke_color\"),\n            \"stroke-opacity\": (\"opacity\", \"stroke_opacity\"),\n            \"stroke-width\": (\"stroke_width\",),\n        }\n        svg_default_dict = self.svg_default\n        result = {}\n        for svg_key, style_keys in keys_converting_dict.items():\n            for style_key in style_keys:\n                if svg_default_dict[style_key] is None:\n                    continue\n                result[svg_key] = str(svg_default_dict[style_key])\n        return result\n\n    def get_mobjects_from(\n        self, svg: se.SVG\n    ) -> tuple[list[VMobject], dict[str, VGroup]]:\n        \"\"\"Convert the elements of the SVG to a list of mobjects.\n\n        Parameters\n        ----------\n        svg\n            The parsed SVG file.\n        \"\"\"\n        result: list[VMobject] = []\n        stack: list[tuple[se.SVGElement, int]] = []\n        stack.append((svg, 1))\n        group_id_number = 0\n        vgroup_stack: list[str] = [\"root\"]\n        vgroup_names: list[str] = [\"root\"]\n        vgroups: dict[str, VGroup] = {\"root\": VGroup()}\n        while len(stack) > 0:\n            element, depth = stack.pop()\n            # Reduce stack heights\n            vgroup_stack = vgroup_stack[0:(depth)]\n            try:\n                group_name = str(element.values[\"id\"])\n            except Exception:\n                group_name = f\"numbered_group_{group_id_number}\"\n                group_id_number += 1\n            vg = VGroup()\n            vgroup_names.append(group_name)\n            vgroup_stack.append(group_name)\n            vgroups[group_name] = vg\n\n            if isinstance(element, (se.Group, se.Use)):\n                stack.extend((subelement, depth + 1) for subelement in element[::-1])\n            # Add element to the parent vgroup\n            try:\n                if isinstance(\n                    element,\n                    (\n                        se.Path,\n                        se.SimpleLine,\n                        se.Rect,\n                        se.Circle,\n                        se.Ellipse,\n                        se.Polygon,\n                        se.Polyline,\n                        se.Text,\n                    ),\n                ):\n                    mob = self.get_mob_from_shape_element(element)\n                    if mob is not None:\n                        result.append(mob)\n                        for parent_name in vgroup_stack[:-1]:\n                            vgroups[parent_name].add(mob)\n            except Exception as e:\n                logger.error(f\"Exception occurred in 'get_mobjects_from'. Details: {e}\")\n\n        return result, vgroups\n\n    def get_mob_from_shape_element(self, shape: se.SVGElement) -> VMobject | None:\n        if isinstance(shape, se.Path):\n            mob: VMobject | None = self.path_to_mobject(shape)\n        elif isinstance(shape, se.SimpleLine):\n            mob = self.line_to_mobject(shape)\n        elif isinstance(shape, se.Rect):\n            mob = self.rect_to_mobject(shape)\n        elif isinstance(shape, (se.Circle, se.Ellipse)):\n            mob = self.ellipse_to_mobject(shape)\n        elif isinstance(shape, se.Polygon):\n            mob = self.polygon_to_mobject(shape)\n        elif isinstance(shape, se.Polyline):\n            mob = self.polyline_to_mobject(shape)\n        elif isinstance(shape, se.Text):\n            mob = self.text_to_mobject(shape)\n        else:\n            logger.warning(f\"Unsupported element type: {type(shape)}\")\n            mob = None\n        if mob is None or not mob.has_points():\n            return mob\n        self.apply_style_to_mobject(mob, shape)\n        if isinstance(shape, se.Transformable) and shape.apply:\n            self.handle_transform(mob, shape.transform)\n        return mob\n\n    @staticmethod\n    def handle_transform(mob: VMobject, matrix: se.Matrix) -> VMobject:\n        \"\"\"Apply SVG transformations to the converted mobject.\n\n        Parameters\n        ----------\n        mob\n            The converted mobject.\n        matrix\n            The transformation matrix determined from the SVG\n            transformation.\n        \"\"\"\n        mat = np.array([[matrix.a, matrix.c], [matrix.b, matrix.d]])\n        vec = np.array([matrix.e, matrix.f, 0.0])\n        mob.apply_matrix(mat)\n        mob.shift(vec)\n        return mob\n\n    @staticmethod\n    def apply_style_to_mobject(mob: VMobject, shape: se.GraphicObject) -> VMobject:\n        \"\"\"Apply SVG style information to the converted mobject.\n\n        Parameters\n        ----------\n        mob\n            The converted mobject.\n        shape\n            The parsed SVG element.\n        \"\"\"\n        mob.set_style(\n            stroke_width=shape.stroke_width,\n            stroke_color=shape.stroke.hexrgb,\n            stroke_opacity=shape.stroke.opacity,\n            fill_color=shape.fill.hexrgb,\n            fill_opacity=shape.fill.opacity,\n        )\n        return mob\n\n    def path_to_mobject(self, path: se.Path) -> VMobjectFromSVGPath:\n        \"\"\"Convert a path element to a vectorized mobject.\n\n        Parameters\n        ----------\n        path\n            The parsed SVG path.\n        \"\"\"\n        return VMobjectFromSVGPath(path, **self.path_string_config)\n\n    @staticmethod\n    def line_to_mobject(line: se.Line) -> Line:\n        \"\"\"Convert a line element to a vectorized mobject.\n\n        Parameters\n        ----------\n        line\n            The parsed SVG line.\n        \"\"\"\n        return Line(\n            start=_convert_point_to_3d(line.x1, line.y1),\n            end=_convert_point_to_3d(line.x2, line.y2),\n        )\n\n    @staticmethod\n    def rect_to_mobject(rect: se.Rect) -> Rectangle:\n        \"\"\"Convert a rectangle element to a vectorized mobject.\n\n        Parameters\n        ----------\n        rect\n            The parsed SVG rectangle.\n        \"\"\"\n        if rect.rx == 0 or rect.ry == 0:\n            mob = Rectangle(\n                width=rect.width,\n                height=rect.height,\n            )\n        else:\n            mob = RoundedRectangle(\n                width=rect.width,\n                height=rect.height * rect.rx / rect.ry,\n                corner_radius=rect.rx,\n            )\n            mob.stretch_to_fit_height(rect.height)\n        mob.shift(\n            _convert_point_to_3d(rect.x + rect.width / 2, rect.y + rect.height / 2)\n        )\n        return mob\n\n    @staticmethod\n    def ellipse_to_mobject(ellipse: se.Ellipse | se.Circle) -> Circle:\n        \"\"\"Convert an ellipse or circle element to a vectorized mobject.\n\n        Parameters\n        ----------\n        ellipse\n            The parsed SVG ellipse or circle.\n        \"\"\"\n        mob = Circle(radius=ellipse.rx)\n        if ellipse.rx != ellipse.ry:\n            mob.stretch_to_fit_height(2 * ellipse.ry)\n        mob.shift(_convert_point_to_3d(ellipse.cx, ellipse.cy))\n        return mob\n\n    @staticmethod\n    def polygon_to_mobject(polygon: se.Polygon) -> Polygon:\n        \"\"\"Convert a polygon element to a vectorized mobject.\n\n        Parameters\n        ----------\n        polygon\n            The parsed SVG polygon.\n        \"\"\"\n        points = [_convert_point_to_3d(*point) for point in polygon]\n        return Polygon(*points)\n\n    def polyline_to_mobject(self, polyline: se.Polyline) -> VMobject:\n        \"\"\"Convert a polyline element to a vectorized mobject.\n\n        Parameters\n        ----------\n        polyline\n            The parsed SVG polyline.\n        \"\"\"\n        points = [_convert_point_to_3d(*point) for point in polyline]\n        vmobject_class = self.get_mobject_type_class()\n        return vmobject_class().set_points_as_corners(points)\n\n    @staticmethod\n    def text_to_mobject(text: se.Text) -> VMobject:\n        \"\"\"Convert a text element to a vectorized mobject.\n\n        .. warning::\n\n            Not yet implemented.\n\n        Parameters\n        ----------\n        text\n            The parsed SVG text.\n        \"\"\"\n        logger.warning(f\"Unsupported element type: {type(text)}\")\n        return  # type: ignore[return-value]\n\n    def move_into_position(self) -> None:\n        \"\"\"Scale and move the generated mobject into position.\"\"\"\n        if self.should_center:\n            self.center()\n        if self.svg_height is not None:\n            self.set(height=self.svg_height)\n        if self.svg_width is not None:\n            self.set(width=self.svg_width)\n\n\nclass VMobjectFromSVGPath(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A vectorized mobject representing an SVG path.\n\n    .. note::\n\n        The ``long_lines``, ``should_subdivide_sharp_curves``,\n        and ``should_remove_null_curves`` keyword arguments are\n        only respected with the OpenGL renderer.\n\n    Parameters\n    ----------\n    path_obj\n        A parsed SVG path object.\n    long_lines\n        Whether or not straight lines in the vectorized mobject\n        are drawn in one or two segments.\n    should_subdivide_sharp_curves\n        Whether or not to subdivide subcurves further in case\n        two segments meet at an angle that is sharper than a\n        given threshold.\n    should_remove_null_curves\n        Whether or not to remove subcurves of length 0.\n    kwargs\n        Further keyword arguments are passed to the parent\n        class.\n    \"\"\"\n\n    def __init__(\n        self,\n        path_obj: se.Path,\n        long_lines: bool = False,\n        should_subdivide_sharp_curves: bool = False,\n        should_remove_null_curves: bool = False,\n        **kwargs: Any,\n    ):\n        # Get rid of arcs\n        path_obj.approximate_arcs_with_quads()\n        self.path_obj = path_obj\n\n        self.long_lines = long_lines\n        self.should_subdivide_sharp_curves = should_subdivide_sharp_curves\n        self.should_remove_null_curves = should_remove_null_curves\n\n        super().__init__(**kwargs)\n\n    def generate_points(self) -> None:\n        # TODO: cache mobject in a re-importable way\n\n        self.handle_commands()\n\n        if config.renderer == \"opengl\":\n            if self.should_subdivide_sharp_curves:\n                # For a healthy triangulation later\n                self.subdivide_sharp_curves()\n            if self.should_remove_null_curves:\n                # Get rid of any null curves\n                self.set_points(self.get_points_without_null_curves())\n\n    def init_points(self) -> None:\n        self.generate_points()\n\n    def handle_commands(self) -> None:\n        all_points: list[np.ndarray] = []\n        last_move: np.ndarray = None\n        curve_start = None\n        last_true_move = None\n\n        def move_pen(pt: np.ndarray, *, true_move: bool = False) -> None:\n            nonlocal last_move, curve_start, last_true_move\n            last_move = pt\n            if curve_start is None:\n                curve_start = last_move\n            if true_move:\n                last_true_move = last_move\n\n        if self.n_points_per_curve == 4:\n\n            def add_cubic(\n                start: np.ndarray, cp1: np.ndarray, cp2: np.ndarray, end: np.ndarray\n            ) -> None:\n                nonlocal all_points\n                assert len(all_points) % 4 == 0, len(all_points)\n                all_points += [start, cp1, cp2, end]\n                move_pen(end)\n\n            def add_quad(start: np.ndarray, cp: np.ndarray, end: np.ndarray) -> None:\n                add_cubic(start, (start + cp + cp) / 3, (cp + cp + end) / 3, end)\n                move_pen(end)\n\n            def add_line(start: np.ndarray, end: np.ndarray) -> None:\n                add_cubic(\n                    start, (start + start + end) / 3, (start + end + end) / 3, end\n                )\n                move_pen(end)\n\n        else:\n\n            def add_cubic(\n                start: np.ndarray, cp1: np.ndarray, cp2: np.ndarray, end: np.ndarray\n            ) -> None:\n                nonlocal all_points\n                assert len(all_points) % 3 == 0, len(all_points)\n                two_quads = get_quadratic_approximation_of_cubic(\n                    start,\n                    cp1,\n                    cp2,\n                    end,\n                )\n                all_points += two_quads[:3].tolist()\n                all_points += two_quads[3:].tolist()\n                move_pen(end)\n\n            def add_quad(start: np.ndarray, cp: np.ndarray, end: np.ndarray) -> None:\n                nonlocal all_points\n                assert len(all_points) % 3 == 0, len(all_points)\n                all_points += [start, cp, end]\n                move_pen(end)\n\n            def add_line(start: np.ndarray, end: np.ndarray) -> None:\n                add_quad(start, (start + end) / 2, end)\n                move_pen(end)\n\n        for segment in self.path_obj:\n            segment_class = segment.__class__\n            if segment_class == se.Move:\n                move_pen(_convert_point_to_3d(*segment.end), true_move=True)\n            elif segment_class == se.Line:\n                add_line(last_move, _convert_point_to_3d(*segment.end))\n            elif segment_class == se.QuadraticBezier:\n                add_quad(\n                    last_move,\n                    _convert_point_to_3d(*segment.control),\n                    _convert_point_to_3d(*segment.end),\n                )\n            elif segment_class == se.CubicBezier:\n                add_cubic(\n                    last_move,\n                    _convert_point_to_3d(*segment.control1),\n                    _convert_point_to_3d(*segment.control2),\n                    _convert_point_to_3d(*segment.end),\n                )\n            elif segment_class == se.Close:\n                # If the SVG path naturally ends at the beginning of the curve,\n                # we do *not* need to draw a closing line. To account for floating\n                # point precision, we use a small value to compare the two points.\n                if abs(np.linalg.norm(last_move - last_true_move)) > 0.0001:\n                    add_line(last_move, last_true_move)\n                curve_start = None\n            else:\n                raise AssertionError(f\"Not implemented: {segment_class}\")\n\n        self.points = np.array(all_points, ndmin=2, dtype=\"float64\")\n        # If we have no points, make sure the array is shaped properly\n        # (0 rows tall by 3 columns wide) so future operations can\n        # add or remove points correctly.\n        if len(all_points) == 0:\n            self.points = np.reshape(self.points, (0, 3))\n"
  },
  {
    "path": "manim/mobject/table.py",
    "content": "r\"\"\"Mobjects representing tables.\n\nExamples\n--------\n\n.. manim:: TableExamples\n    :save_last_frame:\n\n    class TableExamples(Scene):\n        def construct(self):\n            t0 = Table(\n                [[\"First\", \"Second\"],\n                [\"Third\",\"Fourth\"]],\n                row_labels=[Text(\"R1\"), Text(\"R2\")],\n                col_labels=[Text(\"C1\"), Text(\"C2\")],\n                top_left_entry=Text(\"TOP\"))\n            t0.add_highlighted_cell((2,2), color=GREEN)\n            x_vals = np.linspace(-2,2,5)\n            y_vals = np.exp(x_vals)\n            t1 = DecimalTable(\n                [x_vals, y_vals],\n                row_labels=[MathTex(\"x\"), MathTex(\"f(x)\")],\n                include_outer_lines=True)\n            t1.add(t1.get_cell((2,2), color=RED))\n            t2 = MathTable(\n                [[\"+\", 0, 5, 10],\n                [0, 0, 5, 10],\n                [2, 2, 7, 12],\n                [4, 4, 9, 14]],\n                include_outer_lines=True)\n            t2.get_horizontal_lines()[:3].set_color(BLUE)\n            t2.get_vertical_lines()[:3].set_color(BLUE)\n            t2.get_horizontal_lines()[:3].set_z_index(1)\n            cross = VGroup(\n                Line(UP + LEFT, DOWN + RIGHT),\n                Line(UP + RIGHT, DOWN + LEFT))\n            a = Circle().set_color(RED).scale(0.5)\n            b = cross.set_color(BLUE).scale(0.5)\n            t3 = MobjectTable(\n                [[a.copy(),b.copy(),a.copy()],\n                [b.copy(),a.copy(),a.copy()],\n                [a.copy(),b.copy(),b.copy()]])\n            t3.add(Line(\n                t3.get_corner(DL), t3.get_corner(UR)\n            ).set_color(RED))\n            vals = np.arange(1,21).reshape(5,4)\n            t4 = IntegerTable(\n                vals,\n                include_outer_lines=True\n            )\n            g1 = Group(t0, t1).scale(0.5).arrange(buff=1).to_edge(UP, buff=1)\n            g2 = Group(t2, t3, t4).scale(0.5).arrange(buff=1).to_edge(DOWN, buff=1)\n            self.add(g1, g2)\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"Table\",\n    \"MathTable\",\n    \"MobjectTable\",\n    \"IntegerTable\",\n    \"DecimalTable\",\n]\n\n\nimport itertools as it\nfrom collections.abc import Callable, Iterable, Sequence\n\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.geometry.polygram import Polygon\nfrom manim.mobject.geometry.shape_matchers import BackgroundRectangle\nfrom manim.mobject.text.numbers import DecimalNumber, Integer\nfrom manim.mobject.text.tex_mobject import MathTex\nfrom manim.mobject.text.text_mobject import Paragraph\n\nfrom ..animation.animation import Animation\nfrom ..animation.composition import AnimationGroup\nfrom ..animation.creation import Create, Write\nfrom ..animation.fading import FadeIn\nfrom ..mobject.types.vectorized_mobject import VGroup, VMobject\nfrom ..utils.color import BLACK, PURE_YELLOW, ManimColor, ParsableManimColor\nfrom .utils import get_vectorized_mobject_class\n\n\nclass Table(VGroup):\n    r\"\"\"A mobject that displays a table on the screen.\n\n    Parameters\n    ----------\n    table\n        A 2D array or list of lists. Content of the table has to be a valid input\n        for the callable set in ``element_to_mobject``.\n    row_labels\n        List of :class:`~.VMobject` representing the labels of each row.\n    col_labels\n        List of :class:`~.VMobject` representing the labels of each column.\n    top_left_entry\n        The top-left entry of the table, can only be specified if row and\n        column labels are given.\n    v_buff\n        Vertical buffer passed to :meth:`~.Mobject.arrange_in_grid`, by default 0.8.\n    h_buff\n        Horizontal buffer passed to :meth:`~.Mobject.arrange_in_grid`, by default 1.3.\n    include_outer_lines\n        ``True`` if the table should include outer lines, by default False.\n    add_background_rectangles_to_entries\n        ``True`` if background rectangles should be added to entries, by default ``False``.\n    entries_background_color\n        Background color of entries if ``add_background_rectangles_to_entries`` is ``True``.\n    include_background_rectangle\n        ``True`` if the table should have a background rectangle, by default ``False``.\n    background_rectangle_color\n        Background color of table if ``include_background_rectangle`` is ``True``.\n    element_to_mobject\n        The :class:`~.Mobject` class applied to the table entries. by default :class:`~.Paragraph`. For common choices, see :mod:`~.text_mobject`/:mod:`~.tex_mobject`.\n    element_to_mobject_config\n        Custom configuration passed to :attr:`element_to_mobject`, by default {}.\n    arrange_in_grid_config\n        Dict passed to :meth:`~.Mobject.arrange_in_grid`, customizes the arrangement of the table.\n    line_config\n        Dict passed to :class:`~.Line`, customizes the lines of the table.\n    kwargs\n        Additional arguments to be passed to :class:`~.VGroup`.\n\n    Examples\n    --------\n\n    .. manim:: TableExamples\n        :save_last_frame:\n\n        class TableExamples(Scene):\n            def construct(self):\n                t0 = Table(\n                    [[\"This\", \"is a\"],\n                    [\"simple\", \"Table in \\\\n Manim.\"]])\n                t1 = Table(\n                    [[\"This\", \"is a\"],\n                    [\"simple\", \"Table.\"]],\n                    row_labels=[Text(\"R1\"), Text(\"R2\")],\n                    col_labels=[Text(\"C1\"), Text(\"C2\")])\n                t1.add_highlighted_cell((2,2), color=YELLOW)\n                t2 = Table(\n                    [[\"This\", \"is a\"],\n                    [\"simple\", \"Table.\"]],\n                    row_labels=[Text(\"R1\"), Text(\"R2\")],\n                    col_labels=[Text(\"C1\"), Text(\"C2\")],\n                    top_left_entry=Star().scale(0.3),\n                    include_outer_lines=True,\n                    arrange_in_grid_config={\"cell_alignment\": RIGHT})\n                t2.add(t2.get_cell((2,2), color=RED))\n                t3 = Table(\n                    [[\"This\", \"is a\"],\n                    [\"simple\", \"Table.\"]],\n                    row_labels=[Text(\"R1\"), Text(\"R2\")],\n                    col_labels=[Text(\"C1\"), Text(\"C2\")],\n                    top_left_entry=Star().scale(0.3),\n                    include_outer_lines=True,\n                    line_config={\"stroke_width\": 1, \"color\": YELLOW})\n                t3.remove(*t3.get_vertical_lines())\n                g = Group(\n                    t0,t1,t2,t3\n                ).scale(0.7).arrange_in_grid(buff=1)\n                self.add(g)\n\n    .. manim:: BackgroundRectanglesExample\n        :save_last_frame:\n\n        class BackgroundRectanglesExample(Scene):\n            def construct(self):\n                background = Rectangle(height=6.5, width=13)\n                background.set_fill(opacity=.5)\n                background.set_color([TEAL, RED, YELLOW])\n                self.add(background)\n                t0 = Table(\n                    [[\"This\", \"is a\"],\n                    [\"simple\", \"Table.\"]],\n                    add_background_rectangles_to_entries=True)\n                t1 = Table(\n                    [[\"This\", \"is a\"],\n                    [\"simple\", \"Table.\"]],\n                    include_background_rectangle=True)\n                g = Group(t0, t1).scale(0.7).arrange(buff=0.5)\n                self.add(g)\n    \"\"\"\n\n    def __init__(\n        self,\n        table: Iterable[Iterable[float | str | VMobject]],\n        row_labels: Iterable[VMobject] | None = None,\n        col_labels: Iterable[VMobject] | None = None,\n        top_left_entry: VMobject | None = None,\n        v_buff: float = 0.8,\n        h_buff: float = 1.3,\n        include_outer_lines: bool = False,\n        add_background_rectangles_to_entries: bool = False,\n        entries_background_color: ParsableManimColor = BLACK,\n        include_background_rectangle: bool = False,\n        background_rectangle_color: ParsableManimColor = BLACK,\n        element_to_mobject: Callable[\n            [float | str | VMobject],\n            VMobject,\n        ] = Paragraph,\n        element_to_mobject_config: dict = {},\n        arrange_in_grid_config: dict = {},\n        line_config: dict = {},\n        **kwargs,\n    ):\n        self.row_labels = row_labels\n        self.col_labels = col_labels\n        self.top_left_entry = top_left_entry\n        self.row_dim = len(table)\n        self.col_dim = len(table[0])\n        self.v_buff = v_buff\n        self.h_buff = h_buff\n        self.include_outer_lines = include_outer_lines\n        self.add_background_rectangles_to_entries = add_background_rectangles_to_entries\n        self.entries_background_color = ManimColor(entries_background_color)\n        self.include_background_rectangle = include_background_rectangle\n        self.background_rectangle_color = ManimColor(background_rectangle_color)\n        self.element_to_mobject = element_to_mobject\n        self.element_to_mobject_config = element_to_mobject_config\n        self.arrange_in_grid_config = arrange_in_grid_config\n        self.line_config = line_config\n\n        for row in table:\n            if len(row) == len(table[0]):\n                pass\n            else:\n                raise ValueError(\"Not all rows in table have the same length.\")\n\n        super().__init__(**kwargs)\n        mob_table = self._table_to_mob_table(table)\n        self.elements_without_labels = VGroup(*it.chain(*mob_table))\n        mob_table = self._add_labels(mob_table)\n        self._organize_mob_table(mob_table)\n        self.elements = VGroup(*it.chain(*mob_table))\n\n        if len(self.elements[0].get_all_points()) == 0:\n            self.elements.remove(self.elements[0])\n\n        self.add(self.elements)\n        self.center()\n        self.mob_table = mob_table\n        self._add_horizontal_lines()\n        self._add_vertical_lines()\n        if self.add_background_rectangles_to_entries:\n            self.add_background_to_entries(color=self.entries_background_color)\n        if self.include_background_rectangle:\n            self.add_background_rectangle(color=self.background_rectangle_color)\n\n    def _table_to_mob_table(\n        self,\n        table: Iterable[Iterable[float | str | VMobject]],\n    ) -> list:\n        \"\"\"Initializes the entries of ``table`` as :class:`~.VMobject`.\n\n        Parameters\n        ----------\n        table\n            A 2D array or list of lists. Content of the table has to be a valid input\n            for the callable set in ``element_to_mobject``.\n\n        Returns\n        --------\n        List\n            List of :class:`~.VMobject` from the entries of ``table``.\n        \"\"\"\n        return [\n            [\n                self.element_to_mobject(item, **self.element_to_mobject_config)\n                for item in row\n            ]\n            for row in table\n        ]\n\n    def _organize_mob_table(self, table: Iterable[Iterable[VMobject]]) -> VGroup:\n        \"\"\"Arranges the :class:`~.VMobject` of ``table`` in a grid.\n\n        Parameters\n        ----------\n        table\n            A 2D iterable object with :class:`~.VMobject` entries.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            The :class:`~.VMobject` of the ``table`` in a :class:`~.VGroup` already\n            arranged in a table-like grid.\n        \"\"\"\n        help_table = VGroup()\n        for i, row in enumerate(table):\n            for j, _ in enumerate(row):\n                help_table.add(table[i][j])\n        help_table.arrange_in_grid(\n            rows=len(table),\n            cols=len(table[0]),\n            buff=(self.h_buff, self.v_buff),\n            **self.arrange_in_grid_config,\n        )\n        return help_table\n\n    def _add_labels(self, mob_table: VGroup) -> VGroup:\n        \"\"\"Adds labels to an in a grid arranged :class:`~.VGroup`.\n\n        Parameters\n        ----------\n        mob_table\n            An in a grid organized class:`~.VGroup`.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            Returns the ``mob_table`` with added labels.\n        \"\"\"\n        if self.row_labels is not None:\n            for k in range(len(self.row_labels)):\n                mob_table[k] = [self.row_labels[k]] + mob_table[k]\n        if self.col_labels is not None:\n            if self.row_labels is not None:\n                if self.top_left_entry is not None:\n                    col_labels = [self.top_left_entry] + self.col_labels\n                    mob_table.insert(0, col_labels)\n                else:\n                    # Placeholder to use arrange_in_grid if top_left_entry is not set.\n                    # Import OpenGLVMobject to work with --renderer=opengl\n                    dummy_mobject = get_vectorized_mobject_class()()\n                    col_labels = [dummy_mobject] + self.col_labels\n                    mob_table.insert(0, col_labels)\n            else:\n                mob_table.insert(0, self.col_labels)\n        return mob_table\n\n    def _add_horizontal_lines(self) -> Table:\n        \"\"\"Adds the horizontal lines to the table.\"\"\"\n        anchor_left = self.get_left()[0] - 0.5 * self.h_buff\n        anchor_right = self.get_right()[0] + 0.5 * self.h_buff\n        line_group = VGroup()\n        if self.include_outer_lines:\n            anchor = self.get_rows()[0].get_top()[1] + 0.5 * self.v_buff\n            line = Line(\n                [anchor_left, anchor, 0], [anchor_right, anchor, 0], **self.line_config\n            )\n            line_group.add(line)\n            self.add(line)\n            anchor = self.get_rows()[-1].get_bottom()[1] - 0.5 * self.v_buff\n            line = Line(\n                [anchor_left, anchor, 0], [anchor_right, anchor, 0], **self.line_config\n            )\n            line_group.add(line)\n            self.add(line)\n        for k in range(len(self.mob_table) - 1):\n            anchor = self.get_rows()[k + 1].get_top()[1] + 0.5 * (\n                self.get_rows()[k].get_bottom()[1] - self.get_rows()[k + 1].get_top()[1]\n            )\n            line = Line(\n                [anchor_left, anchor, 0], [anchor_right, anchor, 0], **self.line_config\n            )\n            line_group.add(line)\n            self.add(line)\n        self.horizontal_lines = line_group\n        return self\n\n    def _add_vertical_lines(self) -> Table:\n        \"\"\"Adds the vertical lines to the table\"\"\"\n        anchor_top = self.get_rows().get_top()[1] + 0.5 * self.v_buff\n        anchor_bottom = self.get_rows().get_bottom()[1] - 0.5 * self.v_buff\n        line_group = VGroup()\n        if self.include_outer_lines:\n            anchor = self.get_columns()[0].get_left()[0] - 0.5 * self.h_buff\n            line = Line(\n                [anchor, anchor_top, 0], [anchor, anchor_bottom, 0], **self.line_config\n            )\n            line_group.add(line)\n            self.add(line)\n            anchor = self.get_columns()[-1].get_right()[0] + 0.5 * self.h_buff\n            line = Line(\n                [anchor, anchor_top, 0], [anchor, anchor_bottom, 0], **self.line_config\n            )\n            line_group.add(line)\n            self.add(line)\n        for k in range(len(self.mob_table[0]) - 1):\n            anchor = self.get_columns()[k + 1].get_left()[0] + 0.5 * (\n                self.get_columns()[k].get_right()[0]\n                - self.get_columns()[k + 1].get_left()[0]\n            )\n            line = Line(\n                [anchor, anchor_bottom, 0], [anchor, anchor_top, 0], **self.line_config\n            )\n            line_group.add(line)\n            self.add(line)\n        self.vertical_lines = line_group\n        return self\n\n    def get_horizontal_lines(self) -> VGroup:\n        \"\"\"Return the horizontal lines of the table.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            :class:`~.VGroup` containing all the horizontal lines of the table.\n\n        Examples\n        --------\n\n        .. manim:: GetHorizontalLinesExample\n            :save_last_frame:\n\n            class GetHorizontalLinesExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    table.get_horizontal_lines().set_color(RED)\n                    self.add(table)\n        \"\"\"\n        return self.horizontal_lines\n\n    def get_vertical_lines(self) -> VGroup:\n        \"\"\"Return the vertical lines of the table.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            :class:`~.VGroup` containing all the vertical lines of the table.\n\n        Examples\n        --------\n\n        .. manim:: GetVerticalLinesExample\n            :save_last_frame:\n\n            class GetVerticalLinesExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    table.get_vertical_lines()[0].set_color(RED)\n                    self.add(table)\n        \"\"\"\n        return self.vertical_lines\n\n    def get_columns(self) -> VGroup:\n        \"\"\"Return columns of the table as a :class:`~.VGroup` of :class:`~.VGroup`.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            :class:`~.VGroup` containing each column in a :class:`~.VGroup`.\n\n        Examples\n        --------\n\n        .. manim:: GetColumnsExample\n            :save_last_frame:\n\n            class GetColumnsExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    table.add(SurroundingRectangle(table.get_columns()[1]))\n                    self.add(table)\n        \"\"\"\n        return VGroup(\n            *(\n                VGroup(*(row[i] for row in self.mob_table))\n                for i in range(len(self.mob_table[0]))\n            )\n        )\n\n    def get_rows(self) -> VGroup:\n        \"\"\"Return the rows of the table as a :class:`~.VGroup` of :class:`~.VGroup`.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            :class:`~.VGroup` containing each row in a :class:`~.VGroup`.\n\n        Examples\n        --------\n\n        .. manim:: GetRowsExample\n            :save_last_frame:\n\n            class GetRowsExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    table.add(SurroundingRectangle(table.get_rows()[1]))\n                    self.add(table)\n        \"\"\"\n        return VGroup(*(VGroup(*row) for row in self.mob_table))\n\n    def set_column_colors(self, *colors: Iterable[ParsableManimColor]) -> Table:\n        \"\"\"Set individual colors for each column of the table.\n\n        Parameters\n        ----------\n        colors\n            An iterable of colors; each color corresponds to a column.\n\n        Examples\n        --------\n\n        .. manim:: SetColumnColorsExample\n            :save_last_frame:\n\n            class SetColumnColorsExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")]\n                    ).set_column_colors([RED,BLUE], GREEN)\n                    self.add(table)\n        \"\"\"\n        columns = self.get_columns()\n        for color, column in zip(colors, columns, strict=False):\n            column.set_color(color)\n        return self\n\n    def set_row_colors(self, *colors: Iterable[ParsableManimColor]) -> Table:\n        \"\"\"Set individual colors for each row of the table.\n\n        Parameters\n        ----------\n        colors\n            An iterable of colors; each color corresponds to a row.\n\n        Examples\n        --------\n\n        .. manim:: SetRowColorsExample\n            :save_last_frame:\n\n            class SetRowColorsExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")]\n                    ).set_row_colors([RED,BLUE], GREEN)\n                    self.add(table)\n        \"\"\"\n        rows = self.get_rows()\n        for color, row in zip(colors, rows, strict=False):\n            row.set_color(color)\n        return self\n\n    def get_entries(\n        self,\n        pos: Sequence[int] | None = None,\n    ) -> VMobject | VGroup:\n        \"\"\"Return the individual entries of the table (including labels) or one specific entry\n        if the parameter, ``pos``,  is set.\n\n        Parameters\n        ----------\n        pos\n            The position of a specific entry on the table. ``(1,1)`` being the top left entry\n            of the table.\n\n        Returns\n        -------\n        Union[:class:`~.VMobject`, :class:`~.VGroup`]\n            :class:`~.VGroup` containing all entries of the table (including labels)\n            or the :class:`~.VMobject` at the given position if ``pos`` is set.\n\n        Examples\n        --------\n\n        .. manim:: GetEntriesExample\n            :save_last_frame:\n\n            class GetEntriesExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    ent = table.get_entries()\n                    for item in ent:\n                        item.set_color(random_bright_color())\n                    table.get_entries((2,2)).rotate(PI)\n                    self.add(table)\n        \"\"\"\n        if pos is not None:\n            if (\n                self.row_labels is not None\n                and self.col_labels is not None\n                and self.top_left_entry is None\n            ):\n                index = len(self.mob_table[0]) * (pos[0] - 1) + pos[1] - 2\n                return self.elements[index]\n            else:\n                index = len(self.mob_table[0]) * (pos[0] - 1) + pos[1] - 1\n                return self.elements[index]\n        else:\n            return self.elements\n\n    def get_entries_without_labels(\n        self,\n        pos: Sequence[int] | None = None,\n    ) -> VMobject | VGroup:\n        \"\"\"Return the individual entries of the table (without labels) or one specific entry\n        if the parameter, ``pos``, is set.\n\n        Parameters\n        ----------\n        pos\n            The position of a specific entry on the table. ``(1,1)`` being the top left entry\n            of the table (without labels).\n\n        Returns\n        -------\n        Union[:class:`~.VMobject`, :class:`~.VGroup`]\n            :class:`~.VGroup` containing all entries of the table (without labels)\n            or the :class:`~.VMobject` at the given position if ``pos`` is set.\n\n        Examples\n        --------\n\n        .. manim:: GetEntriesWithoutLabelsExample\n            :save_last_frame:\n\n            class GetEntriesWithoutLabelsExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    ent = table.get_entries_without_labels()\n                    colors = [BLUE, GREEN, YELLOW, RED]\n                    for k in range(len(colors)):\n                        ent[k].set_color(colors[k])\n                    table.get_entries_without_labels((2,2)).rotate(PI)\n                    self.add(table)\n        \"\"\"\n        if pos is not None:\n            index = self.col_dim * (pos[0] - 1) + pos[1] - 1\n            return self.elements_without_labels[index]\n        else:\n            return self.elements_without_labels\n\n    def get_row_labels(self) -> VGroup:\n        \"\"\"Return the row labels of the table.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            :class:`~.VGroup` containing the row labels of the table.\n\n        Examples\n        --------\n\n        .. manim:: GetRowLabelsExample\n            :save_last_frame:\n\n            class GetRowLabelsExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    lab = table.get_row_labels()\n                    for item in lab:\n                        item.set_color(random_bright_color())\n                    self.add(table)\n        \"\"\"\n        return VGroup(*self.row_labels)\n\n    def get_col_labels(self) -> VGroup:\n        \"\"\"Return the column labels of the table.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            VGroup containing the column labels of the table.\n\n        Examples\n        --------\n\n        .. manim:: GetColLabelsExample\n            :save_last_frame:\n\n            class GetColLabelsExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    lab = table.get_col_labels()\n                    for item in lab:\n                        item.set_color(random_bright_color())\n                    self.add(table)\n        \"\"\"\n        return VGroup(*self.col_labels)\n\n    def get_labels(self) -> VGroup:\n        \"\"\"Returns the labels of the table.\n\n        Returns\n        --------\n        :class:`~.VGroup`\n            :class:`~.VGroup` containing all the labels of the table.\n\n        Examples\n        --------\n\n        .. manim:: GetLabelsExample\n            :save_last_frame:\n\n            class GetLabelsExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    lab = table.get_labels()\n                    colors = [BLUE, GREEN, YELLOW, RED]\n                    for k in range(len(colors)):\n                        lab[k].set_color(colors[k])\n                    self.add(table)\n        \"\"\"\n        label_group = VGroup()\n        if self.top_left_entry is not None:\n            label_group.add(self.top_left_entry)\n        for label in (self.col_labels, self.row_labels):\n            if label is not None:\n                label_group.add(*label)\n        return label_group\n\n    def add_background_to_entries(self, color: ParsableManimColor = BLACK) -> Table:\n        \"\"\"Adds a black :class:`~.BackgroundRectangle` to each entry of the table.\"\"\"\n        for mob in self.get_entries():\n            mob.add_background_rectangle(color=ManimColor(color))\n        return self\n\n    def get_cell(self, pos: Sequence[int] = (1, 1), **kwargs) -> Polygon:\n        \"\"\"Returns one specific cell as a rectangular :class:`~.Polygon` without the entry.\n\n        Parameters\n        ----------\n        pos\n            The position of a specific entry on the table. ``(1,1)`` being the top left entry\n            of the table.\n        kwargs\n            Additional arguments to be passed to :class:`~.Polygon`.\n\n        Returns\n        -------\n        :class:`~.Polygon`\n            Polygon mimicking one specific cell of the Table.\n\n        Examples\n        --------\n\n        .. manim:: GetCellExample\n            :save_last_frame:\n\n            class GetCellExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    cell = table.get_cell((2,2), color=RED)\n                    self.add(table, cell)\n        \"\"\"\n        row = self.get_rows()[pos[0] - 1]\n        col = self.get_columns()[pos[1] - 1]\n        edge_UL = [\n            col.get_left()[0] - self.h_buff / 2,\n            row.get_top()[1] + self.v_buff / 2,\n            0,\n        ]\n        edge_UR = [\n            col.get_right()[0] + self.h_buff / 2,\n            row.get_top()[1] + self.v_buff / 2,\n            0,\n        ]\n        edge_DL = [\n            col.get_left()[0] - self.h_buff / 2,\n            row.get_bottom()[1] - self.v_buff / 2,\n            0,\n        ]\n        edge_DR = [\n            col.get_right()[0] + self.h_buff / 2,\n            row.get_bottom()[1] - self.v_buff / 2,\n            0,\n        ]\n        rec = Polygon(edge_UL, edge_UR, edge_DR, edge_DL, **kwargs)\n        return rec\n\n    def get_highlighted_cell(\n        self,\n        pos: Sequence[int] = (1, 1),\n        color: ParsableManimColor = PURE_YELLOW,\n        **kwargs,\n    ) -> BackgroundRectangle:\n        \"\"\"Returns a :class:`~.BackgroundRectangle` of the cell at the given position.\n\n        Parameters\n        ----------\n        pos\n            The position of a specific entry on the table. ``(1,1)`` being the top left entry\n            of the table.\n        color\n            The color used to highlight the cell.\n        kwargs\n            Additional arguments to be passed to :class:`~.BackgroundRectangle`.\n\n        Examples\n        --------\n\n        .. manim:: GetHighlightedCellExample\n            :save_last_frame:\n\n            class GetHighlightedCellExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    highlight = table.get_highlighted_cell((2,2), color=GREEN)\n                    table.add_to_back(highlight)\n                    self.add(table)\n        \"\"\"\n        cell = self.get_cell(pos)\n        bg_cell = BackgroundRectangle(cell, color=ManimColor(color), **kwargs)\n        return bg_cell\n\n    def add_highlighted_cell(\n        self,\n        pos: Sequence[int] = (1, 1),\n        color: ParsableManimColor = PURE_YELLOW,\n        **kwargs,\n    ) -> Table:\n        \"\"\"Highlights one cell at a specific position on the table by adding a :class:`~.BackgroundRectangle`.\n\n        Parameters\n        ----------\n        pos\n            The position of a specific entry on the table. ``(1,1)`` being the top left entry\n            of the table.\n        color\n            The color used to highlight the cell.\n        kwargs\n            Additional arguments to be passed to :class:`~.BackgroundRectangle`.\n\n        Examples\n        --------\n\n        .. manim:: AddHighlightedCellExample\n            :save_last_frame:\n\n            class AddHighlightedCellExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")])\n                    table.add_highlighted_cell((2,2), color=GREEN)\n                    self.add(table)\n        \"\"\"\n        bg_cell = self.get_highlighted_cell(pos, color=ManimColor(color), **kwargs)\n        self.add_to_back(bg_cell)\n        entry = self.get_entries(pos)\n        entry.background_rectangle = bg_cell\n        return self\n\n    def create(\n        self,\n        lag_ratio: float = 1,\n        line_animation: Callable[[VMobject | VGroup], Animation] = Create,\n        label_animation: Callable[[VMobject | VGroup], Animation] = Write,\n        element_animation: Callable[[VMobject | VGroup], Animation] = Create,\n        entry_animation: Callable[[VMobject | VGroup], Animation] = FadeIn,\n        **kwargs,\n    ) -> AnimationGroup:\n        \"\"\"Customized create-type function for tables.\n\n        Parameters\n        ----------\n        lag_ratio\n            The lag ratio of the animation.\n        line_animation\n            The animation style of the table lines, see :mod:`~.creation` for examples.\n        label_animation\n            The animation style of the table labels, see :mod:`~.creation` for examples.\n        element_animation\n            The animation style of the table elements, see :mod:`~.creation` for examples.\n        entry_animation\n            The entry animation of the table background, see :mod:`~.creation` for examples.\n        kwargs\n            Further arguments passed to the creation animations.\n\n        Returns\n        -------\n        :class:`~.AnimationGroup`\n            AnimationGroup containing creation of the lines and of the elements.\n\n        Examples\n        --------\n\n        .. manim:: CreateTableExample\n\n            class CreateTableExample(Scene):\n                def construct(self):\n                    table = Table(\n                        [[\"First\", \"Second\"],\n                        [\"Third\",\"Fourth\"]],\n                        row_labels=[Text(\"R1\"), Text(\"R2\")],\n                        col_labels=[Text(\"C1\"), Text(\"C2\")],\n                        include_outer_lines=True)\n                    self.play(table.create())\n                    self.wait()\n        \"\"\"\n        animations: Sequence[Animation] = [\n            line_animation(\n                VGroup(self.vertical_lines, self.horizontal_lines),\n                **kwargs,\n            ),\n            element_animation(self.elements_without_labels.set_z_index(2), **kwargs),\n        ]\n\n        if self.get_labels():\n            animations += [\n                label_animation(self.get_labels(), **kwargs),\n            ]\n\n        if self.get_entries():\n            for entry in self.elements_without_labels:\n                try:\n                    animations += [\n                        entry_animation(\n                            entry.background_rectangle,\n                            **kwargs,\n                        )\n                    ]\n                except AttributeError:\n                    continue\n\n        return AnimationGroup(*animations, lag_ratio=lag_ratio)\n\n    def scale(self, scale_factor: float, **kwargs):\n        # h_buff and v_buff must be adjusted so that Table.get_cell\n        # can construct an accurate polygon for a cell.\n        self.h_buff *= scale_factor\n        self.v_buff *= scale_factor\n        super().scale(scale_factor, **kwargs)\n        return self\n\n\nclass MathTable(Table):\n    \"\"\"A specialized :class:`~.Table` mobject for use with LaTeX.\n\n    Examples\n    --------\n\n    .. manim:: MathTableExample\n        :save_last_frame:\n\n        class MathTableExample(Scene):\n            def construct(self):\n                t0 = MathTable(\n                    [[\"+\", 0, 5, 10],\n                    [0, 0, 5, 10],\n                    [2, 2, 7, 12],\n                    [4, 4, 9, 14]],\n                    include_outer_lines=True)\n                self.add(t0)\n    \"\"\"\n\n    def __init__(\n        self,\n        table: Iterable[Iterable[float | str]],\n        element_to_mobject: Callable[[float | str], VMobject] = MathTex,\n        **kwargs,\n    ):\n        \"\"\"\n        Special case of :class:`~.Table` with `element_to_mobject` set to :class:`~.MathTex`.\n        Every entry in `table` is set in a Latex `align` environment.\n\n        Parameters\n        ----------\n        table\n            A 2d array or list of lists. Content of the table have to be valid input\n            for :class:`~.MathTex`.\n        element_to_mobject\n            The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.MathTex`.\n        kwargs\n            Additional arguments to be passed to :class:`~.Table`.\n        \"\"\"\n        super().__init__(\n            table,\n            element_to_mobject=element_to_mobject,\n            **kwargs,\n        )\n\n\nclass MobjectTable(Table):\n    \"\"\"A specialized :class:`~.Table` mobject for use with :class:`~.Mobject`.\n\n    Examples\n    --------\n\n    .. manim:: MobjectTableExample\n        :save_last_frame:\n\n        class MobjectTableExample(Scene):\n            def construct(self):\n                cross = VGroup(\n                    Line(UP + LEFT, DOWN + RIGHT),\n                    Line(UP + RIGHT, DOWN + LEFT),\n                )\n                a = Circle().set_color(RED).scale(0.5)\n                b = cross.set_color(BLUE).scale(0.5)\n                t0 = MobjectTable(\n                    [[a.copy(),b.copy(),a.copy()],\n                    [b.copy(),a.copy(),a.copy()],\n                    [a.copy(),b.copy(),b.copy()]]\n                )\n                line = Line(\n                    t0.get_corner(DL), t0.get_corner(UR)\n                ).set_color(RED)\n                self.add(t0, line)\n    \"\"\"\n\n    def __init__(\n        self,\n        table: Iterable[Iterable[VMobject]],\n        element_to_mobject: Callable[[VMobject], VMobject] = lambda m: m,\n        **kwargs,\n    ):\n        \"\"\"\n        Special case of :class:`~.Table` with ``element_to_mobject`` set to an identity function.\n        Here, every item in ``table`` must already be of type :class:`~.Mobject`.\n\n        Parameters\n        ----------\n        table\n            A 2D array or list of lists. Content of the table must be of type :class:`~.Mobject`.\n        element_to_mobject\n            The :class:`~.Mobject` class applied to the table entries. Set as ``lambda m : m`` to return itself.\n        kwargs\n            Additional arguments to be passed to :class:`~.Table`.\n        \"\"\"\n        super().__init__(table, element_to_mobject=element_to_mobject, **kwargs)\n\n\nclass IntegerTable(Table):\n    r\"\"\"A specialized :class:`~.Table` mobject for use with :class:`~.Integer`.\n\n    Examples\n    --------\n\n    .. manim:: IntegerTableExample\n        :save_last_frame:\n\n        class IntegerTableExample(Scene):\n            def construct(self):\n                t0 = IntegerTable(\n                    [[0,30,45,60,90],\n                    [90,60,45,30,0]],\n                    col_labels=[\n                        MathTex(r\"\\frac{ \\sqrt{0} }{2}\"),\n                        MathTex(r\"\\frac{ \\sqrt{1} }{2}\"),\n                        MathTex(r\"\\frac{ \\sqrt{2} }{2}\"),\n                        MathTex(r\"\\frac{ \\sqrt{3} }{2}\"),\n                        MathTex(r\"\\frac{ \\sqrt{4} }{2}\")],\n                    row_labels=[MathTex(r\"\\sin\"), MathTex(r\"\\cos\")],\n                    h_buff=1,\n                    element_to_mobject_config={\"unit\": r\"^{\\circ}\"})\n                self.add(t0)\n    \"\"\"\n\n    def __init__(\n        self,\n        table: Iterable[Iterable[float | str]],\n        element_to_mobject: Callable[[float | str], VMobject] = Integer,\n        **kwargs,\n    ):\n        \"\"\"\n        Special case of :class:`~.Table` with `element_to_mobject` set to :class:`~.Integer`.\n        Will round if there are decimal entries in the table.\n\n        Parameters\n        ----------\n        table\n            A 2d array or list of lists. Content of the table has to be valid input\n            for :class:`~.Integer`.\n        element_to_mobject\n            The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.Integer`.\n        kwargs\n            Additional arguments to be passed to :class:`~.Table`.\n        \"\"\"\n        super().__init__(table, element_to_mobject=element_to_mobject, **kwargs)\n\n\nclass DecimalTable(Table):\n    \"\"\"A specialized :class:`~.Table` mobject for use with :class:`~.DecimalNumber` to display decimal entries.\n\n    Examples\n    --------\n\n    .. manim:: DecimalTableExample\n        :save_last_frame:\n\n        class DecimalTableExample(Scene):\n            def construct(self):\n                x_vals = [-2,-1,0,1,2]\n                y_vals = np.exp(x_vals)\n                t0 = DecimalTable(\n                    [x_vals, y_vals],\n                    row_labels=[MathTex(\"x\"), MathTex(\"f(x)=e^{x}\")],\n                    h_buff=1,\n                    element_to_mobject_config={\"num_decimal_places\": 2})\n                self.add(t0)\n    \"\"\"\n\n    def __init__(\n        self,\n        table: Iterable[Iterable[float | str]],\n        element_to_mobject: Callable[[float | str], VMobject] = DecimalNumber,\n        element_to_mobject_config: dict = {\"num_decimal_places\": 1},\n        **kwargs,\n    ):\n        \"\"\"\n        Special case of :class:`~.Table` with ``element_to_mobject`` set to :class:`~.DecimalNumber`.\n        By default, ``num_decimal_places`` is set to 1.\n        Will round/truncate the decimal places based on the provided ``element_to_mobject_config``.\n\n        Parameters\n        ----------\n        table\n            A 2D array, or a list of lists. Content of the table must be valid input\n            for :class:`~.DecimalNumber`.\n        element_to_mobject\n            The :class:`~.Mobject` class applied to the table entries. Set as :class:`~.DecimalNumber`.\n        element_to_mobject_config\n            Element to mobject config, here set as {\"num_decimal_places\": 1}.\n        kwargs\n            Additional arguments to be passed to :class:`~.Table`.\n        \"\"\"\n        super().__init__(\n            table,\n            element_to_mobject=element_to_mobject,\n            element_to_mobject_config=element_to_mobject_config,\n            **kwargs,\n        )\n"
  },
  {
    "path": "manim/mobject/text/__init__.py",
    "content": "\"\"\"Mobjects used to display Text using Pango or LaTeX.\n\nModules\n=======\n\n.. autosummary::\n    :toctree: ../reference\n\n    ~code_mobject\n    ~numbers\n    ~tex_mobject\n    ~text_mobject\n\"\"\"\n"
  },
  {
    "path": "manim/mobject/text/code_mobject.py",
    "content": "\"\"\"Mobject representing highlighted source code listings.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"Code\",\n]\n\nimport re\nfrom pathlib import Path\nfrom typing import Any, Literal\n\nfrom bs4 import BeautifulSoup, Tag\nfrom pygments import highlight\nfrom pygments.formatters.html import HtmlFormatter\nfrom pygments.lexers import get_lexer_by_name, guess_lexer, guess_lexer_for_filename\nfrom pygments.styles import get_all_styles\n\nfrom manim.constants import *\nfrom manim.mobject.geometry.arc import Dot\nfrom manim.mobject.geometry.shape_matchers import SurroundingRectangle\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.types.vectorized_mobject import VGroup, VMobject\nfrom manim.typing import StrPath\nfrom manim.utils.color import WHITE, ManimColor\n\n\nclass Code(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A highlighted source code listing.\n\n    Examples\n    --------\n\n    Normal usage::\n\n        listing = Code(\n            \"helloworldcpp.cpp\",\n            tab_width=4,\n            formatter_style=\"emacs\",\n            background=\"window\",\n            language=\"cpp\",\n            background_config={\"stroke_color\": WHITE},\n            paragraph_config={\"font\": \"Noto Sans Mono\"},\n        )\n\n    We can also render code passed as a string. As the automatic language\n    detection can be a bit flaky, it is recommended to specify the language\n    explicitly:\n\n    .. manim:: CodeFromString\n        :save_last_frame:\n\n        class CodeFromString(Scene):\n            def construct(self):\n                code = '''from manim import Scene, Square\n\n        class FadeInSquare(Scene):\n            def construct(self):\n                s = Square()\n                self.play(FadeIn(s))\n                self.play(s.animate.scale(2))\n                self.wait()'''\n\n                rendered_code = Code(\n                    code_string=code,\n                    language=\"python\",\n                    background=\"window\",\n                    background_config={\"stroke_color\": \"maroon\"},\n                )\n                self.add(rendered_code)\n\n    Parameters\n    ----------\n    code_file\n        The path to the code file to display.\n    code_string\n        Alternatively, the code string to display.\n    language\n        The programming language of the code. If not specified, it will be\n        guessed from the file extension or the code itself.\n    formatter_style\n        The style to use for the code highlighting. Defaults to ``\"vim\"``.\n        A list of all available styles can be obtained by calling\n        :meth:`.Code.get_styles_list`.\n    tab_width\n        The width of a tab character in spaces. Defaults to 4.\n    add_line_numbers\n        Whether to display line numbers. Defaults to ``True``.\n    line_numbers_from\n        The first line number to display. Defaults to 1.\n    background\n        The type of background to use. Can be either ``\"rectangle\"`` (the\n        default) or ``\"window\"``.\n    background_config\n        Keyword arguments passed to the background constructor. Default\n        settings are stored in the class attribute\n        :attr:`.default_background_config` (which can also be modified\n        directly).\n    paragraph_config\n        Keyword arguments passed to the constructor of the\n        :class:`.Paragraph` objects holding the code, and the line\n        numbers. Default settings are stored in the class attribute\n        :attr:`.default_paragraph_config` (which can also be modified\n        directly).\n    \"\"\"\n\n    _styles_list_cache: list[str] | None = None\n    default_background_config: dict[str, Any] = {\n        \"buff\": 0.3,\n        \"fill_color\": ManimColor(\"#222\"),\n        \"stroke_color\": WHITE,\n        \"corner_radius\": 0.2,\n        \"stroke_width\": 1,\n        \"fill_opacity\": 1,\n    }\n    default_paragraph_config: dict[str, Any] = {\n        \"font\": \"Monospace\",\n        \"font_size\": 24,\n        \"line_spacing\": 0.5,\n        \"disable_ligatures\": True,\n    }\n    code: VMobject\n\n    def __init__(\n        self,\n        code_file: StrPath | None = None,\n        code_string: str | None = None,\n        language: str | None = None,\n        formatter_style: str = \"vim\",\n        tab_width: int = 4,\n        add_line_numbers: bool = True,\n        line_numbers_from: int = 1,\n        background: Literal[\"rectangle\", \"window\"] = \"rectangle\",\n        background_config: dict[str, Any] | None = None,\n        paragraph_config: dict[str, Any] | None = None,\n    ):\n        super().__init__()\n\n        if code_file is not None:\n            code_file = Path(code_file)\n            code_string = code_file.read_text(encoding=\"utf-8\")\n            lexer = guess_lexer_for_filename(code_file.name, code_string)\n        elif code_string is not None:\n            if language is not None:\n                lexer = get_lexer_by_name(language)\n            else:\n                lexer = guess_lexer(code_string)\n        else:\n            raise ValueError(\"Either a code file or a code string must be specified.\")\n\n        code_string = code_string.expandtabs(tabsize=tab_width)\n\n        formatter = HtmlFormatter(\n            style=formatter_style,\n            noclasses=True,\n            cssclasses=\"\",\n        )\n        soup = BeautifulSoup(\n            highlight(code_string, lexer, formatter), features=\"html.parser\"\n        )\n        self._code_html = soup.find(\"pre\")\n        assert isinstance(self._code_html, Tag)\n\n        # as we are using Paragraph to render the text, we need to find the character indices\n        # of the segments of changed color in the HTML code\n        color_ranges = []\n        current_line_color_ranges = []\n        current_line_char_index = 0\n        for child in self._code_html.children:\n            if child.name == \"span\":\n                try:\n                    child_style = child[\"style\"]\n                    match_ = re.match(\n                        r\"color: (#[A-Fa-f0-9]{6}|#[A-Fa-f0-9]{3})\", child_style\n                    )\n                    color = None if match_ is None else match_.group(1)\n                except KeyError:\n                    color = None\n                current_line_color_ranges.append(\n                    (\n                        current_line_char_index,\n                        current_line_char_index + len(child.text),\n                        color,\n                    )\n                )\n                current_line_char_index += len(child.text)\n            else:\n                for char in child.text:\n                    if char == \"\\n\":\n                        color_ranges.append(current_line_color_ranges)\n                        current_line_color_ranges = []\n                        current_line_char_index = 0\n                    else:\n                        current_line_char_index += 1\n\n        color_ranges.append(current_line_color_ranges)\n        code_lines = self._code_html.get_text().removesuffix(\"\\n\").split(\"\\n\")\n\n        if paragraph_config is None:\n            paragraph_config = {}\n        base_paragraph_config = self.default_paragraph_config.copy()\n        base_paragraph_config.update(paragraph_config)\n\n        from manim.mobject.text.text_mobject import Paragraph\n\n        self.code_lines = Paragraph(\n            *code_lines,\n            **base_paragraph_config,\n        )\n        for line, color_range in zip(self.code_lines, color_ranges, strict=False):\n            for start, end, color in color_range:\n                line[start:end].set_color(color)\n\n        if add_line_numbers:\n            base_paragraph_config.update({\"alignment\": \"right\"})\n            self.line_numbers = Paragraph(\n                *[\n                    str(i)\n                    for i in range(\n                        line_numbers_from, line_numbers_from + len(self.code_lines)\n                    )\n                ],\n                **base_paragraph_config,\n            )\n            self.line_numbers.next_to(self.code_lines, direction=LEFT).align_to(\n                self.code_lines, UP\n            )\n            self.add(self.line_numbers)\n\n        for line in self.code_lines:\n            line.submobjects = [c for c in line if not isinstance(c, Dot)]\n        self.add(self.code_lines)\n\n        if background_config is None:\n            background_config = {}\n        background_config_base = self.default_background_config.copy()\n        background_config_base.update(background_config)\n\n        if background == \"rectangle\":\n            self.background = SurroundingRectangle(\n                self,\n                **background_config_base,\n            )\n        elif background == \"window\":\n            buttons = VGroup(\n                Dot(radius=0.1, stroke_width=0, color=button_color)\n                for button_color in [\"#ff5f56\", \"#ffbd2e\", \"#27c93f\"]\n            ).arrange(RIGHT, buff=0.1)\n            buttons.next_to(self, UP, buff=0.1).align_to(self, LEFT).shift(LEFT * 0.1)\n            self.background = SurroundingRectangle(\n                VGroup(self, buttons),\n                **background_config_base,\n            )\n            buttons.shift(UP * 0.1 + LEFT * 0.1)\n            self.background.add(buttons)\n        else:\n            raise ValueError(f\"Unknown background type: {background}\")\n\n        self.add_to_back(self.background)\n\n    @classmethod\n    def get_styles_list(cls) -> list[str]:\n        \"\"\"Get the list of all available formatter styles.\"\"\"\n        if cls._styles_list_cache is None:\n            cls._styles_list_cache = list(get_all_styles())\n        return cls._styles_list_cache\n"
  },
  {
    "path": "manim/mobject/text/numbers.py",
    "content": "\"\"\"Mobjects representing numbers.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"DecimalNumber\", \"Integer\", \"Variable\"]\n\nfrom typing import Any, Self\n\nimport numpy as np\n\nfrom manim import config\nfrom manim.constants import *\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.text.tex_mobject import MathTex, SingleStringMathTex, Tex\nfrom manim.mobject.text.text_mobject import Text\nfrom manim.mobject.types.vectorized_mobject import VMobject\nfrom manim.mobject.value_tracker import ValueTracker\nfrom manim.typing import Vector3DLike\n\nstring_to_mob_map: dict[str, SingleStringMathTex] = {}\n\n\nclass DecimalNumber(VMobject, metaclass=ConvertToOpenGL):\n    r\"\"\"An mobject representing a decimal number.\n\n    Parameters\n    ----------\n    number\n        The numeric value to be displayed. It can later be modified using :meth:`.set_value`.\n    num_decimal_places\n        The number of decimal places after the decimal separator. Values are automatically rounded.\n    mob_class\n        The class for rendering digits and units, by default :class:`.MathTex`.\n    include_sign\n        Set to ``True`` to include a sign for positive numbers and zero.\n    group_with_commas\n        When ``True`` thousands groups are separated by commas for readability.\n    digit_buff_per_font_unit\n        Additional spacing between digits. Scales with font size.\n    show_ellipsis\n        When a number has been truncated by rounding, indicate with an ellipsis (``...``).\n    unit\n        A unit string which can be placed to the right of the numerical values.\n    unit_buff_per_font_unit\n        An additional spacing between the numerical values and the unit. A value\n        of ``unit_buff_per_font_unit=0.003`` gives a decent spacing. Scales with font size.\n    include_background_rectangle\n        Adds a background rectangle to increase contrast on busy scenes.\n    edge_to_fix\n        Assuring right- or left-alignment of the full object.\n    font_size\n        Size of the font.\n\n    Examples\n    --------\n\n    .. manim:: MovingSquareWithUpdaters\n\n        class MovingSquareWithUpdaters(Scene):\n            def construct(self):\n                decimal = DecimalNumber(\n                    0,\n                    show_ellipsis=True,\n                    num_decimal_places=3,\n                    include_sign=True,\n                    unit=r\"\\text{M-Units}\",\n                    unit_buff_per_font_unit=0.003\n                )\n                square = Square().to_edge(UP)\n\n                decimal.add_updater(lambda d: d.next_to(square, RIGHT))\n                decimal.add_updater(lambda d: d.set_value(square.get_center()[1]))\n                self.add(square, decimal)\n                self.play(\n                    square.animate.to_edge(DOWN),\n                    rate_func=there_and_back,\n                    run_time=5,\n                )\n                self.wait()\n\n    \"\"\"\n\n    def __init__(\n        self,\n        number: float = 0,\n        num_decimal_places: int = 2,\n        mob_class: type[SingleStringMathTex] = MathTex,\n        include_sign: bool = False,\n        group_with_commas: bool = True,\n        digit_buff_per_font_unit: float = 0.001,\n        show_ellipsis: bool = False,\n        unit: str | None = None,  # Aligned to bottom unless it starts with \"^\"\n        unit_buff_per_font_unit: float = 0,\n        include_background_rectangle: bool = False,\n        edge_to_fix: Vector3DLike = LEFT,\n        font_size: float = DEFAULT_FONT_SIZE,\n        stroke_width: float = 0,\n        fill_opacity: float = 1.0,\n        **kwargs: Any,\n    ):\n        super().__init__(**kwargs, fill_opacity=fill_opacity, stroke_width=stroke_width)\n        self.number = number\n        self.num_decimal_places = num_decimal_places\n        self.include_sign = include_sign\n        self.mob_class = mob_class\n        self.group_with_commas = group_with_commas\n        self.digit_buff_per_font_unit = digit_buff_per_font_unit\n        self.show_ellipsis = show_ellipsis\n        self.unit = unit\n        self.unit_buff_per_font_unit = unit_buff_per_font_unit\n        self.include_background_rectangle = include_background_rectangle\n        self.edge_to_fix = edge_to_fix\n        self._font_size = font_size\n        self.fill_opacity = fill_opacity\n\n        self.initial_config = kwargs.copy()\n        self.initial_config.update(\n            {\n                \"num_decimal_places\": num_decimal_places,\n                \"include_sign\": include_sign,\n                \"group_with_commas\": group_with_commas,\n                \"digit_buff_per_font_unit\": digit_buff_per_font_unit,\n                \"show_ellipsis\": show_ellipsis,\n                \"unit\": unit,\n                \"unit_buff_per_font_unit\": unit_buff_per_font_unit,\n                \"include_background_rectangle\": include_background_rectangle,\n                \"edge_to_fix\": edge_to_fix,\n                \"font_size\": font_size,\n                \"stroke_width\": stroke_width,\n                \"fill_opacity\": fill_opacity,\n            },\n        )\n\n        self._set_submobjects_from_number(number)\n        self.init_colors()\n\n    @property\n    def font_size(self) -> float:\n        \"\"\"The font size of the tex mobject.\"\"\"\n        return_value: float = self.height / self.initial_height * self._font_size\n        return return_value\n\n    @font_size.setter\n    def font_size(self, font_val: float) -> None:\n        if font_val <= 0:\n            raise ValueError(\"font_size must be greater than 0.\")\n        elif self.height > 0:\n            # sometimes manim generates a SingleStringMathex mobject with 0 height.\n            # can't be scaled regardless and will error without the elif.\n\n            # scale to a factor of the initial height so that setting\n            # font_size does not depend on current size.\n            self.scale(font_val / self.font_size)\n\n    def _set_submobjects_from_number(self, number: float) -> None:\n        self.number = number\n        self.submobjects = []\n\n        num_string = self._get_num_string(number)\n        self.add(*(map(self._string_to_mob, num_string)))\n\n        # Add non-numerical bits\n        if self.show_ellipsis:\n            self.add(\n                self._string_to_mob(\"\\\\dots\", SingleStringMathTex, color=self.color),\n            )\n\n        self.arrange(\n            buff=self.digit_buff_per_font_unit * self._font_size,\n            aligned_edge=DOWN,\n        )\n\n        if self.unit is not None:\n            self.unit_sign = self._string_to_mob(self.unit, SingleStringMathTex)\n            self.add(\n                self.unit_sign.next_to(\n                    self,\n                    direction=RIGHT,\n                    buff=(self.unit_buff_per_font_unit + self.digit_buff_per_font_unit)\n                    * self._font_size,\n                    aligned_edge=DOWN,\n                )\n            )\n\n        self.move_to(ORIGIN)\n\n        # Handle alignment of parts that should be aligned\n        # to the bottom\n        for i, c in enumerate(num_string):\n            if c == \"-\" and len(num_string) > i + 1:\n                self[i].align_to(self[i + 1], UP)\n                self[i].shift(self[i + 1].height * DOWN / 2)\n            elif c == \",\":\n                self[i].shift(self[i].height * DOWN / 2)\n        if self.unit and self.unit.startswith(\"^\"):\n            self.unit_sign.align_to(self, UP)\n\n        # track the initial height to enable scaling via font_size\n        self.initial_height: float = self.height\n\n        if self.include_background_rectangle:\n            self.add_background_rectangle()\n\n    def _get_num_string(self, number: float | complex) -> str:\n        if isinstance(number, complex):\n            formatter = self._get_complex_formatter()\n        else:\n            formatter = self._get_formatter()\n        num_string = formatter.format(number)\n\n        rounded_num = np.round(number, self.num_decimal_places)\n        if num_string.startswith(\"-\") and rounded_num == 0:\n            num_string = \"+\" + num_string[1:] if self.include_sign else num_string[1:]\n\n        return num_string\n\n    def _string_to_mob(\n        self,\n        string: str,\n        mob_class: type[SingleStringMathTex] | None = None,\n        **kwargs: Any,\n    ) -> VMobject:\n        if mob_class is None:\n            mob_class = self.mob_class\n\n        if string not in string_to_mob_map:\n            string_to_mob_map[string] = mob_class(string, **kwargs)\n        mob = string_to_mob_map[string].copy()\n        mob.font_size = self._font_size\n        return mob\n\n    def _get_formatter(self, **kwargs: Any) -> str:\n        \"\"\"\n        Configuration is based first off instance attributes,\n        but overwritten by any kew word argument.  Relevant\n        key words:\n        - include_sign\n        - group_with_commas\n        - num_decimal_places\n        - field_name (e.g. 0 or 0.real)\n        \"\"\"\n        config = {\n            attr: getattr(self, attr)\n            for attr in [\n                \"include_sign\",\n                \"group_with_commas\",\n                \"num_decimal_places\",\n            ]\n        }\n        config.update(kwargs)\n        return \"\".join(\n            [\n                \"{\",\n                config.get(\"field_name\", \"\"),\n                \":\",\n                \"+\" if config[\"include_sign\"] else \"\",\n                \",\" if config[\"group_with_commas\"] else \"\",\n                \".\",\n                str(config[\"num_decimal_places\"]),\n                \"f\",\n                \"}\",\n            ],\n        )\n\n    def _get_complex_formatter(self) -> str:\n        return \"\".join(\n            [\n                self._get_formatter(field_name=\"0.real\"),\n                self._get_formatter(field_name=\"0.imag\", include_sign=True),\n                \"i\",\n            ],\n        )\n\n    def set_value(self, number: float) -> Self:\n        \"\"\"Set the value of the :class:`~.DecimalNumber` to a new number.\n\n        Parameters\n        ----------\n        number\n            The value that will overwrite the current number of the :class:`~.DecimalNumber`.\n\n        \"\"\"\n        # creates a new number mob via `set_submobjects_from_number`\n        # then matches the properties (color, font_size, etc...)\n        # of the previous mobject to the new one\n\n        # old_family needed with cairo\n        old_family = self.get_family()\n\n        old_font_size = self.font_size\n        move_to_point = self.get_edge_center(self.edge_to_fix)\n        old_submobjects = self.submobjects\n\n        self._set_submobjects_from_number(number)\n        self.font_size = old_font_size\n        self.move_to(move_to_point, self.edge_to_fix)\n        for sm1, sm2 in zip(self.submobjects, old_submobjects, strict=False):\n            sm1.match_style(sm2)\n\n        if config.renderer == RendererType.CAIRO:\n            for mob in old_family:\n                # Dumb hack...due to how scene handles families\n                # of animated mobjects\n                # for compatibility with updaters to not leave first number in place while updating,\n                # not needed with opengl renderer\n                mob.points[:] = 0\n\n        self.init_colors()\n        return self\n\n    def get_value(self) -> float:\n        return self.number\n\n    def increment_value(self, delta_t: float = 1) -> None:\n        self.set_value(self.get_value() + delta_t)\n\n\nclass Integer(DecimalNumber):\n    \"\"\"A class for displaying Integers.\n\n    Examples\n    --------\n\n    .. manim:: IntegerExample\n        :save_last_frame:\n\n        class IntegerExample(Scene):\n            def construct(self):\n                self.add(Integer(number=2.5).set_color(ORANGE).scale(2.5).set_x(-0.5).set_y(0.8))\n                self.add(Integer(number=3.14159, show_ellipsis=True).set_x(3).set_y(3.3).scale(3.14159))\n                self.add(Integer(number=42).set_x(2.5).set_y(-2.3).set_color_by_gradient(BLUE, TEAL).scale(1.7))\n                self.add(Integer(number=6.28).set_x(-1.5).set_y(-2).set_color(YELLOW).scale(1.4))\n    \"\"\"\n\n    def __init__(\n        self, number: float = 0, num_decimal_places: int = 0, **kwargs: Any\n    ) -> None:\n        super().__init__(number=number, num_decimal_places=num_decimal_places, **kwargs)\n\n    def get_value(self) -> int:\n        return int(np.round(super().get_value()))\n\n\nclass Variable(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A class for displaying text that shows \"label = value\" with\n    the value continuously updated from a :class:`~.ValueTracker`.\n\n    Parameters\n    ----------\n    var\n        The initial value you need to keep track of and display.\n    label\n        The label for your variable. Raw strings are convertex to :class:`~.MathTex` objects.\n    var_type\n        The class used for displaying the number. Defaults to :class:`DecimalNumber`.\n    num_decimal_places\n        The number of decimal places to display in your variable. Defaults to 2.\n        If `var_type` is an :class:`Integer`, this parameter is ignored.\n    kwargs\n            Other arguments to be passed to `~.Mobject`.\n\n    Attributes\n    ----------\n    label : Union[:class:`str`, :class:`~.Tex`, :class:`~.MathTex`, :class:`~.Text`, :class:`~.SingleStringMathTex`]\n        The label for your variable, for example ``x = ...``.\n    tracker : :class:`~.ValueTracker`\n        Useful in updating the value of your variable on-screen.\n    value : Union[:class:`DecimalNumber`, :class:`Integer`]\n        The tex for the value of your variable.\n\n    Examples\n    --------\n    Normal usage::\n\n        # DecimalNumber type\n        var = 0.5\n        on_screen_var = Variable(var, Text(\"var\"), num_decimal_places=3)\n        # Integer type\n        int_var = 0\n        on_screen_int_var = Variable(int_var, Text(\"int_var\"), var_type=Integer)\n        # Using math mode for the label\n        on_screen_int_var = Variable(int_var, \"{a}_{i}\", var_type=Integer)\n\n    .. manim:: VariablesWithValueTracker\n\n        class VariablesWithValueTracker(Scene):\n            def construct(self):\n                var = 0.5\n                on_screen_var = Variable(var, Text(\"var\"), num_decimal_places=3)\n\n                # You can also change the colours for the label and value\n                on_screen_var.label.set_color(RED)\n                on_screen_var.value.set_color(GREEN)\n\n                self.play(Write(on_screen_var))\n                # The above line will just display the variable with\n                # its initial value on the screen. If you also wish to\n                # update it, you can do so by accessing the `tracker` attribute\n                self.wait()\n                var_tracker = on_screen_var.tracker\n                var = 10.5\n                self.play(var_tracker.animate.set_value(var))\n                self.wait()\n\n                int_var = 0\n                on_screen_int_var = Variable(\n                    int_var, Text(\"int_var\"), var_type=Integer\n                ).next_to(on_screen_var, DOWN)\n                on_screen_int_var.label.set_color(RED)\n                on_screen_int_var.value.set_color(GREEN)\n\n                self.play(Write(on_screen_int_var))\n                self.wait()\n                var_tracker = on_screen_int_var.tracker\n                var = 10.5\n                self.play(var_tracker.animate.set_value(var))\n                self.wait()\n\n                # If you wish to have a somewhat more complicated label for your\n                # variable with subscripts, superscripts, etc. the default class\n                # for the label is MathTex\n                subscript_label_var = 10\n                on_screen_subscript_var = Variable(subscript_label_var, \"{a}_{i}\").next_to(\n                    on_screen_int_var, DOWN\n                )\n                self.play(Write(on_screen_subscript_var))\n                self.wait()\n\n    .. manim:: VariableExample\n\n        class VariableExample(Scene):\n            def construct(self):\n                start = 2.0\n\n                x_var = Variable(start, 'x', num_decimal_places=3)\n                sqr_var = Variable(start**2, 'x^2', num_decimal_places=3)\n                Group(x_var, sqr_var).arrange(DOWN)\n\n                sqr_var.add_updater(lambda v: v.tracker.set_value(x_var.tracker.get_value()**2))\n\n                self.add(x_var, sqr_var)\n                self.play(x_var.tracker.animate.set_value(5), run_time=2, rate_func=linear)\n                self.wait(0.1)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        var: float,\n        label: str | Tex | MathTex | Text | SingleStringMathTex,\n        var_type: type[DecimalNumber | Integer] = DecimalNumber,\n        num_decimal_places: int = 2,\n        **kwargs: Any,\n    ):\n        self.label = MathTex(label) if isinstance(label, str) else label\n        equals = MathTex(\"=\").next_to(self.label, RIGHT)\n        self.label.add(equals)\n\n        self.tracker = ValueTracker(var)\n\n        if var_type == DecimalNumber:\n            self.value = DecimalNumber(\n                self.tracker.get_value(),\n                num_decimal_places=num_decimal_places,\n            )\n        elif var_type == Integer:\n            self.value = Integer(self.tracker.get_value())\n\n        self.value.add_updater(lambda v: v.set_value(self.tracker.get_value())).next_to(\n            self.label,\n            RIGHT,\n        )\n\n        super().__init__(**kwargs)\n        self.add(self.label, self.value)\n"
  },
  {
    "path": "manim/mobject/text/tex_mobject.py",
    "content": "r\"\"\"Mobjects representing text rendered using LaTeX.\n\n.. important::\n\n   See the corresponding tutorial :ref:`rendering-with-latex`\n\n.. note::\n\n   Just as you can use :class:`~.Text` (from the module :mod:`~.text_mobject`) to add text to your videos, you can use :class:`~.Tex` and :class:`~.MathTex` to insert LaTeX.\n\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom manim.utils.color import BLACK, ParsableManimColor\n\n__all__ = [\n    \"SingleStringMathTex\",\n    \"MathTex\",\n    \"Tex\",\n    \"BulletedList\",\n    \"Title\",\n]\n\n\nimport operator as op\nimport re\nfrom collections.abc import Iterable\nfrom functools import reduce\nfrom textwrap import dedent\nfrom typing import Any, Self\n\nfrom manim import config, logger\nfrom manim.constants import *\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.svg.svg_mobject import SVGMobject\nfrom manim.mobject.types.vectorized_mobject import VGroup, VMobject\nfrom manim.utils.tex import TexTemplate\nfrom manim.utils.tex_file_writing import tex_to_svg_file\n\nfrom ..opengl.opengl_compatibility import ConvertToOpenGL\n\nMATHTEX_SUBSTRING = \"substring\"\n\n\nclass SingleStringMathTex(SVGMobject):\n    \"\"\"Elementary building block for rendering text with LaTeX.\n\n    Tests\n    -----\n    Check that creating a :class:`~.SingleStringMathTex` object works::\n\n        >>> SingleStringMathTex('Test') # doctest: +SKIP\n        SingleStringMathTex('Test')\n    \"\"\"\n\n    def __init__(\n        self,\n        tex_string: str,\n        stroke_width: float = 0,\n        should_center: bool = True,\n        height: float | None = None,\n        organize_left_to_right: bool = False,\n        tex_environment: str | None = \"align*\",\n        tex_template: TexTemplate | None = None,\n        font_size: float = DEFAULT_FONT_SIZE,\n        color: ParsableManimColor | None = None,\n        **kwargs: Any,\n    ):\n        if color is None:\n            color = VMobject().color\n\n        self._font_size = font_size\n        self.organize_left_to_right = organize_left_to_right\n        self.tex_environment = tex_environment\n        if tex_template is None:\n            tex_template = config[\"tex_template\"]\n        self.tex_template: TexTemplate = tex_template\n\n        self.tex_string = tex_string\n        file_name = tex_to_svg_file(\n            self._get_modified_expression(tex_string),\n            environment=self.tex_environment,\n            tex_template=self.tex_template,\n        )\n        super().__init__(\n            file_name=file_name,\n            should_center=should_center,\n            stroke_width=stroke_width,\n            height=height,\n            color=color,\n            path_string_config={\n                \"should_subdivide_sharp_curves\": True,\n                \"should_remove_null_curves\": True,\n            },\n            **kwargs,\n        )\n        self.init_colors()\n\n        # used for scaling via font_size.setter\n        self.initial_height = self.height\n\n        if height is None:\n            self.font_size = self._font_size\n\n        if self.organize_left_to_right:\n            self._organize_submobjects_left_to_right()\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__name__}({repr(self.tex_string)})\"\n\n    @property\n    def font_size(self) -> float:\n        \"\"\"The font size of the tex mobject.\"\"\"\n        return self.height / self.initial_height / SCALE_FACTOR_PER_FONT_POINT\n\n    @font_size.setter\n    def font_size(self, font_val: float) -> None:\n        if font_val <= 0:\n            raise ValueError(\"font_size must be greater than 0.\")\n        elif self.height > 0:\n            # sometimes manim generates a SingleStringMathex mobject with 0 height.\n            # can't be scaled regardless and will error without the elif.\n\n            # scale to a factor of the initial height so that setting\n            # font_size does not depend on current size.\n            self.scale(font_val / self.font_size)\n\n    def _get_modified_expression(self, tex_string: str) -> str:\n        result = tex_string\n        result = result.strip()\n        result = self._modify_special_strings(result)\n        return result\n\n    def _modify_special_strings(self, tex: str) -> str:\n        tex = tex.strip()\n        should_add_filler = reduce(\n            op.or_,\n            [\n                # Fraction line needs something to be over\n                tex == \"\\\\over\",\n                tex == \"\\\\overline\",\n                # Make sure sqrt has overbar\n                tex == \"\\\\sqrt\",\n                tex == \"\\\\sqrt{\",\n                # Need to add blank subscript or superscript\n                tex.endswith(\"_\"),\n                tex.endswith(\"^\"),\n                tex.endswith(\"dot\"),\n            ],\n        )\n\n        if should_add_filler:\n            filler = \"{\\\\quad}\"\n            tex += filler\n\n        if tex == \"\\\\substack\":\n            tex = \"\\\\quad\"\n\n        if tex == \"\":\n            tex = \"\\\\quad\"\n\n        # To keep files from starting with a line break\n        if tex.startswith(\"\\\\\\\\\"):\n            tex = tex.replace(\"\\\\\\\\\", \"\\\\quad\\\\\\\\\")\n\n        # Handle imbalanced \\left and \\right\n        num_lefts, num_rights = (\n            len([s for s in tex.split(substr)[1:] if s and s[0] in \"(){}[]|.\\\\\"])\n            for substr in (\"\\\\left\", \"\\\\right\")\n        )\n        if num_lefts != num_rights:\n            tex = tex.replace(\"\\\\left\", \"\\\\big\")\n            tex = tex.replace(\"\\\\right\", \"\\\\big\")\n\n        tex = self._remove_stray_braces(tex)\n\n        for context in [\"array\"]:\n            begin_in = (\"\\\\begin{%s}\" % context) in tex  # noqa: UP031\n            end_in = (\"\\\\end{%s}\" % context) in tex  # noqa: UP031\n            if begin_in ^ end_in:\n                # Just turn this into a blank string,\n                # which means caller should leave a\n                # stray \\\\begin{...} with other symbols\n                tex = \"\"\n        return tex\n\n    def _remove_stray_braces(self, tex: str) -> str:\n        r\"\"\"\n        Makes :class:`~.MathTex` resilient to unmatched braces.\n\n        This is important when the braces in the TeX code are spread over\n        multiple arguments as in, e.g., ``MathTex(r\"e^{i\", r\"\\tau} = 1\")``.\n        \"\"\"\n        # \"\\{\" does not count (it's a brace literal), but \"\\\\{\" counts (it's a new line and then brace)\n        num_lefts = tex.count(\"{\") - tex.count(\"\\\\{\") + tex.count(\"\\\\\\\\{\")\n        num_rights = tex.count(\"}\") - tex.count(\"\\\\}\") + tex.count(\"\\\\\\\\}\")\n        while num_rights > num_lefts:\n            tex = \"{\" + tex\n            num_lefts += 1\n        while num_lefts > num_rights:\n            tex = tex + \"}\"\n            num_rights += 1\n        return tex\n\n    def _organize_submobjects_left_to_right(self) -> Self:\n        self.sort(lambda p: p[0])\n        return self\n\n    def get_tex_string(self) -> str:\n        return self.tex_string\n\n    def init_colors(self, propagate_colors: bool = True) -> Self:\n        for submobject in self.submobjects:\n            # needed to preserve original (non-black)\n            # TeX colors of individual submobjects\n            if submobject.color != BLACK:\n                continue\n            submobject.color = self.color\n            if config.renderer == RendererType.OPENGL:\n                submobject.init_colors()\n            elif config.renderer == RendererType.CAIRO:\n                submobject.init_colors(propagate_colors=propagate_colors)\n        return self\n\n\nclass MathTex(SingleStringMathTex):\n    r\"\"\"A string compiled with LaTeX in math mode.\n\n    Examples\n    --------\n    .. manim:: Formula\n        :save_last_frame:\n\n        class Formula(Scene):\n            def construct(self):\n                t = MathTex(r\"\\int_a^b f'(x) dx = f(b)- f(a)\")\n                self.add(t)\n\n    Notes\n    -----\n    Double-brace notation ``{{ ... }}`` can be used to split a single\n    string argument into multiple submobjects without having to pass\n    separate strings::\n\n        MathTex(r\"{{ a^2 }} + {{ b^2 }} = {{ c^2 }}\")\n\n    Each ``{{ ... }}`` group and every piece of text between groups\n    becomes its own submobject, which is useful for\n    :class:`~.TransformMatchingTex` animations.\n\n    For ``{{`` to be recognised as a group opener it must appear either\n    at the very start of the string or be immediately preceded by a\n    whitespace character.  ``{{`` that follows non-whitespace — such as\n    in ``\\frac{{{n}}}{k}`` or ``a^{{2}}`` — is left untouched, so\n    ordinary nested-brace LaTeX is not accidentally split.  To prevent\n    an unintentional split, insert a space between the two braces:\n    ``{{ ... }}`` → ``{ { ... } }``.\n\n    Tests\n    -----\n    Check that creating a :class:`~.MathTex` works::\n\n        >>> MathTex('a^2 + b^2 = c^2') # doctest: +SKIP\n        MathTex('a^2 + b^2 = c^2')\n\n    Check that double brace group splitting works correctly::\n\n        >>> t1 = MathTex('{{ a }} + {{ b }} = {{ c }}') # doctest: +SKIP\n        >>> len(t1.submobjects) # doctest: +SKIP\n        5\n        >>> t2 = MathTex(r\"\\frac{1}{a+b\\sqrt{2}}\") # doctest: +SKIP\n        >>> len(t2.submobjects) # doctest: +SKIP\n        1\n\n    \"\"\"\n\n    def __init__(\n        self,\n        *tex_strings: str,\n        arg_separator: str = \" \",\n        substrings_to_isolate: Iterable[str] | None = None,\n        tex_to_color_map: dict[str, ParsableManimColor] | None = None,\n        tex_environment: str | None = \"align*\",\n        **kwargs: Any,\n    ):\n        self.tex_template = kwargs.pop(\"tex_template\", config[\"tex_template\"])\n        self.arg_separator = arg_separator\n        self.substrings_to_isolate = (\n            [] if substrings_to_isolate is None else list(substrings_to_isolate)\n        )\n        if tex_to_color_map is None:\n            self.tex_to_color_map: dict[str, ParsableManimColor] = {}\n        else:\n            self.tex_to_color_map = tex_to_color_map\n        self.substrings_to_isolate.extend(self.tex_to_color_map.keys())\n        self.tex_environment = tex_environment\n        self.brace_notation_split_occurred = False\n        self.tex_strings = self._prepare_tex_strings(tex_strings)\n        self.matched_strings_and_ids: list[tuple[str, str]] = []\n\n        try:\n            joined_string = self._join_tex_strings_with_unique_deliminters(\n                self.tex_strings, self.substrings_to_isolate\n            )\n            super().__init__(\n                joined_string,\n                tex_environment=self.tex_environment,\n                tex_template=self.tex_template,\n                **kwargs,\n            )\n            # Save the original tex_string\n            self.tex_string = self.arg_separator.join(self.tex_strings)\n            self._break_up_by_substrings()\n        except ValueError as compilation_error:\n            if self.brace_notation_split_occurred:\n                logger.error(\n                    dedent(\n                        \"\"\"\\\n                        A group of double braces, {{ ... }}, was detected in\n                        your string. Manim splits TeX strings at the double\n                        braces, which might have caused the current\n                        compilation error. If you didn't use the double brace\n                        split intentionally, add spaces between the braces to\n                        avoid the automatic splitting: {{ ... }} --> { { ... } }.\n                        \"\"\",\n                    ),\n                )\n            raise compilation_error\n        self.set_color_by_tex_to_color_map(self.tex_to_color_map)\n\n        if self.organize_left_to_right:\n            self._organize_submobjects_left_to_right()\n\n    def _prepare_tex_strings(self, tex_strings: Iterable[str]) -> list[str]:\n        # Deal with the case where tex_strings contains integers instead\n        # of strings.\n        tex_strings_validated = [\n            string if isinstance(string, str) else str(string) for string in tex_strings\n        ]\n        # Locate double curly bracers and split on them.\n        tex_strings_validated_two = []\n        for tex_string in tex_strings_validated:\n            split = self._split_double_braces(tex_string)\n            tex_strings_validated_two.extend(split)\n        if len(tex_strings_validated_two) > len(tex_strings_validated):\n            self.brace_notation_split_occurred = True\n        return [string for string in tex_strings_validated_two if len(string) > 0]\n\n    @staticmethod\n    def _split_double_braces(tex_string: str) -> list[str]:\n        r\"\"\"Split *tex_string* on Manim's ``{{ ... }}`` double-brace notation.\n\n        Rules that avoid false positives on ordinary LaTeX source:\n\n        * ``{{`` is only treated as a group opener when it appears at the very\n          start of the string or is immediately preceded by a whitespace\n          character.  Naturally-occurring ``{{`` in LaTeX is usually preceded\n          by non-whitespace (e.g. ``\\frac{{{n}}}{k}`` or ``a^{{2}}``), so\n          the whitespace guard eliminates the most common false positives\n          without any brace-depth bookkeeping on the outer string.\n\n        * Inside an open group the depth of *real* LaTeX braces is tracked.\n          ``}}`` only closes the Manim group when the inner depth is zero,\n          so ``{{ a^{b^{c}} }}`` is handled correctly.\n\n        * Escape sequences are consumed as two-character units in priority\n          order: ``\\\\`` first (escaped backslash), then ``\\{`` / ``\\}``\n          (escaped braces).  This ensures e.g. ``\\\\}}`` is read as an\n          escaped backslash followed by a real ``}}`` rather than as\n          ``\\`` + ``\\}`` + lone ``}``.\n        \"\"\"\n        segments: list[str] = []\n        current = \"\"\n        i = 0\n        inside_manim = False\n        inner_depth = 0\n\n        while i < len(tex_string):\n            # --- consume escape sequences as atomic units ---\n            if tex_string[i] == \"\\\\\" and i + 1 < len(tex_string):\n                next_ch = tex_string[i + 1]\n                if next_ch == \"\\\\\" or next_ch in \"{}\":\n                    # \\\\ (escaped backslash) checked before \\{ / \\} so that\n                    # the second \\ in \\\\ is never mistaken for an escape prefix.\n                    current += tex_string[i : i + 2]\n                    i += 2\n                    continue\n\n            if not inside_manim:\n                # {{ opens a Manim group only at start-of-string or after whitespace.\n                if tex_string[i : i + 2] == \"{{\" and (\n                    i == 0 or tex_string[i - 1].isspace()\n                ):\n                    segments.append(current)\n                    current = \"\"\n                    inside_manim = True\n                    inner_depth = 0\n                    i += 2\n                else:\n                    current += tex_string[i]\n                    i += 1\n            else:\n                if tex_string[i] == \"{\":\n                    inner_depth += 1\n                    current += tex_string[i]\n                    i += 1\n                elif (\n                    tex_string[i] == \"}\"\n                    and inner_depth == 0\n                    and tex_string[i : i + 2] == \"}}\"\n                ):\n                    # }} at inner depth 0 closes the Manim group.\n                    segments.append(current)\n                    current = \"\"\n                    inside_manim = False\n                    i += 2\n                elif tex_string[i] == \"}\":\n                    inner_depth -= 1\n                    current += tex_string[i]\n                    i += 1\n                else:\n                    current += tex_string[i]\n                    i += 1\n\n        segments.append(current)\n        return segments\n\n    def _join_tex_strings_with_unique_deliminters(\n        self, tex_strings: list[str], substrings_to_isolate: Iterable[str]\n    ) -> str:\n        joined_string = \"\"\n        ssIdx = 0\n        for idx, tex_string in enumerate(tex_strings):\n            string_part = rf\"\\special{{dvisvgm:raw <g id='unique{idx:03d}'>}}\"\n            self.matched_strings_and_ids.append((tex_string, f\"unique{idx:03d}\"))\n\n            # Try to match with all substrings_to_isolate and apply the first match\n            # then match again (on the rest of the string) and continue until no\n            # characters are left in the string\n            unprocessed_string = str(tex_string)\n            processed_string = \"\"\n            while len(unprocessed_string) > 0:\n                first_match = self._locate_first_match(\n                    substrings_to_isolate, unprocessed_string\n                )\n\n                if first_match:\n                    processed, unprocessed_string = self._handle_match(\n                        ssIdx, first_match\n                    )\n                    processed_string = processed_string + processed\n                    ssIdx += 1\n                else:\n                    processed_string = processed_string + unprocessed_string\n                    unprocessed_string = \"\"\n\n            string_part += processed_string\n            if idx < len(tex_strings) - 1:\n                string_part += self.arg_separator\n            string_part += r\"\\special{dvisvgm:raw </g>}\"\n            joined_string = joined_string + string_part\n        return joined_string\n\n    def _locate_first_match(\n        self, substrings_to_isolate: Iterable[str], unprocessed_string: str\n    ) -> re.Match | None:\n        first_match_start = len(unprocessed_string)\n        first_match_length = 0\n        first_match = None\n        for substring in substrings_to_isolate:\n            match = re.match(f\"(.*?)({re.escape(substring)})(.*)\", unprocessed_string)\n            if match and len(match.group(1)) < first_match_start:\n                first_match = match\n                first_match_start = len(match.group(1))\n                first_match_length = len(match.group(2))\n            elif match and len(match.group(1)) == first_match_start:\n                # Break ties by looking at length of matches.\n                if first_match_length < len(match.group(2)):\n                    first_match = match\n                    first_match_start = len(match.group(1))\n                    first_match_length = len(match.group(2))\n        return first_match\n\n    def _handle_match(self, ssIdx: int, first_match: re.Match) -> tuple[str, str]:\n        pre_match = first_match.group(1)\n        matched_string = first_match.group(2)\n        post_match = first_match.group(3)\n        pre_string = (\n            rf\"\\special{{dvisvgm:raw <g id='unique{ssIdx:03d}{MATHTEX_SUBSTRING}'>}}\"\n        )\n        post_string = r\"\\special{dvisvgm:raw </g>}\"\n        self.matched_strings_and_ids.append(\n            (matched_string, f\"unique{ssIdx:03d}{MATHTEX_SUBSTRING}\")\n        )\n        processed_string = pre_match + pre_string + matched_string + post_string\n        unprocessed_string = post_match\n        return processed_string, unprocessed_string\n\n    @property\n    def _substring_matches(self) -> list[tuple[str, str]]:\n        \"\"\"Return only the 'ss' (substring_to_isolate) matches.\"\"\"\n        return [\n            (tex, id_)\n            for tex, id_ in self.matched_strings_and_ids\n            if id_.endswith(MATHTEX_SUBSTRING)\n        ]\n\n    @property\n    def _main_matches(self) -> list[tuple[str, str]]:\n        \"\"\"Return only the main tex_string matches.\"\"\"\n        return [\n            (tex, id_)\n            for tex, id_ in self.matched_strings_and_ids\n            if not id_.endswith(MATHTEX_SUBSTRING)\n        ]\n\n    def _break_up_by_substrings(self) -> Self:\n        \"\"\"\n        Reorganize existing submobjects one layer\n        deeper based on the structure of tex_strings (as a list\n        of tex_strings)\n        \"\"\"\n        new_submobjects: list[VMobject] = []\n        try:\n            for tex_string, tex_string_id in self._main_matches:\n                mtp = MathTexPart()\n                mtp.tex_string = tex_string\n                mtp.add(*self.id_to_vgroup_dict[tex_string_id].submobjects)\n                new_submobjects.append(mtp)\n        except KeyError:\n            logger.error(\n                f\"MathTex: Could not find SVG group for tex part '{tex_string}' (id: {tex_string_id}). Using fallback to root group.\"\n            )\n            new_submobjects.append(self.id_to_vgroup_dict[\"root\"])\n        self.submobjects = new_submobjects\n        return self\n\n    def get_part_by_tex(self, tex: str, **kwargs: Any) -> VGroup | None:\n        for tex_str, match_id in self.matched_strings_and_ids:\n            if tex_str == tex:\n                return self.id_to_vgroup_dict[match_id]\n        return None\n\n    def set_color_by_tex(\n        self, tex: str, color: ParsableManimColor, **kwargs: Any\n    ) -> Self:\n        for tex_str, match_id in self.matched_strings_and_ids:\n            if tex_str == tex:\n                self.id_to_vgroup_dict[match_id].set_color(color)\n        return self\n\n    def set_opacity_by_tex(\n        self,\n        tex: str,\n        opacity: float = 0.5,\n        remaining_opacity: float | None = None,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"\n        Sets the opacity of the tex specified. If 'remaining_opacity' is specified,\n        then the remaining tex will be set to that opacity.\n\n        Parameters\n        ----------\n        tex\n            The tex to set the opacity of.\n        opacity\n            Default 0.5. The opacity to set the tex to\n        remaining_opacity\n            Default None. The opacity to set the remaining tex to.\n            If None, then the remaining tex will not be changed\n        \"\"\"\n        if remaining_opacity is not None:\n            self.set_opacity(opacity=remaining_opacity)\n        for tex_str, match_id in self.matched_strings_and_ids:\n            if tex_str == tex:\n                self.id_to_vgroup_dict[match_id].set_opacity(opacity)\n        return self\n\n    def set_color_by_tex_to_color_map(\n        self, texs_to_color_map: dict[str, ParsableManimColor], **kwargs: Any\n    ) -> Self:\n        for texs, color in list(texs_to_color_map.items()):\n            for match in self.matched_strings_and_ids:\n                if match[0] == texs:\n                    self.id_to_vgroup_dict[match[1]].set_color(color)\n        return self\n\n    def index_of_part(self, part: VMobject) -> int:\n        split_self = self.split()\n        if part not in split_self:\n            raise ValueError(\"Trying to get index of part not in MathTex\")\n        return split_self.index(part)\n\n    def sort_alphabetically(self) -> None:\n        self.submobjects.sort(key=lambda m: m.get_tex_string())\n\n\nclass MathTexPart(VMobject, metaclass=ConvertToOpenGL):\n    tex_string: str\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__name__}({repr(self.tex_string)})\"\n\n\nclass Tex(MathTex):\n    r\"\"\"A string compiled with LaTeX in normal mode.\n\n    The color can be set using\n    the ``color`` argument. Any parts of the ``tex_string`` that are colored by the\n    TeX commands ``\\color`` or ``\\textcolor`` will retain their original color.\n\n    Tests\n    -----\n\n    Check whether writing a LaTeX string works::\n\n        >>> Tex('The horse does not eat cucumber salad.') # doctest: +SKIP\n        Tex('The horse does not eat cucumber salad.')\n\n    \"\"\"\n\n    def __init__(\n        self,\n        *tex_strings: str,\n        arg_separator: str = \"\",\n        tex_environment: str | None = \"center\",\n        **kwargs: Any,\n    ):\n        super().__init__(\n            *tex_strings,\n            arg_separator=arg_separator,\n            tex_environment=tex_environment,\n            **kwargs,\n        )\n\n\nclass BulletedList(Tex):\n    \"\"\"A bulleted list.\n\n    Examples\n    --------\n\n    .. manim:: BulletedListExample\n        :save_last_frame:\n\n        class BulletedListExample(Scene):\n            def construct(self):\n                blist = BulletedList(\"Item 1\", \"Item 2\", \"Item 3\", height=2, width=2)\n                blist.set_color_by_tex(\"Item 1\", RED)\n                blist.set_color_by_tex(\"Item 2\", GREEN)\n                blist.set_color_by_tex(\"Item 3\", BLUE)\n                self.add(blist)\n    \"\"\"\n\n    def __init__(\n        self,\n        *items: str,\n        buff: float = MED_LARGE_BUFF,\n        dot_scale_factor: float = 2,\n        tex_environment: str | None = None,\n        **kwargs: Any,\n    ):\n        self.buff = buff\n        self.dot_scale_factor = dot_scale_factor\n        self.tex_environment = tex_environment\n        line_separated_items = [s + \"\\\\\\\\\" for s in items]\n        super().__init__(\n            *line_separated_items,\n            tex_environment=tex_environment,\n            **kwargs,\n        )\n        for part in self:\n            dot = MathTex(\"\\\\cdot\").scale(self.dot_scale_factor)\n            dot.next_to(part[0], LEFT, SMALL_BUFF)\n            part.add_to_back(dot)\n        self.arrange(DOWN, aligned_edge=LEFT, buff=self.buff)\n\n    def fade_all_but(self, index_or_string: int | str, opacity: float = 0.5) -> None:\n        arg = index_or_string\n        if isinstance(arg, str):\n            part: VGroup | VMobject | None = self.get_part_by_tex(arg)\n            if part is None:\n                raise Exception(\n                    f\"Could not locate part by provided tex string '{arg}'.\"\n                )\n        elif isinstance(arg, int):\n            part = self.submobjects[arg]\n        else:\n            raise TypeError(f\"Expected int or string, got {arg}\")\n        for other_part in self.submobjects:\n            if other_part is part:\n                other_part.set_fill(opacity=1)\n            else:\n                other_part.set_fill(opacity=opacity)\n\n\nclass Title(Tex):\n    \"\"\"A mobject representing an underlined title.\n\n    Examples\n    --------\n    .. manim:: TitleExample\n        :save_last_frame:\n\n        import manim\n\n        class TitleExample(Scene):\n            def construct(self):\n                banner = ManimBanner()\n                title = Title(f\"Manim version {manim.__version__}\")\n                self.add(banner, title)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        *text_parts: str,\n        include_underline: bool = True,\n        match_underline_width_to_text: bool = False,\n        underline_buff: float = MED_SMALL_BUFF,\n        **kwargs: Any,\n    ):\n        self.include_underline = include_underline\n        self.match_underline_width_to_text = match_underline_width_to_text\n        self.underline_buff = underline_buff\n        super().__init__(*text_parts, **kwargs)\n        self.to_edge(UP)\n        if self.include_underline:\n            underline_width = config[\"frame_width\"] - 2\n            underline = Line(LEFT, RIGHT)\n            underline.next_to(self, DOWN, buff=self.underline_buff)\n            if self.match_underline_width_to_text:\n                underline.match_width(self)\n            else:\n                underline.width = underline_width\n            self.add(underline)\n            self.underline = underline\n"
  },
  {
    "path": "manim/mobject/text/text_mobject.py",
    "content": "\"\"\"Mobjects used for displaying (non-LaTeX) text.\n\n.. note::\n   Just as you can use :class:`~.Tex` and :class:`~.MathTex` (from the module :mod:`~.tex_mobject`)\n   to insert LaTeX to your videos, you can use :class:`~.Text` to to add normal text.\n\n.. important::\n\n   See the corresponding tutorial :ref:`using-text-objects`, especially for information about fonts.\n\n\nThe simplest way to add text to your animations is to use the :class:`~.Text` class. It uses the Pango library to render text.\nWith Pango, you are also able to render non-English alphabets like `你好` or  `こんにちは` or `안녕하세요` or `مرحبا بالعالم`.\n\nExamples\n--------\n\n.. manim:: HelloWorld\n    :save_last_frame:\n\n    class HelloWorld(Scene):\n        def construct(self):\n            text = Text('Hello world').scale(3)\n            self.add(text)\n\n.. manim:: TextAlignment\n    :save_last_frame:\n\n    class TextAlignment(Scene):\n        def construct(self):\n            title = Text(\"K-means clustering and Logistic Regression\", color=WHITE)\n            title.scale(0.75)\n            self.add(title.to_edge(UP))\n\n            t1 = Text(\"1. Measuring\").set_color(WHITE)\n\n            t2 = Text(\"2. Clustering\").set_color(WHITE)\n\n            t3 = Text(\"3. Regression\").set_color(WHITE)\n\n            t4 = Text(\"4. Prediction\").set_color(WHITE)\n\n            x = VGroup(t1, t2, t3, t4).arrange(direction=DOWN, aligned_edge=LEFT).scale(0.7).next_to(ORIGIN,DR)\n            x.set_opacity(0.5)\n            x.submobjects[1].set_opacity(1)\n            self.add(x)\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport functools\n\n__all__ = [\"Text\", \"Paragraph\", \"MarkupText\", \"register_font\"]\n\n\nimport copy\nimport hashlib\nimport re\nfrom collections.abc import Iterable, Iterator, Sequence\nfrom contextlib import contextmanager\nfrom itertools import chain\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, Any\n\nimport manimpango\nimport numpy as np\nfrom manimpango import MarkupUtils, PangoUtils, TextSetting\n\nfrom manim import config, logger\nfrom manim.constants import *\nfrom manim.mobject.geometry.arc import Dot\nfrom manim.mobject.svg.svg_mobject import SVGMobject\nfrom manim.mobject.types.vectorized_mobject import VGroup, VMobject\nfrom manim.typing import Point3D\nfrom manim.utils.color import ManimColor, ParsableManimColor, color_gradient\n\nif TYPE_CHECKING:\n    from typing import Self\n\n    from manim.typing import Point3D\n\nTEXT_MOB_SCALE_FACTOR = 0.05\nDEFAULT_LINE_SPACING_SCALE = 0.3\nTEXT2SVG_ADJUSTMENT_FACTOR = 4.8\n\n__all__ = [\"Text\", \"Paragraph\", \"MarkupText\", \"register_font\"]\n\n\ndef remove_invisible_chars(mobject: VMobject) -> VMobject:\n    \"\"\"Function to remove unwanted invisible characters from some mobjects.\n\n    Parameters\n    ----------\n    mobject\n        Any SVGMobject from which we want to remove unwanted invisible characters.\n\n    Returns\n    -------\n    :class:`~.SVGMobject`\n        The SVGMobject without unwanted invisible characters.\n    \"\"\"\n    mobject_without_dots = VGroup()\n    if isinstance(mobject[0], VGroup):\n        for submob in mobject:\n            mobject_without_dots.add(\n                VGroup(k for k in submob if not isinstance(k, Dot))\n            )\n    else:\n        mobject_without_dots.add(*(k for k in mobject if not isinstance(k, Dot)))\n    return mobject_without_dots\n\n\nclass Paragraph(VGroup):\n    r\"\"\"Display a paragraph of text.\n\n    For a given :class:`.Paragraph` ``par``, the attribute ``par.chars`` is a\n    :class:`.VGroup` containing all the lines. In this context, every line is\n    constructed as a :class:`.VGroup` of characters contained in the line.\n\n\n    Parameters\n    ----------\n    line_spacing\n        Represents the spacing between lines. Defaults to -1, which means auto.\n    alignment\n        Defines the alignment of paragraph. Defaults to None. Possible values are \"left\", \"right\" or \"center\".\n\n    Examples\n    --------\n    Normal usage::\n\n        paragraph = Paragraph(\n            \"this is a awesome\",\n            \"paragraph\",\n            \"With \\nNewlines\",\n            \"\\tWith Tabs\",\n            \"  With Spaces\",\n            \"With Alignments\",\n            \"center\",\n            \"left\",\n            \"right\",\n        )\n\n    Remove unwanted invisible characters::\n\n        self.play(Transform(remove_invisible_chars(paragraph.chars[0:2]),\n                            remove_invisible_chars(paragraph.chars[3][0:3]))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        *text: str,\n        line_spacing: float = -1,\n        alignment: str | None = None,\n        **kwargs: Any,\n    ):\n        self.line_spacing = line_spacing\n        self.alignment = alignment\n        self.consider_spaces_as_chars = kwargs.get(\"disable_ligatures\", False)\n        super().__init__()\n\n        lines_str = \"\\n\".join(list(text))\n        self.lines_text = Text(lines_str, line_spacing=line_spacing, **kwargs)\n        lines_str_list = lines_str.split(\"\\n\")\n        self.chars = self._gen_chars(lines_str_list)\n\n        # TODO: If possible get rid of self.lines_chars, as it seems to be a\n        # listified duplicate of self.chars.\n        self.lines_chars = list(self.chars)\n        self.lines_alignments = [self.alignment] * len(self.chars)\n        self.lines_initial_positions = [line.get_center() for line in self.lines_chars]\n        self.add(*self.lines_chars)\n        self.move_to(np.array([0, 0, 0]))\n        if self.alignment:\n            self._set_all_lines_alignments(self.alignment)\n\n    def _gen_chars(self, lines_str_list: list) -> VGroup:\n        \"\"\"Function to convert a list of plain strings to a VGroup of VGroups of chars.\n\n        Parameters\n        ----------\n        lines_str_list\n            List of plain text strings.\n\n        Returns\n        -------\n        :class:`~.VGroup`\n            The generated 2d-VGroup of chars.\n        \"\"\"\n        char_index_counter = 0\n        chars = self.get_group_class()()\n        for line_no in range(len(lines_str_list)):\n            line_str = lines_str_list[line_no]\n            # Count all the characters in line_str\n            # Spaces may or may not count as characters\n            if self.consider_spaces_as_chars:\n                char_count = len(line_str)\n            else:\n                char_count = 0\n                for char in line_str:\n                    if not char.isspace():\n                        char_count += 1\n\n            chars.add(self.get_group_class()())\n            chars[line_no].add(\n                *self.lines_text.chars[\n                    char_index_counter : char_index_counter + char_count\n                ]\n            )\n            char_index_counter += char_count\n            if self.consider_spaces_as_chars:\n                # If spaces count as characters, count the extra \\n character\n                # which separates Paragraph's lines to avoid issues\n                char_index_counter += 1\n        return chars\n\n    def _set_all_lines_alignments(self, alignment: str) -> Paragraph:\n        \"\"\"Function to set all line's alignment to a specific value.\n\n        Parameters\n        ----------\n        alignment\n            Defines the alignment of paragraph. Possible values are \"left\", \"right\", \"center\".\n        \"\"\"\n        for line_no in range(len(self.lines_chars)):\n            self._change_alignment_for_a_line(alignment, line_no)\n        return self\n\n    def _set_line_alignment(self, alignment: str, line_no: int) -> Paragraph:\n        \"\"\"Function to set one line's alignment to a specific value.\n\n        Parameters\n        ----------\n        alignment\n            Defines the alignment of paragraph. Possible values are \"left\", \"right\", \"center\".\n        line_no\n            Defines the line number for which we want to set given alignment.\n        \"\"\"\n        self._change_alignment_for_a_line(alignment, line_no)\n        return self\n\n    def _set_all_lines_to_initial_positions(self) -> Paragraph:\n        \"\"\"Set all lines to their initial positions.\"\"\"\n        self.lines_alignments = [None] * len(self.lines_chars)\n        for line_no in range(len(self.lines_chars)):\n            self[line_no].move_to(\n                self.get_center() + self.lines_initial_positions[line_no],\n            )\n        return self\n\n    def _set_line_to_initial_position(self, line_no: int) -> Paragraph:\n        \"\"\"Function to set one line to initial positions.\n\n        Parameters\n        ----------\n        line_no\n            Defines the line number for which we want to set given alignment.\n        \"\"\"\n        self.lines_alignments[line_no] = None\n        self[line_no].move_to(self.get_center() + self.lines_initial_positions[line_no])\n        return self\n\n    def _change_alignment_for_a_line(self, alignment: str, line_no: int) -> None:\n        \"\"\"Function to change one line's alignment to a specific value.\n\n        Parameters\n        ----------\n        alignment\n            Defines the alignment of paragraph. Possible values are \"left\", \"right\", \"center\".\n        line_no\n            Defines the line number for which we want to set given alignment.\n        \"\"\"\n        self.lines_alignments[line_no] = alignment\n        if self.lines_alignments[line_no] == \"center\":\n            self[line_no].move_to(\n                np.array([self.get_center()[0], self[line_no].get_center()[1], 0]),\n            )\n        elif self.lines_alignments[line_no] == \"right\":\n            self[line_no].move_to(\n                np.array(\n                    [\n                        self.get_right()[0] - self[line_no].width / 2,\n                        self[line_no].get_center()[1],\n                        0,\n                    ],\n                ),\n            )\n        elif self.lines_alignments[line_no] == \"left\":\n            self[line_no].move_to(\n                np.array(\n                    [\n                        self.get_left()[0] + self[line_no].width / 2,\n                        self[line_no].get_center()[1],\n                        0,\n                    ],\n                ),\n            )\n\n\nclass Text(SVGMobject):\n    r\"\"\"Display (non-LaTeX) text rendered using `Pango <https://pango.org/>`_.\n\n    Text objects behave like a :class:`.VGroup`-like iterable of all characters\n    in the given text. In particular, slicing is possible.\n\n    Parameters\n    ----------\n    text\n        The text that needs to be created as a mobject.\n    font\n        The font family to be used to render the text. This is either a system font or\n        one loaded with `register_font()`. Note that font family names may be different\n        across operating systems.\n    warn_missing_font\n        If True (default), Manim will issue a warning if the font does not exist in the\n        (case-sensitive) list of fonts returned from `manimpango.list_fonts()`.\n\n    Returns\n    -------\n    :class:`Text`\n        The mobject-like :class:`.VGroup`.\n\n    Examples\n    ---------\n\n    .. manim:: Example1Text\n        :save_last_frame:\n\n        class Example1Text(Scene):\n            def construct(self):\n                text = Text('Hello world').scale(3)\n                self.add(text)\n\n    .. manim:: TextColorExample\n        :save_last_frame:\n\n        class TextColorExample(Scene):\n            def construct(self):\n                text1 = Text('Hello world', color=BLUE).scale(3)\n                text2 = Text('Hello world', gradient=(BLUE, GREEN)).scale(3).next_to(text1, DOWN)\n                self.add(text1, text2)\n\n    .. manim:: TextItalicAndBoldExample\n        :save_last_frame:\n\n        class TextItalicAndBoldExample(Scene):\n            def construct(self):\n                text1 = Text(\"Hello world\", slant=ITALIC)\n                text2 = Text(\"Hello world\", t2s={'world':ITALIC})\n                text3 = Text(\"Hello world\", weight=BOLD)\n                text4 = Text(\"Hello world\", t2w={'world':BOLD})\n                text5 = Text(\"Hello world\", t2c={'o':YELLOW}, disable_ligatures=True)\n                text6 = Text(\n                    \"Visit us at docs.manim.community\",\n                    t2c={\"docs.manim.community\": YELLOW},\n                    disable_ligatures=True,\n               )\n                text6.scale(1.3).shift(DOWN)\n                self.add(text1, text2, text3, text4, text5 , text6)\n                Group(*self.mobjects).arrange(DOWN, buff=.8).set(height=config.frame_height-LARGE_BUFF)\n\n    .. manim:: TextMoreCustomization\n            :save_last_frame:\n\n            class TextMoreCustomization(Scene):\n                def construct(self):\n                    text1 = Text(\n                        'Google',\n                        t2c={'[:1]': '#3174f0', '[1:2]': '#e53125',\n                             '[2:3]': '#fbb003', '[3:4]': '#3174f0',\n                             '[4:5]': '#269a43', '[5:]': '#e53125'}, font_size=58).scale(3)\n                    self.add(text1)\n\n    As :class:`Text` uses Pango to render text, rendering non-English\n    characters is easily possible:\n\n    .. manim:: MultipleFonts\n        :save_last_frame:\n\n        class MultipleFonts(Scene):\n            def construct(self):\n                morning = Text(\"வணக்கம்\", font=\"sans-serif\")\n                japanese = Text(\n                    \"日本へようこそ\", t2c={\"日本\": BLUE}\n                )  # works same as ``Text``.\n                mess = Text(\"Multi-Language\", weight=BOLD)\n                russ = Text(\"Здравствуйте मस नम म \", font=\"sans-serif\")\n                hin = Text(\"नमस्ते\", font=\"sans-serif\")\n                arb = Text(\n                    \"صباح الخير \\n تشرفت بمقابلتك\", font=\"sans-serif\"\n                )  # don't mix RTL and LTR languages nothing shows up then ;-)\n                chinese = Text(\"臂猿「黛比」帶著孩子\", font=\"sans-serif\")\n                self.add(morning, japanese, mess, russ, hin, arb, chinese)\n                for i,mobj in enumerate(self.mobjects):\n                    mobj.shift(DOWN*(i-3))\n\n\n    .. manim:: PangoRender\n        :quality: low\n\n        class PangoRender(Scene):\n            def construct(self):\n                morning = Text(\"வணக்கம்\", font=\"sans-serif\")\n                self.play(Write(morning))\n                self.wait(2)\n\n    Tests\n    -----\n\n    Check that the creation of :class:`~.Text` works::\n\n        >>> Text('The horse does not eat cucumber salad.')\n        Text('The horse does not eat cucumber salad.')\n\n    \"\"\"\n\n    @staticmethod\n    @functools.cache\n    def font_list() -> list[str]:\n        value: list[str] = manimpango.list_fonts()\n        return value\n\n    def __init__(\n        self,\n        text: str,\n        fill_opacity: float = 1.0,\n        stroke_width: float = 0,\n        color: ParsableManimColor | None = None,\n        font_size: float = DEFAULT_FONT_SIZE,\n        line_spacing: float = -1,\n        font: str = \"\",\n        slant: str = NORMAL,\n        weight: str = NORMAL,\n        t2c: dict[str, str] | None = None,\n        t2f: dict[str, str] | None = None,\n        t2g: dict[str, Iterable[ParsableManimColor]] | None = None,\n        t2s: dict[str, str] | None = None,\n        t2w: dict[str, str] | None = None,\n        gradient: Iterable[ParsableManimColor] | None = None,\n        tab_width: int = 4,\n        warn_missing_font: bool = True,\n        # Mobject\n        height: float | None = None,\n        width: float | None = None,\n        should_center: bool = True,\n        disable_ligatures: bool = False,\n        use_svg_cache: bool = False,\n        **kwargs: Any,\n    ):\n        self.line_spacing = line_spacing\n        if font and warn_missing_font:\n            fonts_list = Text.font_list()\n            # handle special case of sans/sans-serif\n            if font.lower() == \"sans-serif\":\n                font = \"sans\"\n            if font not in fonts_list:\n                # check if the capitalized version is in the supported fonts\n                if font.capitalize() in fonts_list:\n                    font = font.capitalize()\n                elif font.lower() in fonts_list:\n                    font = font.lower()\n                elif font.title() in fonts_list:\n                    font = font.title()\n                else:\n                    logger.warning(f\"Font {font} not in {fonts_list}.\")\n        self.font = font\n        self._font_size = float(font_size)\n        # needs to be a float or else size is inflated when font_size = 24\n        # (unknown cause)\n        self.slant = slant\n        self.weight = weight\n        self.gradient = gradient\n        self.tab_width = tab_width\n        if t2c is None:\n            t2c = {}\n        if t2f is None:\n            t2f = {}\n        if t2g is None:\n            t2g = {}\n        if t2s is None:\n            t2s = {}\n        if t2w is None:\n            t2w = {}\n        # If long form arguments are present, they take precedence\n        t2c = kwargs.pop(\"text2color\", t2c)\n        t2f = kwargs.pop(\"text2font\", t2f)\n        t2g = kwargs.pop(\"text2gradient\", t2g)\n        t2s = kwargs.pop(\"text2slant\", t2s)\n        t2w = kwargs.pop(\"text2weight\", t2w)\n        assert t2c is not None\n        assert t2f is not None\n        assert t2g is not None\n        assert t2s is not None\n        assert t2w is not None\n        self.t2c: dict[str, str] = {k: ManimColor(v).to_hex() for k, v in t2c.items()}\n        self.t2f: dict[str, str] = t2f\n        self.t2g: dict[str, Iterable[ParsableManimColor]] = t2g\n        self.t2s: dict[str, str] = t2s\n        self.t2w: dict[str, str] = t2w\n\n        self.original_text = text\n        self.disable_ligatures = disable_ligatures\n        text_without_tabs = text\n        if text.find(\"\\t\") != -1:\n            text_without_tabs = text.replace(\"\\t\", \" \" * self.tab_width)\n        self.text = text_without_tabs\n        if self.line_spacing == -1:\n            self.line_spacing = (\n                self._font_size + self._font_size * DEFAULT_LINE_SPACING_SCALE\n            )\n        else:\n            self.line_spacing = self._font_size + self._font_size * self.line_spacing\n\n        parsed_color: ManimColor = ManimColor(color) if color else VMobject().color\n        file_name = self._text2svg(parsed_color.to_hex())\n        PangoUtils.remove_last_M(file_name)\n        super().__init__(\n            file_name,\n            fill_opacity=fill_opacity,\n            stroke_width=stroke_width,\n            height=height,\n            width=width,\n            should_center=should_center,\n            use_svg_cache=use_svg_cache,\n            **kwargs,\n        )\n        self.text = text\n        if self.disable_ligatures:\n            self.submobjects = [*self._gen_chars()]\n        self.chars = self.get_group_class()(*self.submobjects)\n        self.text = text_without_tabs.replace(\" \", \"\").replace(\"\\n\", \"\")\n        nppc = self.n_points_per_curve\n        for each in self:\n            if len(each.points) == 0:\n                continue\n            points = each.points\n            curve_start = points[0]\n            assert len(curve_start) == self.dim, curve_start\n            # Some of the glyphs in this text might not be closed,\n            # so we close them by identifying when one curve ends\n            # but it is not where the next curve starts.\n            # It is more efficient to temporarily create a list\n            # of points and add them one at a time, then turn them\n            # into a numpy array at the end, rather than creating\n            # new numpy arrays every time a point or fixing line\n            # is added (which is O(n^2) for numpy arrays).\n            closed_curve_points: list[Point3D] = []\n            # OpenGL has points be part of quadratic Bezier curves;\n            # Cairo uses cubic Bezier curves.\n            if nppc == 3:  # RendererType.OPENGL\n\n                def add_line_to(end: Point3D) -> None:\n                    nonlocal closed_curve_points\n                    start = closed_curve_points[-1]\n                    closed_curve_points += [\n                        start,\n                        (start + end) / 2,\n                        end,\n                    ]\n\n            else:  # RendererType.CAIRO\n\n                def add_line_to(end: Point3D) -> None:\n                    nonlocal closed_curve_points\n                    start = closed_curve_points[-1]\n                    closed_curve_points += [\n                        start,\n                        (start + start + end) / 3,\n                        (start + end + end) / 3,\n                        end,\n                    ]\n\n            for index, point in enumerate(points):\n                closed_curve_points.append(point)\n                if (\n                    index != len(points) - 1\n                    and (index + 1) % nppc == 0\n                    and any(point != points[index + 1])\n                ):\n                    # Add straight line from last point on this curve to the\n                    # start point on the next curve. We represent the line\n                    # as a cubic bezier curve where the two control points\n                    # are half-way between the start and stop point.\n                    add_line_to(curve_start)\n                    curve_start = points[index + 1]\n            # Make sure last curve is closed\n            add_line_to(curve_start)\n            each.points = np.array(closed_curve_points, ndmin=2)\n        # anti-aliasing\n        if height is None and width is None:\n            self.scale(TEXT_MOB_SCALE_FACTOR)\n        self.initial_height = self.height\n\n    def __repr__(self) -> str:\n        return f\"Text({repr(self.original_text)})\"\n\n    @property\n    def font_size(self) -> float:\n        return (\n            self.height\n            / self.initial_height\n            / TEXT_MOB_SCALE_FACTOR\n            * 2.4\n            * self._font_size\n            / DEFAULT_FONT_SIZE\n        )\n\n    @font_size.setter\n    def font_size(self, font_val: float) -> None:\n        # TODO: use pango's font size scaling.\n        if font_val <= 0:\n            raise ValueError(\"font_size must be greater than 0.\")\n        else:\n            self.scale(font_val / self.font_size)\n\n    def _gen_chars(self) -> VGroup:\n        chars = self.get_group_class()()\n        submobjects_char_index = 0\n        for char_index in range(len(self.text)):\n            if self.text[char_index].isspace():\n                space = Dot(radius=0, fill_opacity=0, stroke_opacity=0)\n                if char_index == 0:\n                    space.move_to(self.submobjects[submobjects_char_index].get_center())\n                else:\n                    space.move_to(\n                        self.submobjects[submobjects_char_index - 1].get_center(),\n                    )\n                chars.add(space)\n            else:\n                chars.add(self.submobjects[submobjects_char_index])\n                submobjects_char_index += 1\n        return chars\n\n    def _find_indexes(self, word: str, text: str) -> list[tuple[int, int]]:\n        \"\"\"Finds the indexes of ``text`` in ``word``.\"\"\"\n        temp = re.match(r\"\\[([0-9\\-]{0,}):([0-9\\-]{0,})\\]\", word)\n        if temp:\n            start = int(temp.group(1)) if temp.group(1) != \"\" else 0\n            end = int(temp.group(2)) if temp.group(2) != \"\" else len(text)\n            start = len(text) + start if start < 0 else start\n            end = len(text) + end if end < 0 else end\n            return [\n                (start, end),\n            ]\n        indexes = []\n        index = text.find(word)\n        while index != -1:\n            indexes.append((index, index + len(word)))\n            index = text.find(word, index + len(word))\n        return indexes\n\n    def _text2hash(self, color: ParsableManimColor) -> str:\n        \"\"\"Generates ``sha256`` hash for file name.\"\"\"\n        settings = (\n            \"PANGO\" + self.font + self.slant + self.weight + str(color)\n        )  # to differentiate Text and CairoText\n        settings += str(self.t2f) + str(self.t2s) + str(self.t2w) + str(self.t2c)\n        settings += str(self.line_spacing) + str(self._font_size)\n        settings += str(self.disable_ligatures)\n        settings += str(self.gradient)\n        id_str = self.text + settings\n        hasher = hashlib.sha256()\n        hasher.update(id_str.encode())\n        return hasher.hexdigest()[:16]\n\n    def _merge_settings(\n        self,\n        left_setting: TextSetting,\n        right_setting: TextSetting,\n        default_args: dict[str, Iterable[str]],\n    ) -> TextSetting:\n        contained = right_setting.end < left_setting.end\n        new_setting = copy.copy(left_setting) if contained else copy.copy(right_setting)\n\n        new_setting.start = right_setting.end if contained else left_setting.end\n        left_setting.end = right_setting.start\n        if not contained:\n            right_setting.end = new_setting.start\n\n        for arg in default_args:\n            left = getattr(left_setting, arg)\n            right = getattr(right_setting, arg)\n            default = default_args[arg]\n            if left != default and getattr(right_setting, arg) != default:\n                raise ValueError(\n                    f\"Ambiguous style for text '{self.text[right_setting.start : right_setting.end]}':\"\n                    + f\"'{arg}' cannot be both '{left}' and '{right}'.\"\n                )\n            setattr(right_setting, arg, left if left != default else right)\n        return new_setting\n\n    def _get_settings_from_t2xs(\n        self,\n        t2xs: Sequence[tuple[dict[str, str], str]],\n        default_args: dict[str, Iterable[str]],\n    ) -> list[TextSetting]:\n        settings = []\n        t2xwords = set(chain(*([*t2x.keys()] for t2x, _ in t2xs)))\n        for word in t2xwords:\n            setting_args = {\n                arg: str(t2x[word]) if word in t2x else default_args[arg]\n                # NOTE: when t2x[word] is a ManimColor, str will yield the\n                # hex representation\n                for t2x, arg in t2xs\n            }\n\n            for start, end in self._find_indexes(word, self.text):\n                settings.append(TextSetting(start, end, **setting_args))\n        return settings\n\n    def _get_settings_from_gradient(\n        self, default_args: dict[str, Any]\n    ) -> list[TextSetting]:\n        settings = []\n        args = copy.copy(default_args)\n        if self.gradient:\n            colors: list[ManimColor] = color_gradient(self.gradient, len(self.text))\n            for i in range(len(self.text)):\n                args[\"color\"] = colors[i].to_hex()\n                settings.append(TextSetting(i, i + 1, **args))\n\n        for word, gradient in self.t2g.items():\n            colors = color_gradient(gradient, len(word))\n            for start, end in self._find_indexes(word, self.text):\n                for i in range(start, end):\n                    args[\"color\"] = colors[i - start].to_hex()\n                    settings.append(TextSetting(i, i + 1, **args))\n        return settings\n\n    def _text2settings(self, color: ParsableManimColor) -> list[TextSetting]:\n        \"\"\"Converts the texts and styles to a setting for parsing.\"\"\"\n        t2xs: list[tuple[dict[str, str], str]] = [\n            (self.t2f, \"font\"),\n            (self.t2s, \"slant\"),\n            (self.t2w, \"weight\"),\n            (self.t2c, \"color\"),\n        ]\n        # setting_args requires values to be strings\n\n        default_args: dict[str, Any] = {\n            arg: getattr(self, arg) if arg != \"color\" else color for _, arg in t2xs\n        }\n\n        settings = self._get_settings_from_t2xs(t2xs, default_args)\n        settings.extend(self._get_settings_from_gradient(default_args))\n\n        # Handle overlaps\n\n        settings.sort(key=lambda setting: setting.start)\n        for index, setting in enumerate(settings):\n            if index + 1 == len(settings):\n                break\n\n            next_setting = settings[index + 1]\n            if setting.end > next_setting.start:\n                new_setting = self._merge_settings(setting, next_setting, default_args)\n                new_index = index + 1\n                while (\n                    new_index < len(settings)\n                    and settings[new_index].start < new_setting.start\n                ):\n                    new_index += 1\n                settings.insert(new_index, new_setting)\n\n        # Set all text settings (default font, slant, weight)\n        temp_settings = settings.copy()\n        start = 0\n        for setting in settings:\n            if setting.start != start:\n                temp_settings.append(TextSetting(start, setting.start, **default_args))\n            start = setting.end\n        if start != len(self.text):\n            temp_settings.append(TextSetting(start, len(self.text), **default_args))\n        settings = sorted(temp_settings, key=lambda setting: setting.start)\n\n        line_num = 0\n        if re.search(r\"\\n\", self.text):\n            for for_start, for_end in self._find_indexes(\"\\n\", self.text):\n                for setting in settings:\n                    if setting.line_num == -1:\n                        setting.line_num = line_num\n                    if for_start < setting.end:\n                        line_num += 1\n                        new_setting = copy.copy(setting)\n                        setting.end = for_end\n                        new_setting.start = for_end\n                        new_setting.line_num = line_num\n                        settings.append(new_setting)\n                        settings.sort(key=lambda setting: setting.start)\n                        break\n        for setting in settings:\n            if setting.line_num == -1:\n                setting.line_num = line_num\n\n        return settings\n\n    def _text2svg(self, color: ParsableManimColor) -> str:\n        \"\"\"Convert the text to SVG using Pango.\"\"\"\n        size = self._font_size\n        line_spacing = self.line_spacing\n        size /= TEXT2SVG_ADJUSTMENT_FACTOR\n        line_spacing /= TEXT2SVG_ADJUSTMENT_FACTOR\n\n        dir_name = config.get_dir(\"text_dir\")\n        dir_name.mkdir(parents=True, exist_ok=True)\n        hash_name = self._text2hash(color)\n        file_name = dir_name / (hash_name + \".svg\")\n\n        if file_name.exists():\n            svg_file = str(file_name.resolve())\n        else:\n            settings = self._text2settings(color)\n            width = config[\"pixel_width\"]\n            height = config[\"pixel_height\"]\n\n            svg_file = manimpango.text2svg(\n                settings,\n                size,\n                line_spacing,\n                self.disable_ligatures,\n                str(file_name.resolve()),\n                START_X,\n                START_Y,\n                width,\n                height,\n                self.text,\n            )\n\n        return svg_file\n\n    def init_colors(self, propagate_colors: bool = True) -> Self:\n        if config.renderer == RendererType.OPENGL:\n            super().init_colors()\n        elif config.renderer == RendererType.CAIRO:\n            super().init_colors(propagate_colors=propagate_colors)\n        return self\n\n\nclass MarkupText(SVGMobject):\n    r\"\"\"Display (non-LaTeX) text rendered using `Pango <https://pango.org/>`_.\n\n    Text objects behave like a :class:`.VGroup`-like iterable of all characters\n    in the given text. In particular, slicing is possible.\n\n    **What is PangoMarkup?**\n\n    PangoMarkup is a small markup language like html and it helps you avoid using\n    \"range of characters\" while coloring or styling a piece a Text. You can use\n    this language with :class:`~.MarkupText`.\n\n    A simple example of a marked-up string might be::\n\n        <span foreground=\"blue\" size=\"x-large\">Blue text</span> is <i>cool</i>!\"\n\n    and it can be used with :class:`~.MarkupText` as\n\n    .. manim:: MarkupExample\n        :save_last_frame:\n\n        class MarkupExample(Scene):\n            def construct(self):\n                text = MarkupText('<span foreground=\"blue\" size=\"x-large\">Blue text</span> is <i>cool</i>!\"')\n                self.add(text)\n\n    A more elaborate example would be:\n\n    .. manim:: MarkupElaborateExample\n        :save_last_frame:\n\n        class MarkupElaborateExample(Scene):\n            def construct(self):\n                text = MarkupText(\n                    '<span foreground=\"purple\">ا</span><span foreground=\"red\">َ</span>'\n                    'ل<span foreground=\"blue\">ْ</span>ع<span foreground=\"red\">َ</span>ر'\n                    '<span foreground=\"red\">َ</span>ب<span foreground=\"red\">ِ</span>ي'\n                    '<span foreground=\"green\">ّ</span><span foreground=\"red\">َ</span>ة'\n                    '<span foreground=\"blue\">ُ</span>'\n                )\n                self.add(text)\n\n    PangoMarkup can also contain XML features such as numeric character\n    entities such as ``&#169;`` for © can be used too.\n\n    The most general markup tag is ``<span>``, then there are some\n    convenience tags.\n\n    Here is a list of supported tags:\n\n    - ``<b>bold</b>``, ``<i>italic</i>`` and ``<b><i>bold+italic</i></b>``\n    - ``<u>underline</u>`` and ``<s>strike through</s>``\n    - ``<tt>typewriter font</tt>``\n    - ``<big>bigger font</big>`` and ``<small>smaller font</small>``\n    - ``<sup>superscript</sup>`` and ``<sub>subscript</sub>``\n    - ``<span underline=\"double\" underline_color=\"green\">double underline</span>``\n    - ``<span underline=\"error\">error underline</span>``\n    - ``<span overline=\"single\" overline_color=\"green\">overline</span>``\n    - ``<span strikethrough=\"true\" strikethrough_color=\"red\">strikethrough</span>``\n    - ``<span font_family=\"sans\">temporary change of font</span>``\n    - ``<span foreground=\"red\">temporary change of color</span>``\n    - ``<span fgcolor=\"red\">temporary change of color</span>``\n    - ``<gradient from=\"YELLOW\" to=\"RED\">temporary gradient</gradient>``\n\n    For ``<span>`` markup, colors can be specified either as\n    hex triples like ``#aabbcc`` or as named CSS colors like\n    ``AliceBlue``.\n    The ``<gradient>`` tag is handled by Manim rather than\n    Pango, and supports hex triplets or Manim constants like\n    ``RED`` or ``RED_A``.\n    If you want to use Manim constants like ``RED_A`` together\n    with ``<span>``, you will need to use Python's f-String\n    syntax as follows::\n\n        MarkupText(f'<span foreground=\"{RED_A}\">here you go</span>')\n\n    If your text contains ligatures, the :class:`MarkupText` class may\n    incorrectly determine the first and last letter when creating the\n    gradient. This is due to the fact that ``fl`` are two separate characters,\n    but might be set as one single glyph - a ligature. If your language\n    does not depend on ligatures, consider setting ``disable_ligatures``\n    to ``True``. If you must use ligatures, the ``gradient`` tag supports an optional\n    attribute ``offset`` which can be used to compensate for that error.\n\n    For example:\n\n    - ``<gradient from=\"RED\" to=\"YELLOW\" offset=\"1\">example</gradient>`` to *start* the gradient one letter earlier\n    - ``<gradient from=\"RED\" to=\"YELLOW\" offset=\",1\">example</gradient>`` to *end* the gradient one letter earlier\n    - ``<gradient from=\"RED\" to=\"YELLOW\" offset=\"2,1\">example</gradient>`` to *start* the gradient two letters earlier and *end* it one letter earlier\n\n    Specifying a second offset may be necessary if the text to be colored does\n    itself contain ligatures. The same can happen when using HTML entities for\n    special chars.\n\n    When using ``underline``, ``overline`` or ``strikethrough`` together with\n    ``<gradient>`` tags, you will also need to use the offset, because\n    underlines are additional paths in the final :class:`SVGMobject`.\n    Check out the following example.\n\n    Escaping of special characters: ``>`` **should** be written as ``&gt;``\n    whereas ``<`` and ``&`` *must* be written as ``&lt;`` and\n    ``&amp;``.\n\n    You can find more information about Pango markup formatting at the\n    corresponding documentation page:\n    `Pango Markup <https://docs.gtk.org/Pango/pango_markup.html>`_.\n    Please be aware that not all features are supported by this class and that\n    the ``<gradient>`` tag mentioned above is not supported by Pango.\n\n    Parameters\n    ----------\n\n    text\n        The text that needs to be created as mobject.\n    fill_opacity\n        The fill opacity, with 1 meaning opaque and 0 meaning transparent.\n    stroke_width\n        Stroke width.\n    font_size\n        Font size.\n    line_spacing\n        Line spacing.\n    font\n        Global font setting for the entire text. Local overrides are possible.\n    slant\n        Global slant setting, e.g. `NORMAL` or `ITALIC`. Local overrides are possible.\n    weight\n        Global weight setting, e.g. `NORMAL` or `BOLD`. Local overrides are possible.\n    gradient\n        Global gradient setting. Local overrides are possible.\n    warn_missing_font\n        If True (default), Manim will issue a warning if the font does not exist in the\n        (case-sensitive) list of fonts returned from `manimpango.list_fonts()`.\n\n    Returns\n    -------\n    :class:`MarkupText`\n        The text displayed in form of a :class:`.VGroup`-like mobject.\n\n    Examples\n    ---------\n\n    .. manim:: BasicMarkupExample\n        :save_last_frame:\n\n        class BasicMarkupExample(Scene):\n            def construct(self):\n                text1 = MarkupText(\"<b>foo</b> <i>bar</i> <b><i>foobar</i></b>\")\n                text2 = MarkupText(\"<s>foo</s> <u>bar</u> <big>big</big> <small>small</small>\")\n                text3 = MarkupText(\"H<sub>2</sub>O and H<sub>3</sub>O<sup>+</sup>\")\n                text4 = MarkupText(\"type <tt>help</tt> for help\")\n                text5 = MarkupText(\n                    '<span underline=\"double\">foo</span> <span underline=\"error\">bar</span>'\n                )\n                group = VGroup(text1, text2, text3, text4, text5).arrange(DOWN)\n                self.add(group)\n\n    .. manim:: ColorExample\n        :save_last_frame:\n\n        class ColorExample(Scene):\n            def construct(self):\n                text1 = MarkupText(\n                    f'all in red <span fgcolor=\"{YELLOW}\">except this</span>', color=RED\n                )\n                text2 = MarkupText(\"nice gradient\", gradient=(BLUE, GREEN))\n                text3 = MarkupText(\n                    'nice <gradient from=\"RED\" to=\"YELLOW\">intermediate</gradient> gradient',\n                    gradient=(BLUE, GREEN),\n                )\n                text4 = MarkupText(\n                    'fl ligature <gradient from=\"RED\" to=\"YELLOW\">causing trouble</gradient> here'\n                )\n                text5 = MarkupText(\n                    'fl ligature <gradient from=\"RED\" to=\"YELLOW\" offset=\"1\">defeated</gradient> with offset'\n                )\n                text6 = MarkupText(\n                    'fl ligature <gradient from=\"RED\" to=\"YELLOW\" offset=\"1\">floating</gradient> inside'\n                )\n                text7 = MarkupText(\n                    'fl ligature <gradient from=\"RED\" to=\"YELLOW\" offset=\"1,1\">floating</gradient> inside'\n                )\n                group = VGroup(text1, text2, text3, text4, text5, text6, text7).arrange(DOWN)\n                self.add(group)\n\n    .. manim:: UnderlineExample\n        :save_last_frame:\n\n        class UnderlineExample(Scene):\n            def construct(self):\n                text1 = MarkupText(\n                    '<span underline=\"double\" underline_color=\"green\">bla</span>'\n                )\n                text2 = MarkupText(\n                    '<span underline=\"single\" underline_color=\"green\">xxx</span><gradient from=\"#ffff00\" to=\"RED\">aabb</gradient>y'\n                )\n                text3 = MarkupText(\n                    '<span underline=\"single\" underline_color=\"green\">xxx</span><gradient from=\"#ffff00\" to=\"RED\" offset=\"-1\">aabb</gradient>y'\n                )\n                text4 = MarkupText(\n                    '<span underline=\"double\" underline_color=\"green\">xxx</span><gradient from=\"#ffff00\" to=\"RED\">aabb</gradient>y'\n                )\n                text5 = MarkupText(\n                    '<span underline=\"double\" underline_color=\"green\">xxx</span><gradient from=\"#ffff00\" to=\"RED\" offset=\"-2\">aabb</gradient>y'\n                )\n                group = VGroup(text1, text2, text3, text4, text5).arrange(DOWN)\n                self.add(group)\n\n    .. manim:: FontExample\n        :save_last_frame:\n\n        class FontExample(Scene):\n            def construct(self):\n                text1 = MarkupText(\n                    'all in sans <span font_family=\"serif\">except this</span>', font=\"sans\"\n                )\n                text2 = MarkupText(\n                    '<span font_family=\"serif\">mixing</span> <span font_family=\"sans\">fonts</span> <span font_family=\"monospace\">is ugly</span>'\n                )\n                text3 = MarkupText(\"special char > or &gt;\")\n                text4 = MarkupText(\"special char &lt; and &amp;\")\n                group = VGroup(text1, text2, text3, text4).arrange(DOWN)\n                self.add(group)\n\n    .. manim:: NewlineExample\n        :save_last_frame:\n\n        class NewlineExample(Scene):\n            def construct(self):\n                text = MarkupText('foooo<span foreground=\"red\">oo\\nbaa</span>aar')\n                self.add(text)\n\n    .. manim:: NoLigaturesExample\n        :save_last_frame:\n\n        class NoLigaturesExample(Scene):\n            def construct(self):\n                text1 = MarkupText('fl<gradient from=\"RED\" to=\"GREEN\">oat</gradient>ing')\n                text2 = MarkupText('fl<gradient from=\"RED\" to=\"GREEN\">oat</gradient>ing', disable_ligatures=True)\n                group = VGroup(text1, text2).arrange(DOWN)\n                self.add(group)\n\n\n    As :class:`MarkupText` uses Pango to render text, rendering non-English\n    characters is easily possible:\n\n    .. manim:: MultiLanguage\n        :save_last_frame:\n\n        class MultiLanguage(Scene):\n            def construct(self):\n                morning = MarkupText(\"வணக்கம்\", font=\"sans-serif\")\n                japanese = MarkupText(\n                    '<span fgcolor=\"blue\">日本</span>へようこそ'\n                )  # works as in ``Text``.\n                mess = MarkupText(\"Multi-Language\", weight=BOLD)\n                russ = MarkupText(\"Здравствуйте मस नम म \", font=\"sans-serif\")\n                hin = MarkupText(\"नमस्ते\", font=\"sans-serif\")\n                chinese = MarkupText(\"臂猿「黛比」帶著孩子\", font=\"sans-serif\")\n                group = VGroup(morning, japanese, mess, russ, hin, chinese).arrange(DOWN)\n                self.add(group)\n\n    You can justify the text by passing :attr:`justify` parameter.\n\n    .. manim:: JustifyText\n\n        class JustifyText(Scene):\n            def construct(self):\n                ipsum_text = (\n                    \"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\"\n                    \"Praesent feugiat metus sit amet iaculis pulvinar. Nulla posuere \"\n                    \"quam a ex aliquam, eleifend consectetur tellus viverra. Aliquam \"\n                    \"fermentum interdum justo, nec rutrum elit pretium ac. Nam quis \"\n                    \"leo pulvinar, dignissim est at, venenatis nisi.\"\n                )\n                justified_text = MarkupText(ipsum_text, justify=True).scale(0.4)\n                not_justified_text = MarkupText(ipsum_text, justify=False).scale(0.4)\n                just_title = Title(\"Justified\")\n                njust_title = Title(\"Not Justified\")\n                self.add(njust_title, not_justified_text)\n                self.play(\n                    FadeOut(not_justified_text),\n                    FadeIn(justified_text),\n                    FadeOut(njust_title),\n                    FadeIn(just_title),\n                )\n                self.wait(1)\n\n    Tests\n    -----\n\n    Check that the creation of :class:`~.MarkupText` works::\n\n        >>> MarkupText('The horse does not eat cucumber salad.')\n        MarkupText('The horse does not eat cucumber salad.')\n\n    \"\"\"\n\n    @staticmethod\n    @functools.cache\n    def font_list() -> list[str]:\n        value: list[str] = manimpango.list_fonts()\n        return value\n\n    def __init__(\n        self,\n        text: str,\n        fill_opacity: float = 1,\n        stroke_width: float = 0,\n        color: ParsableManimColor | None = None,\n        font_size: float = DEFAULT_FONT_SIZE,\n        line_spacing: float = -1,\n        font: str = \"\",\n        slant: str = NORMAL,\n        weight: str = NORMAL,\n        justify: bool = False,\n        gradient: Iterable[ParsableManimColor] | None = None,\n        tab_width: int = 4,\n        height: int | None = None,\n        width: int | None = None,\n        should_center: bool = True,\n        disable_ligatures: bool = False,\n        warn_missing_font: bool = True,\n        **kwargs: Any,\n    ):\n        self.text = text\n        self.line_spacing: float = line_spacing\n        if font and warn_missing_font:\n            fonts_list = Text.font_list()\n            # handle special case of sans/sans-serif\n            if font.lower() == \"sans-serif\":\n                font = \"sans\"\n            if font not in fonts_list:\n                # check if the capitalized version is in the supported fonts\n                if font.capitalize() in fonts_list:\n                    font = font.capitalize()\n                elif font.lower() in fonts_list:\n                    font = font.lower()\n                elif font.title() in fonts_list:\n                    font = font.title()\n                else:\n                    logger.warning(f\"Font {font} not in {fonts_list}.\")\n        self.font = font\n        self._font_size = float(font_size)\n        self.slant = slant\n        self.weight = weight\n        self.gradient = gradient\n        self.tab_width = tab_width\n        self.justify = justify\n\n        self.original_text = text\n        self.disable_ligatures = disable_ligatures\n        text_without_tabs = text\n        if \"\\t\" in text:\n            text_without_tabs = text.replace(\"\\t\", \" \" * self.tab_width)\n\n        colormap = self._extract_color_tags()\n        if len(colormap) > 0:\n            logger.warning(\n                'Using <color> tags in MarkupText is deprecated. Please use <span foreground=\"...\"> instead.',\n            )\n        gradientmap = self._extract_gradient_tags()\n        validate_error = MarkupUtils.validate(self.text)\n        if validate_error:\n            raise ValueError(validate_error)\n\n        if self.line_spacing == -1:\n            self.line_spacing = (\n                self._font_size + self._font_size * DEFAULT_LINE_SPACING_SCALE\n            )\n        else:\n            self.line_spacing = self._font_size + self._font_size * self.line_spacing\n\n        parsed_color: ManimColor = ManimColor(color) if color else VMobject().color\n        file_name = self._text2svg(parsed_color)\n\n        PangoUtils.remove_last_M(file_name)\n        super().__init__(\n            file_name,\n            fill_opacity=fill_opacity,\n            stroke_width=stroke_width,\n            height=height,\n            width=width,\n            should_center=should_center,\n            **kwargs,\n        )\n\n        self.chars = self.get_group_class()(*self.submobjects)\n        self.text = text_without_tabs.replace(\" \", \"\").replace(\"\\n\", \"\")\n\n        nppc = self.n_points_per_curve\n        for each in self:\n            if len(each.points) == 0:\n                continue\n            points = each.points\n            curve_start = points[0]\n            assert len(curve_start) == self.dim, curve_start\n            # Some of the glyphs in this text might not be closed,\n            # so we close them by identifying when one curve ends\n            # but it is not where the next curve starts.\n            # It is more efficient to temporarily create a list\n            # of points and add them one at a time, then turn them\n            # into a numpy array at the end, rather than creating\n            # new numpy arrays every time a point or fixing line\n            # is added (which is O(n^2) for numpy arrays).\n            closed_curve_points: list[Point3D] = []\n            # OpenGL has points be part of quadratic Bezier curves;\n            # Cairo uses cubic Bezier curves.\n            if nppc == 3:  # RendererType.OPENGL\n\n                def add_line_to(end: Point3D) -> None:\n                    nonlocal closed_curve_points\n                    start = closed_curve_points[-1]\n                    closed_curve_points += [\n                        start,\n                        (start + end) / 2,\n                        end,\n                    ]\n\n            else:  # RendererType.CAIRO\n\n                def add_line_to(end: Point3D) -> None:\n                    nonlocal closed_curve_points\n                    start = closed_curve_points[-1]\n                    closed_curve_points += [\n                        start,\n                        (start + start + end) / 3,\n                        (start + end + end) / 3,\n                        end,\n                    ]\n\n            for index, point in enumerate(points):\n                closed_curve_points.append(point)\n                if (\n                    index != len(points) - 1\n                    and (index + 1) % nppc == 0\n                    and any(point != points[index + 1])\n                ):\n                    # Add straight line from last point on this curve to the\n                    # start point on the next curve.\n                    add_line_to(curve_start)\n                    curve_start = points[index + 1]\n            # Make sure last curve is closed\n            add_line_to(curve_start)\n            each.points = np.array(closed_curve_points, ndmin=2)\n\n        if self.gradient:\n            self.set_color_by_gradient(*self.gradient)\n        for col in colormap:\n            self.chars[\n                col[\"start\"] - col[\"start_offset\"] : col[\"end\"]\n                - col[\"start_offset\"]\n                - col[\"end_offset\"]\n            ].set_color(self._parse_color(col[\"color\"]))\n        for grad in gradientmap:\n            self.chars[\n                grad[\"start\"] - grad[\"start_offset\"] : grad[\"end\"]\n                - grad[\"start_offset\"]\n                - grad[\"end_offset\"]\n            ].set_color_by_gradient(\n                *(self._parse_color(grad[\"from\"]), self._parse_color(grad[\"to\"]))\n            )\n        # anti-aliasing\n        if height is None and width is None:\n            self.scale(TEXT_MOB_SCALE_FACTOR)\n\n        self.initial_height = self.height\n\n    @property\n    def font_size(self) -> float:\n        return (\n            self.height\n            / self.initial_height\n            / TEXT_MOB_SCALE_FACTOR\n            * 2.4\n            * self._font_size\n            / DEFAULT_FONT_SIZE\n        )\n\n    @font_size.setter\n    def font_size(self, font_val: float) -> None:\n        # TODO: use pango's font size scaling.\n        if font_val <= 0:\n            raise ValueError(\"font_size must be greater than 0.\")\n        else:\n            self.scale(font_val / self.font_size)\n\n    def _text2hash(self, color: ParsableManimColor) -> str:\n        \"\"\"Generates ``sha256`` hash for file name.\"\"\"\n        settings = (\n            \"MARKUPPANGO\"\n            + self.font\n            + self.slant\n            + self.weight\n            + ManimColor(color).to_hex().lower()\n        )  # to differentiate from classical Pango Text\n        settings += str(self.line_spacing) + str(self._font_size)\n        settings += str(self.disable_ligatures)\n        settings += str(self.justify)\n        id_str = self.text + settings\n        hasher = hashlib.sha256()\n        hasher.update(id_str.encode())\n        return hasher.hexdigest()[:16]\n\n    def _text2svg(self, color: ParsableManimColor | None) -> str:\n        \"\"\"Convert the text to SVG using Pango.\"\"\"\n        color = ManimColor(color)\n        size = self._font_size\n        line_spacing: float = self.line_spacing\n        size /= TEXT2SVG_ADJUSTMENT_FACTOR\n        line_spacing /= TEXT2SVG_ADJUSTMENT_FACTOR\n\n        dir_name = config.get_dir(\"text_dir\")\n        dir_name.mkdir(parents=True, exist_ok=True)\n        hash_name = self._text2hash(color)\n        file_name = dir_name / (hash_name + \".svg\")\n\n        if file_name.exists():\n            svg_file: str = str(file_name.resolve())\n        else:\n            final_text = (\n                f'<span foreground=\"{color.to_hex()}\">{self.text}</span>'\n                if color is not None\n                else self.text\n            )\n            logger.debug(f\"Setting Text {self.text}\")\n            svg_file = MarkupUtils.text2svg(\n                final_text,\n                self.font,\n                self.slant,\n                self.weight,\n                size,\n                line_spacing,\n                self.disable_ligatures,\n                str(file_name.resolve()),\n                START_X,\n                START_Y,\n                600,  # width\n                400,  # height\n                justify=self.justify,\n                pango_width=500,\n            )\n        return svg_file\n\n    def _count_real_chars(self, s: str) -> int:\n        \"\"\"Counts characters that will be displayed.\n\n        This is needed for partial coloring or gradients, because space\n        counts to the text's `len`, but has no corresponding character.\n        \"\"\"\n        count = 0\n        level = 0\n        # temporarily replace HTML entities by single char\n        s = re.sub(\"&[^;]+;\", \"x\", s)\n        for c in s:\n            if c == \"<\":\n                level += 1\n            if c == \">\" and level > 0:\n                level -= 1\n            elif c != \" \" and c != \"\\t\" and level == 0:\n                count += 1\n        return count\n\n    def _extract_gradient_tags(self) -> list[dict[str, Any]]:\n        \"\"\"Used to determine which parts (if any) of the string should be formatted\n        with a gradient.\n\n        Removes the ``<gradient>`` tag, as it is not part of Pango's markup and would cause an error.\n        \"\"\"\n        tags = re.finditer(\n            r'<gradient\\s+from=\"([^\"]+)\"\\s+to=\"([^\"]+)\"(\\s+offset=\"([^\"]+)\")?>(.+?)</gradient>',\n            self.original_text,\n            re.S,\n        )\n        gradientmap: list[dict[str, Any]] = []\n        for tag in tags:\n            start = self._count_real_chars(self.original_text[: tag.start(0)])\n            end = start + self._count_real_chars(tag.group(5))\n            offsets = tag.group(4).split(\",\") if tag.group(4) else [0]\n            start_offset = int(offsets[0]) if offsets[0] else 0\n            end_offset = int(offsets[1]) if len(offsets) == 2 and offsets[1] else 0\n\n            gradientmap.append(\n                {\n                    \"start\": start,\n                    \"end\": end,\n                    \"from\": tag.group(1),\n                    \"to\": tag.group(2),\n                    \"start_offset\": start_offset,\n                    \"end_offset\": end_offset,\n                },\n            )\n        self.text = re.sub(\n            \"<gradient[^>]+>(.+?)</gradient>\", r\"\\1\", self.text, count=0, flags=re.S\n        )\n        return gradientmap\n\n    def _parse_color(self, col: str) -> str:\n        \"\"\"Parse color given in ``<color>`` or ``<gradient>`` tags.\"\"\"\n        if re.match(\"#[0-9a-f]{6}\", col):\n            return col\n        else:\n            return ManimColor(col).to_hex()\n\n    def _extract_color_tags(self) -> list[dict[str, Any]]:\n        \"\"\"Used to determine which parts (if any) of the string should be formatted\n        with a custom color.\n\n        Removes the ``<color>`` tag, as it is not part of Pango's markup and would cause an error.\n\n        Note: Using the ``<color>`` tags is deprecated. As soon as the legacy syntax is gone, this function\n        will be removed.\n        \"\"\"\n        tags = re.finditer(\n            r'<color\\s+col=\"([^\"]+)\"(\\s+offset=\"([^\"]+)\")?>(.+?)</color>',\n            self.original_text,\n            re.S,\n        )\n\n        colormap: list[dict[str, Any]] = []\n        for tag in tags:\n            start = self._count_real_chars(self.original_text[: tag.start(0)])\n            end = start + self._count_real_chars(tag.group(4))\n            offsets = tag.group(3).split(\",\") if tag.group(3) else [0]\n            start_offset = int(offsets[0]) if offsets[0] else 0\n            end_offset = int(offsets[1]) if len(offsets) == 2 and offsets[1] else 0\n\n            colormap.append(\n                {\n                    \"start\": start,\n                    \"end\": end,\n                    \"color\": tag.group(1),\n                    \"start_offset\": start_offset,\n                    \"end_offset\": end_offset,\n                },\n            )\n        self.text = re.sub(\n            \"<color[^>]+>(.+?)</color>\", r\"\\1\", self.text, count=0, flags=re.S\n        )\n        return colormap\n\n    def __repr__(self) -> str:\n        return f\"MarkupText({repr(self.original_text)})\"\n\n\n@contextmanager\ndef register_font(font_file: str | Path) -> Iterator[None]:\n    \"\"\"Temporarily add a font file to Pango's search path.\n\n    This searches for the font_file at various places. The order it searches it described below.\n\n    1. Absolute path.\n    2. In ``assets/fonts`` folder.\n    3. In ``font/`` folder.\n    4. In the same directory.\n\n    Parameters\n    ----------\n    font_file\n        The font file to add.\n\n    Examples\n    --------\n    Use ``with register_font(...)`` to add a font file to search\n    path.\n\n    .. code-block:: python\n\n        with register_font(\"path/to/font_file.ttf\"):\n            a = Text(\"Hello\", font=\"Custom Font Name\")\n\n    Raises\n    ------\n    FileNotFoundError:\n        If the font doesn't exists.\n\n    AttributeError:\n        If this method is used on macOS.\n\n    .. important ::\n\n        This method is available for macOS for ``ManimPango>=v0.2.3``. Using this\n        method with previous releases will raise an :class:`AttributeError` on macOS.\n    \"\"\"\n    input_folder = Path(config.input_file).parent.resolve()\n    possible_paths = [\n        Path(font_file),\n        input_folder / \"assets/fonts\" / font_file,\n        input_folder / \"fonts\" / font_file,\n        input_folder / font_file,\n    ]\n    for path in possible_paths:\n        path = path.resolve()\n        if path.exists():\n            file_path = path\n            logger.debug(\"Found file at %s\", file_path.absolute())\n            break\n    else:\n        error = f\"Can't find {font_file}. Checked paths: {possible_paths}\"\n        raise FileNotFoundError(error)\n\n    try:\n        assert manimpango.register_font(str(file_path))\n        yield\n    finally:\n        manimpango.unregister_font(str(file_path))\n"
  },
  {
    "path": "manim/mobject/three_d/__init__.py",
    "content": "\"\"\"Three-dimensional mobjects.\n\nModules\n=======\n\n.. autosummary::\n    :toctree: ../reference\n\n    ~polyhedra\n    ~three_d_utils\n    ~three_dimensions\n\"\"\"\n"
  },
  {
    "path": "manim/mobject/three_d/polyhedra.py",
    "content": "\"\"\"General polyhedral class and platonic solids.\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import Hashable\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom manim.mobject.geometry.polygram import Polygon\nfrom manim.mobject.graph import Graph\nfrom manim.mobject.three_d.three_dimensions import Dot3D\nfrom manim.mobject.types.vectorized_mobject import VGroup\nfrom manim.utils.qhull import QuickHull\n\nif TYPE_CHECKING:\n    from manim.mobject.mobject import Mobject\n    from manim.typing import Point3D, Point3DLike_Array\n\n__all__ = [\n    \"Polyhedron\",\n    \"Tetrahedron\",\n    \"Octahedron\",\n    \"Icosahedron\",\n    \"Dodecahedron\",\n    \"ConvexHull3D\",\n]\n\n\nclass Polyhedron(VGroup):\n    \"\"\"An abstract polyhedra class.\n\n    In this implementation, polyhedra are defined with a list of vertex coordinates in space, and a list\n    of faces. This implementation mirrors that of a standard polyhedral data format (OFF, object file format).\n\n    Parameters\n    ----------\n    vertex_coords\n        A list of coordinates of the corresponding vertices in the polyhedron. Each coordinate will correspond to\n        a vertex. The vertices are indexed with the usual indexing of Python.\n    faces_list\n        A list of faces. Each face is a sublist containing the indices of the vertices that form the corners of that face.\n    faces_config\n        Configuration for the polygons representing the faces of the polyhedron.\n    graph_config\n        Configuration for the graph containing the vertices and edges of the polyhedron.\n\n    Examples\n    --------\n    To understand how to create a custom polyhedra, let's use the example of a rather simple one - a square pyramid.\n\n    .. manim:: SquarePyramidScene\n        :save_last_frame:\n\n        class SquarePyramidScene(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                vertex_coords = [\n                    [1, 1, 0],\n                    [1, -1, 0],\n                    [-1, -1, 0],\n                    [-1, 1, 0],\n                    [0, 0, 2]\n                ]\n                faces_list = [\n                    [0, 1, 4],\n                    [1, 2, 4],\n                    [2, 3, 4],\n                    [3, 0, 4],\n                    [0, 1, 2, 3]\n                ]\n                pyramid = Polyhedron(vertex_coords, faces_list)\n                self.add(pyramid)\n\n    In defining the polyhedron above, we first defined the coordinates of the vertices.\n    These are the corners of the square base, given as the first four coordinates in the vertex list,\n    and the apex, the last coordinate in the list.\n\n    Next, we define the faces of the polyhedron. The triangular surfaces of the pyramid are polygons\n    with two adjacent vertices in the base and the vertex at the apex as corners. We thus define these\n    surfaces in the first four elements of our face list. The last element defines the base of the pyramid.\n\n    The graph and faces of polyhedra can also be accessed and modified directly, after instantiation.\n    They are stored in the `graph` and `faces` attributes respectively.\n\n    .. manim:: PolyhedronSubMobjects\n        :save_last_frame:\n\n        class PolyhedronSubMobjects(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                octahedron = Octahedron(edge_length = 3)\n                octahedron.graph[0].set_color(RED)\n                octahedron.faces[2].set_color(YELLOW)\n                self.add(octahedron)\n    \"\"\"\n\n    def __init__(\n        self,\n        vertex_coords: Point3DLike_Array,\n        faces_list: list[list[int]],\n        faces_config: dict[str, str | int | float | bool] = {},\n        graph_config: dict[str, Any] = {},\n    ):\n        super().__init__()\n        self.faces_config = dict(\n            {\"fill_opacity\": 0.5, \"shade_in_3d\": True}, **faces_config\n        )\n        self.graph_config = dict(\n            {\n                \"vertex_type\": Dot3D,\n                \"edge_config\": {\n                    \"stroke_opacity\": 0,  # I find that having the edges visible makes the polyhedra look weird\n                },\n            },\n            **graph_config,\n        )\n        self.vertex_coords = vertex_coords\n        self.vertex_indices = list(range(len(self.vertex_coords)))\n        self.layout: dict[Hashable, Any] = dict(enumerate(self.vertex_coords))\n        self.faces_list = faces_list\n        self.face_coords = [[self.layout[j] for j in i] for i in faces_list]\n        self.edges = self.get_edges(self.faces_list)\n        self.faces = self.create_faces(self.face_coords)\n        self.graph = Graph(\n            self.vertex_indices, self.edges, layout=self.layout, **self.graph_config\n        )\n        self.add(self.faces, self.graph)\n        self.add_updater(self.update_faces)\n\n    def get_edges(self, faces_list: list[list[int]]) -> list[tuple[int, int]]:\n        \"\"\"Creates list of cyclic pairwise tuples.\"\"\"\n        edges: list[tuple[int, int]] = []\n        for face in faces_list:\n            edges += zip(face, face[1:] + face[:1], strict=True)\n        return edges\n\n    def create_faces(\n        self,\n        face_coords: Point3DLike_Array,\n    ) -> VGroup:\n        \"\"\"Creates VGroup of faces from a list of face coordinates.\"\"\"\n        face_group = VGroup()\n        for face in face_coords:\n            face_group.add(Polygon(*face, **self.faces_config))\n        return face_group\n\n    def update_faces(self, m: Mobject) -> None:\n        face_coords = self.extract_face_coords()\n        new_faces = self.create_faces(face_coords)\n        self.faces.match_points(new_faces)\n\n    def extract_face_coords(self) -> Point3DLike_Array:\n        \"\"\"Extracts the coordinates of the vertices in the graph.\n        Used for updating faces.\n        \"\"\"\n        new_vertex_coords = [self.graph[v].get_center() for v in self.graph.vertices]\n        layout = dict(enumerate(new_vertex_coords))\n        return [[layout[j] for j in i] for i in self.faces_list]\n\n\nclass Tetrahedron(Polyhedron):\n    \"\"\"A tetrahedron, one of the five platonic solids. It has 4 faces, 6 edges, and 4 vertices.\n\n    Parameters\n    ----------\n    edge_length\n        The length of an edge between any two vertices.\n\n    Examples\n    --------\n\n    .. manim:: TetrahedronScene\n        :save_last_frame:\n\n        class TetrahedronScene(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                obj = Tetrahedron()\n                self.add(obj)\n    \"\"\"\n\n    def __init__(self, edge_length: float = 1, **kwargs: Any):\n        unit = edge_length * np.sqrt(2) / 4\n        super().__init__(\n            vertex_coords=[\n                np.array([unit, unit, unit]),\n                np.array([unit, -unit, -unit]),\n                np.array([-unit, unit, -unit]),\n                np.array([-unit, -unit, unit]),\n            ],\n            faces_list=[[0, 1, 2], [3, 0, 2], [0, 1, 3], [3, 1, 2]],\n            **kwargs,\n        )\n\n\nclass Octahedron(Polyhedron):\n    \"\"\"An octahedron, one of the five platonic solids. It has 8 faces, 12 edges and 6 vertices.\n\n    Parameters\n    ----------\n    edge_length\n        The length of an edge between any two vertices.\n\n    Examples\n    --------\n\n    .. manim:: OctahedronScene\n        :save_last_frame:\n\n        class OctahedronScene(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                obj = Octahedron()\n                self.add(obj)\n    \"\"\"\n\n    def __init__(self, edge_length: float = 1, **kwargs: Any):\n        unit = edge_length * np.sqrt(2) / 2\n        super().__init__(\n            vertex_coords=[\n                np.array([unit, 0, 0]),\n                np.array([-unit, 0, 0]),\n                np.array([0, unit, 0]),\n                np.array([0, -unit, 0]),\n                np.array([0, 0, unit]),\n                np.array([0, 0, -unit]),\n            ],\n            faces_list=[\n                [2, 4, 1],\n                [0, 4, 2],\n                [4, 3, 0],\n                [1, 3, 4],\n                [3, 5, 0],\n                [1, 5, 3],\n                [2, 5, 1],\n                [0, 5, 2],\n            ],\n            **kwargs,\n        )\n\n\nclass Icosahedron(Polyhedron):\n    \"\"\"An icosahedron, one of the five platonic solids. It has 20 faces, 30 edges and 12 vertices.\n\n    Parameters\n    ----------\n    edge_length\n        The length of an edge between any two vertices.\n\n    Examples\n    --------\n\n    .. manim:: IcosahedronScene\n        :save_last_frame:\n\n        class IcosahedronScene(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                obj = Icosahedron()\n                self.add(obj)\n    \"\"\"\n\n    def __init__(self, edge_length: float = 1, **kwargs: Any):\n        unit_a = edge_length * ((1 + np.sqrt(5)) / 4)\n        unit_b = edge_length * (1 / 2)\n        super().__init__(\n            vertex_coords=[\n                np.array([0, unit_b, unit_a]),\n                np.array([0, -unit_b, unit_a]),\n                np.array([0, unit_b, -unit_a]),\n                np.array([0, -unit_b, -unit_a]),\n                np.array([unit_b, unit_a, 0]),\n                np.array([unit_b, -unit_a, 0]),\n                np.array([-unit_b, unit_a, 0]),\n                np.array([-unit_b, -unit_a, 0]),\n                np.array([unit_a, 0, unit_b]),\n                np.array([unit_a, 0, -unit_b]),\n                np.array([-unit_a, 0, unit_b]),\n                np.array([-unit_a, 0, -unit_b]),\n            ],\n            faces_list=[\n                [1, 8, 0],\n                [1, 5, 7],\n                [8, 5, 1],\n                [7, 3, 5],\n                [5, 9, 3],\n                [8, 9, 5],\n                [3, 2, 9],\n                [9, 4, 2],\n                [8, 4, 9],\n                [0, 4, 8],\n                [6, 4, 0],\n                [6, 2, 4],\n                [11, 2, 6],\n                [3, 11, 2],\n                [0, 6, 10],\n                [10, 1, 0],\n                [10, 7, 1],\n                [11, 7, 3],\n                [10, 11, 7],\n                [10, 11, 6],\n            ],\n            **kwargs,\n        )\n\n\nclass Dodecahedron(Polyhedron):\n    \"\"\"A dodecahedron, one of the five platonic solids. It has 12 faces, 30 edges and 20 vertices.\n\n    Parameters\n    ----------\n    edge_length\n        The length of an edge between any two vertices.\n\n    Examples\n    --------\n\n    .. manim:: DodecahedronScene\n        :save_last_frame:\n\n        class DodecahedronScene(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                obj = Dodecahedron()\n                self.add(obj)\n    \"\"\"\n\n    def __init__(self, edge_length: float = 1, **kwargs: Any):\n        unit_a = edge_length * ((1 + np.sqrt(5)) / 4)\n        unit_b = edge_length * ((3 + np.sqrt(5)) / 4)\n        unit_c = edge_length * (1 / 2)\n        super().__init__(\n            vertex_coords=[\n                np.array([unit_a, unit_a, unit_a]),\n                np.array([unit_a, unit_a, -unit_a]),\n                np.array([unit_a, -unit_a, unit_a]),\n                np.array([unit_a, -unit_a, -unit_a]),\n                np.array([-unit_a, unit_a, unit_a]),\n                np.array([-unit_a, unit_a, -unit_a]),\n                np.array([-unit_a, -unit_a, unit_a]),\n                np.array([-unit_a, -unit_a, -unit_a]),\n                np.array([0, unit_c, unit_b]),\n                np.array([0, unit_c, -unit_b]),\n                np.array([0, -unit_c, -unit_b]),\n                np.array([0, -unit_c, unit_b]),\n                np.array([unit_c, unit_b, 0]),\n                np.array([-unit_c, unit_b, 0]),\n                np.array([unit_c, -unit_b, 0]),\n                np.array([-unit_c, -unit_b, 0]),\n                np.array([unit_b, 0, unit_c]),\n                np.array([-unit_b, 0, unit_c]),\n                np.array([unit_b, 0, -unit_c]),\n                np.array([-unit_b, 0, -unit_c]),\n            ],\n            faces_list=[\n                [18, 16, 0, 12, 1],\n                [3, 18, 16, 2, 14],\n                [3, 10, 9, 1, 18],\n                [1, 9, 5, 13, 12],\n                [0, 8, 4, 13, 12],\n                [2, 16, 0, 8, 11],\n                [4, 17, 6, 11, 8],\n                [17, 19, 5, 13, 4],\n                [19, 7, 15, 6, 17],\n                [6, 15, 14, 2, 11],\n                [19, 5, 9, 10, 7],\n                [7, 10, 3, 14, 15],\n            ],\n            **kwargs,\n        )\n\n\nclass ConvexHull3D(Polyhedron):\n    \"\"\"A convex hull for a set of points\n\n    Parameters\n    ----------\n    points\n        The points to consider.\n    tolerance\n        The tolerance used for quickhull.\n    kwargs\n        Forwarded to the parent constructor.\n\n    Examples\n    --------\n    .. manim:: ConvexHull3DExample\n        :save_last_frame:\n        :quality: high\n\n        class ConvexHull3DExample(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                points = [\n                    [ 1.93192757,  0.44134585, -1.52407061],\n                    [-0.93302521,  1.23206983,  0.64117067],\n                    [-0.44350918, -0.61043677,  0.21723705],\n                    [-0.42640268, -1.05260843,  1.61266094],\n                    [-1.84449637,  0.91238739, -1.85172623],\n                    [ 1.72068132, -0.11880457,  0.51881751],\n                    [ 0.41904805,  0.44938012, -1.86440686],\n                    [ 0.83864666,  1.66653337,  1.88960123],\n                    [ 0.22240514, -0.80986286,  1.34249326],\n                    [-1.29585759,  1.01516189,  0.46187522],\n                    [ 1.7776499,  -1.59550796, -1.70240747],\n                    [ 0.80065226, -0.12530398,  1.70063977],\n                    [ 1.28960948, -1.44158255,  1.39938582],\n                    [-0.93538943,  1.33617705, -0.24852643],\n                    [-1.54868271,  1.7444399,  -0.46170734]\n                ]\n                hull = ConvexHull3D(\n                    *points,\n                    faces_config = {\"stroke_opacity\": 0},\n                    graph_config = {\n                        \"vertex_type\": Dot3D,\n                        \"edge_config\": {\n                            \"stroke_color\": BLUE,\n                            \"stroke_width\": 2,\n                            \"stroke_opacity\": 0.05,\n                        }\n                    }\n                )\n                dots = VGroup(*[Dot3D(point) for point in points])\n                self.add(hull)\n                self.add(dots)\n    \"\"\"\n\n    def __init__(self, *points: Point3D, tolerance: float = 1e-5, **kwargs: Any):\n        # Build Convex Hull\n        array = np.array(points)\n        hull = QuickHull(tolerance)\n        hull.build(array)\n\n        # Setup Lists\n        vertices = []\n        faces = []\n\n        # Extract Faces\n        c = 0\n        d = {}\n        facets = set(hull.facets) - hull.removed\n        for facet in facets:\n            tmp = set()\n            for subfacet in facet.subfacets:\n                for point in subfacet.points:\n                    if point not in d:\n                        vertices.append(point.coordinates)\n                        d[point] = c\n                        c += 1\n                    tmp.add(point)\n            faces.append([d[point] for point in tmp])\n\n        # Call Polyhedron\n        super().__init__(\n            vertex_coords=vertices,\n            faces_list=faces,\n            **kwargs,\n        )\n"
  },
  {
    "path": "manim/mobject/three_d/three_d_utils.py",
    "content": "\"\"\"Utility functions for three-dimensional mobjects.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"get_3d_vmob_gradient_start_and_end_points\",\n    \"get_3d_vmob_start_corner_index\",\n    \"get_3d_vmob_end_corner_index\",\n    \"get_3d_vmob_start_corner\",\n    \"get_3d_vmob_end_corner\",\n    \"get_3d_vmob_unit_normal\",\n    \"get_3d_vmob_start_corner_unit_normal\",\n    \"get_3d_vmob_end_corner_unit_normal\",\n]\n\n\nfrom typing import TYPE_CHECKING, Literal\n\nimport numpy as np\n\nfrom manim.constants import ORIGIN, UP\nfrom manim.utils.space_ops import get_unit_normal\n\nif TYPE_CHECKING:\n    from manim.typing import Point3D, Vector3D\n\n    from ..types.vectorized_mobject import VMobject\n\n\ndef get_3d_vmob_gradient_start_and_end_points(\n    vmob: VMobject,\n) -> tuple[Point3D, Point3D]:\n    return (\n        get_3d_vmob_start_corner(vmob),\n        get_3d_vmob_end_corner(vmob),\n    )\n\n\ndef get_3d_vmob_start_corner_index(vmob: VMobject) -> Literal[0]:\n    return 0\n\n\ndef get_3d_vmob_end_corner_index(vmob: VMobject) -> int:\n    return ((len(vmob.points) - 1) // 6) * 3\n\n\ndef get_3d_vmob_start_corner(vmob: VMobject) -> Point3D:\n    if vmob.get_num_points() == 0:\n        return np.array(ORIGIN)\n    return vmob.points[get_3d_vmob_start_corner_index(vmob)]\n\n\ndef get_3d_vmob_end_corner(vmob: VMobject) -> Point3D:\n    if vmob.get_num_points() == 0:\n        return np.array(ORIGIN)\n    return vmob.points[get_3d_vmob_end_corner_index(vmob)]\n\n\ndef get_3d_vmob_unit_normal(vmob: VMobject, point_index: int) -> Vector3D:\n    n_points = vmob.get_num_points()\n    if len(vmob.get_anchors()) <= 2:\n        return np.array(UP)\n    i = point_index\n    im3 = i - 3 if i > 2 else (n_points - 4)\n    ip3 = i + 3 if i < (n_points - 3) else 3\n    unit_normal = get_unit_normal(\n        vmob.points[ip3] - vmob.points[i],\n        vmob.points[im3] - vmob.points[i],\n    )\n    if np.linalg.norm(unit_normal) == 0:\n        return np.array(UP)\n    return unit_normal\n\n\ndef get_3d_vmob_start_corner_unit_normal(vmob: VMobject) -> Vector3D:\n    return get_3d_vmob_unit_normal(vmob, get_3d_vmob_start_corner_index(vmob))\n\n\ndef get_3d_vmob_end_corner_unit_normal(vmob: VMobject) -> Vector3D:\n    return get_3d_vmob_unit_normal(vmob, get_3d_vmob_end_corner_index(vmob))\n"
  },
  {
    "path": "manim/mobject/three_d/three_dimensions.py",
    "content": "\"\"\"Three-dimensional mobjects.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"ThreeDVMobject\",\n    \"Surface\",\n    \"Sphere\",\n    \"Dot3D\",\n    \"Cube\",\n    \"Prism\",\n    \"Cone\",\n    \"Arrow3D\",\n    \"Cylinder\",\n    \"Line3D\",\n    \"Torus\",\n]\n\nfrom collections.abc import Callable, Iterable, Sequence\nfrom typing import TYPE_CHECKING, Any, Literal, Self\n\nimport numpy as np\n\nfrom manim import config, logger\nfrom manim.constants import *\nfrom manim.mobject.geometry.arc import Circle\nfrom manim.mobject.geometry.polygram import Square\nfrom manim.mobject.mobject import *\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.mobject.types.vectorized_mobject import VectorizedPoint, VGroup, VMobject\nfrom manim.utils.color import (\n    BLUE,\n    BLUE_D,\n    BLUE_E,\n    LIGHT_GREY,\n    WHITE,\n    ManimColor,\n    ParsableManimColor,\n    interpolate_color,\n)\nfrom manim.utils.space_ops import normalize, perpendicular_bisector, z_to_vector\n\nif TYPE_CHECKING:\n    from manim.mobject.graphing.coordinate_systems import ThreeDAxes\n    from manim.typing import Point3D, Point3DLike, Vector3D, Vector3DLike\n\n\nclass ThreeDVMobject(VMobject, metaclass=ConvertToOpenGL):\n    u_index: int\n    v_index: int\n    u1: float\n    u2: float\n    v1: float\n    v2: float\n\n    def __init__(self, shade_in_3d: bool = True, **kwargs: Any):\n        super().__init__(shade_in_3d=shade_in_3d, **kwargs)\n\n\nclass Surface(VGroup, metaclass=ConvertToOpenGL):\n    \"\"\"Creates a Parametric Surface using a checkerboard pattern.\n\n    Parameters\n    ----------\n    func\n        The function defining the :class:`Surface`.\n    u_range\n        The range of the ``u`` variable: ``(u_min, u_max)``.\n    v_range\n        The range of the ``v`` variable: ``(v_min, v_max)``.\n    resolution\n        The number of samples taken of the :class:`Surface`. A tuple can be\n        used to define different resolutions for ``u`` and ``v`` respectively.\n    fill_color\n        The color of the :class:`Surface`. Ignored if ``checkerboard_colors``\n        is set.\n    fill_opacity\n        The opacity of the :class:`Surface`, from 0 being fully transparent\n        to 1 being fully opaque. Defaults to 1.\n    checkerboard_colors\n        ng individual faces alternating colors. Overrides ``fill_color``.\n    stroke_color\n        Color of the stroke surrounding each face of :class:`Surface`.\n    stroke_width\n        Width of the stroke surrounding each face of :class:`Surface`.\n        Defaults to 0.5.\n    should_make_jagged\n        Changes the anchor mode of the Bézier curves from smooth to jagged.\n        Defaults to ``False``.\n\n    Examples\n    --------\n    .. manim:: ParaSurface\n        :save_last_frame:\n\n        class ParaSurface(ThreeDScene):\n            def func(self, u, v):\n                return np.array([np.cos(u) * np.cos(v), np.cos(u) * np.sin(v), u])\n\n            def construct(self):\n                axes = ThreeDAxes(x_range=[-4,4], x_length=8)\n                surface = Surface(\n                    lambda u, v: axes.c2p(*self.func(u, v)),\n                    u_range=[-PI, PI],\n                    v_range=[0, TAU],\n                    resolution=8,\n                )\n                self.set_camera_orientation(theta=70 * DEGREES, phi=75 * DEGREES)\n                self.add(axes, surface)\n    \"\"\"\n\n    def __init__(\n        self,\n        func: Callable[[float, float], np.ndarray],\n        u_range: tuple[float, float] = (0, 1),\n        v_range: tuple[float, float] = (0, 1),\n        resolution: int | Sequence[int] = 32,\n        surface_piece_config: dict = {},\n        fill_color: ParsableManimColor = BLUE_D,\n        fill_opacity: float = 1.0,\n        checkerboard_colors: Iterable[ParsableManimColor] | Literal[False] = [\n            BLUE_D,\n            BLUE_E,\n        ],\n        stroke_color: ParsableManimColor = LIGHT_GREY,\n        stroke_width: float = 0.5,\n        should_make_jagged: bool = False,\n        pre_function_handle_to_anchor_scale_factor: float = 0.00001,\n        **kwargs: Any,\n    ) -> None:\n        self.u_range = u_range\n        self.v_range = v_range\n        super().__init__(\n            fill_color=fill_color,\n            fill_opacity=fill_opacity,\n            stroke_color=stroke_color,\n            stroke_width=stroke_width,\n            **kwargs,\n        )\n        self.resolution = resolution\n        self.surface_piece_config = surface_piece_config\n        self.checkerboard_colors: list[ManimColor] | Literal[False]\n        if checkerboard_colors is False:\n            self.checkerboard_colors = checkerboard_colors\n        else:\n            self.checkerboard_colors = [ManimColor(i) for i in checkerboard_colors]\n        self.should_make_jagged = should_make_jagged\n        self.pre_function_handle_to_anchor_scale_factor = (\n            pre_function_handle_to_anchor_scale_factor\n        )\n        self.list_of_faces: list[ThreeDVMobject] = []\n        self._func = func\n        self._setup_in_uv_space()\n        self.apply_function(lambda p: func(p[0], p[1]))\n        if self.should_make_jagged:\n            self.make_jagged()\n\n    def func(self, u: float, v: float) -> np.ndarray:\n        return self._func(u, v)\n\n    def _get_u_values_and_v_values(self) -> tuple[np.ndarray, np.ndarray]:\n        if isinstance(self.resolution, int):\n            u_res = v_res = self.resolution\n        else:\n            u_res, v_res = self.resolution\n\n        u_values = np.linspace(*self.u_range, u_res + 1)\n        v_values = np.linspace(*self.v_range, v_res + 1)\n\n        return u_values, v_values\n\n    def _setup_in_uv_space(self) -> None:\n        u_values, v_values = self._get_u_values_and_v_values()\n        faces = VGroup()\n        self.list_of_faces = []\n        for i in range(len(u_values) - 1):\n            for j in range(len(v_values) - 1):\n                u1, u2 = u_values[i : i + 2]\n                v1, v2 = v_values[j : j + 2]\n                face = ThreeDVMobject()\n                face.set_points_as_corners(\n                    [\n                        [u1, v1, 0],\n                        [u2, v1, 0],\n                        [u2, v2, 0],\n                        [u1, v2, 0],\n                        [u1, v1, 0],\n                    ],\n                )\n                faces.add(face)\n                face.u_index = i\n                face.v_index = j\n                face.u1 = u1\n                face.u2 = u2\n                face.v1 = v1\n                face.v2 = v2\n                self.list_of_faces.append(face)\n        faces.set_fill(color=self.fill_color, opacity=self.fill_opacity)\n        faces.set_stroke(\n            color=self.stroke_color,\n            width=self.stroke_width,\n            opacity=self.stroke_opacity,\n        )\n        self.add(*faces)\n        if self.checkerboard_colors:\n            self.set_fill_by_checkerboard(*self.checkerboard_colors)\n\n    def set_fill_by_checkerboard(\n        self, *colors: ParsableManimColor, opacity: float | None = None\n    ) -> Self:\n        \"\"\"Sets the fill_color of each face of :class:`Surface` in\n        an alternating pattern.\n\n        Parameters\n        ----------\n        colors\n            List of colors for alternating pattern.\n        opacity\n            The fill_opacity of :class:`Surface`, from 0 being fully transparent\n            to 1 being fully opaque.\n\n        Returns\n        -------\n        :class:`~.Surface`\n            The parametric surface with an alternating pattern.\n        \"\"\"\n        n_colors = len(colors)\n        for face in self.list_of_faces:\n            c_index = (face.u_index + face.v_index) % n_colors\n            face.set_fill(colors[c_index], opacity=opacity)\n        return self\n\n    def set_fill_by_value(\n        self,\n        axes: ThreeDAxes,\n        colorscale: Iterable[ParsableManimColor]\n        | Iterable[tuple[ParsableManimColor, float]]\n        | None = None,\n        axis: int = 2,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"Sets the color of each mobject of a parametric surface to a color\n        relative to its axis-value.\n\n        Parameters\n        ----------\n        axes\n            The axes for the parametric surface, which will be used to map\n            axis-values to colors.\n        colorscale\n            A list of colors, ordered from lower axis-values to higher axis-values.\n            If a list of tuples is passed containing colors paired with numbers,\n            then those numbers will be used as the pivots.\n        axis\n            The chosen axis to use for the color mapping. (0 = x, 1 = y, 2 = z)\n\n        Returns\n        -------\n        :class:`~.Surface`\n            The parametric surface with a gradient applied by value. For chaining.\n\n        Examples\n        --------\n        .. manim:: FillByValueExample\n            :save_last_frame:\n\n            class FillByValueExample(ThreeDScene):\n                def construct(self):\n                    resolution_fa = 8\n                    self.set_camera_orientation(phi=75 * DEGREES, theta=-160 * DEGREES)\n                    axes = ThreeDAxes(x_range=(0, 5, 1), y_range=(0, 5, 1), z_range=(-1, 1, 0.5))\n                    def param_surface(u, v):\n                        x = u\n                        y = v\n                        z = np.sin(x) * np.cos(y)\n                        return z\n                    surface_plane = Surface(\n                        lambda u, v: axes.c2p(u, v, param_surface(u, v)),\n                        resolution=(resolution_fa, resolution_fa),\n                        v_range=[0, 5],\n                        u_range=[0, 5],\n                        )\n                    surface_plane.set_style(fill_opacity=1)\n                    surface_plane.set_fill_by_value(axes=axes, colorscale=[(RED, -0.5), (YELLOW, 0), (GREEN, 0.5)], axis=2)\n                    self.add(axes, surface_plane)\n        \"\"\"\n        if \"colors\" in kwargs and colorscale is None:\n            colorscale = kwargs.pop(\"colors\")\n            if kwargs:\n                raise ValueError(\n                    \"Unsupported keyword argument(s): \"\n                    f\"{', '.join(str(key) for key in kwargs)}\"\n                )\n        if colorscale is None:\n            logger.warning(\n                \"The value passed to the colorscale keyword argument was None, \"\n                \"the surface fill color has not been changed\"\n            )\n            return self\n        colorscale_list = list(colorscale)\n\n        ranges = [axes.x_range, axes.y_range, axes.z_range]\n        assert isinstance(colorscale_list, list)\n        new_colors: list[ManimColor]\n        if type(colorscale_list[0]) is tuple and len(colorscale_list[0]) == 2:\n            new_colors, pivots = [\n                [ManimColor(i) for i, j in colorscale_list],\n                [j for i, j in colorscale_list],\n            ]\n        else:\n            new_colors = [ManimColor(i) for i in colorscale_list]\n            current_range = ranges[axis]\n\n            assert current_range is not None\n            pivot_min = current_range[0]\n            pivot_max = current_range[1]\n            pivot_frequency = (pivot_max - pivot_min) / (len(new_colors) - 1)\n            pivots = np.arange(\n                start=pivot_min,\n                stop=pivot_max + pivot_frequency,\n                step=pivot_frequency,\n            )\n\n        for mob in self.family_members_with_points():\n            axis_value = axes.point_to_coords(mob.get_midpoint())[axis]\n            if axis_value <= pivots[0]:\n                mob.set_color(new_colors[0])\n            elif axis_value >= pivots[-1]:\n                mob.set_color(new_colors[-1])\n            else:\n                for i, pivot in enumerate(pivots):\n                    if pivot > axis_value:\n                        color_index = (axis_value - pivots[i - 1]) / (\n                            pivots[i] - pivots[i - 1]\n                        )\n                        color_index = min(color_index, 1)\n                        mob_color = interpolate_color(\n                            new_colors[i - 1],\n                            new_colors[i],\n                            color_index,\n                        )\n                        if config.renderer == RendererType.OPENGL:\n                            assert isinstance(mob, OpenGLMobject)\n                            mob.set_color(mob_color, recurse=False)\n                        elif config.renderer == RendererType.CAIRO:\n                            mob.set_color(mob_color, family=False)\n                        break\n\n        return self\n\n\n# Specific shapes\n\n\nclass Sphere(Surface):\n    \"\"\"A three-dimensional sphere.\n\n    Parameters\n    ----------\n    center\n        Center of the :class:`Sphere`.\n    radius\n        The radius of the :class:`Sphere`.\n    resolution\n        The number of samples taken of the :class:`Sphere`. A tuple can be used\n        to define different resolutions for ``u`` and ``v`` respectively.\n    u_range\n        The range of the ``u`` variable: ``(u_min, u_max)``.\n    v_range\n        The range of the ``v`` variable: ``(v_min, v_max)``.\n\n    Examples\n    --------\n\n    .. manim:: ExampleSphere\n        :save_last_frame:\n\n        class ExampleSphere(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=PI / 6, theta=PI / 6)\n                sphere1 = Sphere(center=(3, 0, 0), radius=1, resolution=(20, 20))\n                sphere1.set_color(RED)\n                self.add(sphere1)\n                sphere2 = Sphere(center=(-1, -3, 0), radius=2, resolution=(18, 18))\n                sphere2.set_color(GREEN)\n                self.add(sphere2)\n                sphere3 = Sphere(center=(-1, 2, 0), radius=2, resolution=(16, 16))\n                sphere3.set_color(BLUE)\n                self.add(sphere3)\n\n    This example shows that overlapping spheres can intersect with rough transitions.\n\n    .. manim:: ExampleSphereOverlap\n        :save_last_frame:\n\n        class ExampleSphereOverlap(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=PI / 4, theta=PI / 4)\n                sphere1 = Sphere(center=(0, 0, 0), radius=1, resolution=(20, 20))\n                sphere1.set_color(RED)\n                self.add(sphere1)\n                sphere2 = Sphere(center=(-0.5, -1, 0.5), radius=1.2, resolution=(20, 20))\n                sphere2.set_color(GREEN)\n                self.add(sphere2)\n                sphere3 = Sphere(center=(1, -1, 0), radius=1.1, resolution=(20, 20))\n                sphere3.set_color(BLUE)\n                self.add(sphere3)\n\n    In this example, by modifying ``u_range`` (the range of the azimuthal angle) and\n    ``v_range`` (the range of the polar angle), it is possible to obtain a portion of a\n    sphere:\n\n    .. manim:: ExamplePartialSpheres\n        :save_last_frame:\n\n        class ExamplePartialSpheres(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=PI / 4)\n                sphere1 = Sphere(\n                    center=(-3, 0, 0),\n                    resolution=(10, 20),\n                    u_range=[TAU / 4, 3 * TAU / 4],\n                )\n                sphere1.set_color(RED)\n                self.add(sphere1)\n                sphere2 = Sphere(\n                    center=(0, 0, 0),\n                    resolution=(20, 10),\n                    v_range=[0, TAU / 4],\n                )\n                sphere2.set_color(GREEN)\n                self.add(sphere2)\n                sphere3 = Sphere(\n                    center=(3, 0, 0),\n                    resolution=(5, 10),\n                    u_range=[3 * TAU / 4, TAU],\n                    v_range=[TAU / 4, TAU / 2],\n                )\n                sphere3.set_color(BLUE)\n                self.add(sphere3)\n    \"\"\"\n\n    def __init__(\n        self,\n        center: Point3DLike = ORIGIN,\n        radius: float = 1,\n        resolution: int | Sequence[int] | None = None,\n        u_range: tuple[float, float] = (0, TAU),\n        v_range: tuple[float, float] = (0, PI),\n        **kwargs: Any,\n    ) -> None:\n        if config.renderer == RendererType.OPENGL:\n            res_value = (101, 51)\n        elif config.renderer == RendererType.CAIRO:\n            res_value = (24, 12)\n        else:\n            raise Exception(\"Unknown renderer\")\n\n        resolution = resolution if resolution is not None else res_value\n\n        self.radius = radius\n\n        super().__init__(\n            self.func,\n            resolution=resolution,\n            u_range=u_range,\n            v_range=v_range,\n            **kwargs,\n        )\n\n        self.shift(center)\n\n    def func(self, u: float, v: float) -> Point3D:\n        \"\"\"The z values defining the :class:`Sphere` being plotted.\n\n        Returns\n        -------\n        :class:`Point3D`\n            The z values defining the :class:`Sphere`.\n        \"\"\"\n        return self.radius * np.array(\n            [np.cos(u) * np.sin(v), np.sin(u) * np.sin(v), -np.cos(v)],\n        )\n\n\nclass Dot3D(Sphere):\n    \"\"\"A spherical dot.\n\n    Parameters\n    ----------\n    point\n        The location of the dot.\n    radius\n        The radius of the dot.\n    color\n        The color of the :class:`Dot3D`.\n    resolution\n        The number of samples taken of the :class:`Dot3D`. A tuple can be\n        used to define different resolutions for ``u`` and ``v`` respectively.\n\n    Examples\n    --------\n\n    .. manim:: Dot3DExample\n        :save_last_frame:\n\n        class Dot3DExample(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=75*DEGREES, theta=-45*DEGREES)\n\n                axes = ThreeDAxes()\n                dot_1 = Dot3D(point=axes.coords_to_point(0, 0, 1), color=RED)\n                dot_2 = Dot3D(point=axes.coords_to_point(2, 0, 0), radius=0.1, color=BLUE)\n                dot_3 = Dot3D(point=[0, 0, 0], radius=0.1, color=ORANGE)\n                self.add(axes, dot_1, dot_2,dot_3)\n    \"\"\"\n\n    def __init__(\n        self,\n        point: Point3D = ORIGIN,\n        radius: float = DEFAULT_DOT_RADIUS,\n        color: ParsableManimColor = WHITE,\n        resolution: int | tuple[int, int] | None = (8, 8),\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(center=point, radius=radius, resolution=resolution, **kwargs)\n        self.set_color(color)\n\n\nclass Cube(VGroup):\n    \"\"\"A three-dimensional cube.\n\n    Parameters\n    ----------\n    side_length\n        Length of each side of the :class:`Cube`.\n    fill_opacity\n        The opacity of the :class:`Cube`, from 0 being fully transparent to 1 being\n        fully opaque. Defaults to 0.75.\n    fill_color\n        The color of the :class:`Cube`.\n    stroke_width\n        The width of the stroke surrounding each face of the :class:`Cube`.\n\n    Examples\n    --------\n\n    .. manim:: CubeExample\n        :save_last_frame:\n\n        class CubeExample(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=75*DEGREES, theta=-45*DEGREES)\n\n                axes = ThreeDAxes()\n                cube = Cube(side_length=3, fill_opacity=0.7, fill_color=BLUE)\n                self.add(cube)\n    \"\"\"\n\n    def __init__(\n        self,\n        side_length: float = 2,\n        fill_opacity: float = 0.75,\n        fill_color: ParsableManimColor = BLUE,\n        stroke_width: float = 0,\n        **kwargs: Any,\n    ) -> None:\n        self.side_length = side_length\n        super().__init__(\n            fill_color=fill_color,\n            fill_opacity=fill_opacity,\n            stroke_width=stroke_width,\n            **kwargs,\n        )\n\n    def generate_points(self) -> None:\n        \"\"\"Creates the sides of the :class:`Cube`.\"\"\"\n        for vect in IN, OUT, LEFT, RIGHT, UP, DOWN:\n            face = Square(\n                side_length=self.side_length,\n                shade_in_3d=True,\n                joint_type=LineJointType.BEVEL,\n            )\n            face.flip()\n            face.shift(self.side_length * OUT / 2.0)\n            face.apply_matrix(z_to_vector(vect))\n\n            self.add(face)\n\n    def init_points(self) -> None:\n        self.generate_points()\n\n\nclass Prism(Cube):\n    \"\"\"A right rectangular prism (or rectangular cuboid).\n    Defined by the length of each side in ``[x, y, z]`` format.\n\n    Parameters\n    ----------\n    dimensions\n        Dimensions of the :class:`Prism` in ``[x, y, z]`` format.\n\n    Examples\n    --------\n\n    .. manim:: ExamplePrism\n        :save_last_frame:\n\n        class ExamplePrism(ThreeDScene):\n            def construct(self):\n                self.set_camera_orientation(phi=60 * DEGREES, theta=150 * DEGREES)\n                prismSmall = Prism(dimensions=[1, 2, 3]).rotate(PI / 2)\n                prismLarge = Prism(dimensions=[1.5, 3, 4.5]).move_to([2, 0, 0])\n                self.add(prismSmall, prismLarge)\n    \"\"\"\n\n    def __init__(\n        self,\n        dimensions: Vector3DLike = [3, 2, 1],\n        **kwargs: Any,\n    ) -> None:\n        self.dimensions = dimensions\n        super().__init__(**kwargs)\n\n    def generate_points(self) -> None:\n        \"\"\"Creates the sides of the :class:`Prism`.\"\"\"\n        super().generate_points()\n        for dim, value in enumerate(self.dimensions):\n            self.rescale_to_fit(value, dim, stretch=True)\n\n\nclass Cone(Surface):\n    \"\"\"A circular cone.\n    Can be defined using 2 parameters: its height, and its base radius.\n    The polar angle, theta, can be calculated using arctan(base_radius /\n    height) The spherical radius, r, is calculated using the pythagorean\n    theorem.\n\n    Parameters\n    ----------\n    base_radius\n        The base radius from which the cone tapers.\n    height\n        The height measured from the plane formed by the base_radius to\n        the apex of the cone.\n    direction\n        The direction of the apex.\n    show_base\n        Whether to show the base plane or not.\n    v_range\n        The azimuthal angle to start and end at.\n    u_min\n        The radius at the apex.\n    checkerboard_colors\n        Show checkerboard grid texture on the cone.\n\n    Examples\n    --------\n    .. manim:: ExampleCone\n        :save_last_frame:\n\n        class ExampleCone(ThreeDScene):\n            def construct(self):\n                axes = ThreeDAxes()\n                cone = Cone(direction=X_AXIS+Y_AXIS+2*Z_AXIS, resolution=8)\n                self.set_camera_orientation(phi=5*PI/11, theta=PI/9)\n                self.add(axes, cone)\n    \"\"\"\n\n    def __init__(\n        self,\n        base_radius: float = 1,\n        height: float = 1,\n        direction: Vector3DLike = Z_AXIS,\n        show_base: bool = False,\n        v_range: tuple[float, float] = (0, TAU),\n        u_min: float = 0,\n        checkerboard_colors: Iterable[ParsableManimColor] | Literal[False] = False,\n        **kwargs: Any,\n    ) -> None:\n        self.direction = np.array(direction)\n        self.theta = PI - np.arctan(base_radius / height)\n\n        super().__init__(\n            self.func,\n            v_range=v_range,\n            u_range=(u_min, np.sqrt(base_radius**2 + height**2)),\n            checkerboard_colors=checkerboard_colors,\n            **kwargs,\n        )\n        # used for rotations\n        self.new_height = height\n        self._current_theta = 0\n        self._current_phi = 0\n        self.base_circle = Circle(\n            radius=base_radius,\n            color=self.fill_color,\n            fill_opacity=self.fill_opacity,\n            stroke_width=0,\n        )\n        self.base_circle.shift(height * IN)\n        self._set_start_and_end_attributes(direction)\n        if show_base:\n            self.add(self.base_circle)\n\n        self._rotate_to_direction()\n\n    def func(self, u: float, v: float) -> Point3D:\n        \"\"\"Converts from spherical coordinates to cartesian.\n\n        Parameters\n        ----------\n        u\n            The radius.\n        v\n            The azimuthal angle.\n\n        Returns\n        -------\n        :class:`numpy.array`\n            Points defining the :class:`Cone`.\n        \"\"\"\n        r = u\n        phi = v\n        return np.array(\n            [\n                r * np.sin(self.theta) * np.cos(phi),\n                r * np.sin(self.theta) * np.sin(phi),\n                r * np.cos(self.theta),\n            ],\n        )\n\n    def get_start(self) -> Point3D:\n        return self.start_point.get_center()\n\n    def get_end(self) -> Point3D:\n        return self.end_point.get_center()\n\n    def _rotate_to_direction(self) -> None:\n        x, y, z = self.direction\n\n        r = np.sqrt(x**2 + y**2 + z**2)\n        theta = np.arccos(z / r) if r > 0 else 0\n\n        if x == 0:\n            if y == 0:  # along the z axis\n                phi = 0\n            else:\n                phi = np.arctan(np.inf)\n                if y < 0:\n                    phi += PI\n        else:\n            phi = np.arctan(y / x)\n        if x < 0:\n            phi += PI\n\n        # Undo old rotation (in reverse order)\n        self.rotate(-self._current_phi, Z_AXIS, about_point=ORIGIN)\n        self.rotate(-self._current_theta, Y_AXIS, about_point=ORIGIN)\n\n        # Do new rotation\n        self.rotate(theta, Y_AXIS, about_point=ORIGIN)\n        self.rotate(phi, Z_AXIS, about_point=ORIGIN)\n\n        # Store values\n        self._current_theta = theta\n        self._current_phi = phi\n\n    def set_direction(self, direction: Vector3DLike) -> None:\n        \"\"\"Changes the direction of the apex of the :class:`Cone`.\n\n        Parameters\n        ----------\n        direction\n            The direction of the apex.\n        \"\"\"\n        self.direction = np.array(direction)\n        self._rotate_to_direction()\n\n    def get_direction(self) -> Vector3D:\n        \"\"\"Returns the current direction of the apex of the :class:`Cone`.\n\n        Returns\n        -------\n        direction : :class:`numpy.array`\n            The direction of the apex.\n        \"\"\"\n        return self.direction\n\n    def _set_start_and_end_attributes(self, direction: Vector3D) -> None:\n        normalized_direction = direction * np.linalg.norm(direction)\n\n        start = self.base_circle.get_center()\n        end = start + normalized_direction * self.new_height\n        self.start_point = VectorizedPoint(start)\n        self.end_point = VectorizedPoint(end)\n        self.add(self.start_point, self.end_point)\n\n\nclass Cylinder(Surface):\n    \"\"\"A cylinder, defined by its height, radius and direction,\n\n    Parameters\n    ----------\n    radius\n        The radius of the cylinder.\n    height\n        The height of the cylinder.\n    direction\n        The direction of the central axis of the cylinder.\n    v_range\n        The height along the height axis (given by direction) to start and end on.\n    show_ends\n        Whether to show the end caps or not.\n    resolution\n        The number of samples taken of the :class:`Cylinder`. A tuple can be used\n        to define different resolutions for ``u`` and ``v`` respectively.\n\n    Examples\n    --------\n    .. manim:: ExampleCylinder\n        :save_last_frame:\n\n        class ExampleCylinder(ThreeDScene):\n            def construct(self):\n                axes = ThreeDAxes()\n                cylinder = Cylinder(radius=2, height=3)\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                self.add(axes, cylinder)\n    \"\"\"\n\n    def __init__(\n        self,\n        radius: float = 1,\n        height: float = 2,\n        direction: Vector3DLike = Z_AXIS,\n        v_range: tuple[float, float] = (0, TAU),\n        show_ends: bool = True,\n        resolution: int | tuple[int, int] = (24, 24),\n        **kwargs: Any,\n    ) -> None:\n        self._height = height\n        self.radius = radius\n        super().__init__(\n            self.func,\n            resolution=resolution,\n            u_range=(-self._height / 2, self._height / 2),\n            v_range=v_range,\n            **kwargs,\n        )\n        if show_ends:\n            self.add_bases()\n        self._current_phi = 0\n        self._current_theta = 0\n        self.set_direction(direction)\n\n    def func(self, u: float, v: float) -> np.ndarray:\n        \"\"\"Converts from cylindrical coordinates to cartesian.\n\n        Parameters\n        ----------\n        u\n            The height.\n        v\n            The azimuthal angle.\n\n        Returns\n        -------\n        :class:`numpy.ndarray`\n            Points defining the :class:`Cylinder`.\n        \"\"\"\n        height = u\n        phi = v\n        r = self.radius\n        return np.array([r * np.cos(phi), r * np.sin(phi), height])\n\n    def add_bases(self) -> None:\n        \"\"\"Adds the end caps of the cylinder.\"\"\"\n        opacity: float\n        if config.renderer == RendererType.OPENGL:\n            assert isinstance(self, OpenGLMobject)\n            color = self.color\n            opacity = self.opacity\n        elif config.renderer == RendererType.CAIRO:\n            color = self.fill_color\n            opacity = self.fill_opacity\n\n        self.base_top = Circle(\n            radius=self.radius,\n            color=color,\n            fill_opacity=opacity,\n            shade_in_3d=True,\n            stroke_width=0,\n        )\n        self.base_top.shift(self.u_range[1] * IN)\n        self.base_bottom = Circle(\n            radius=self.radius,\n            color=color,\n            fill_opacity=opacity,\n            shade_in_3d=True,\n            stroke_width=0,\n        )\n        self.base_bottom.shift(self.u_range[0] * IN)\n        self.add(self.base_top, self.base_bottom)\n\n    def _rotate_to_direction(self) -> None:\n        x, y, z = self.direction\n\n        r = np.sqrt(x**2 + y**2 + z**2)\n        theta = np.arccos(z / r) if r > 0 else 0\n\n        if x == 0:\n            if y == 0:  # along the z axis\n                phi = 0\n            else:  # along the x axis\n                phi = np.arctan(np.inf)\n                if y < 0:\n                    phi += PI\n        else:\n            phi = np.arctan(y / x)\n        if x < 0:\n            phi += PI\n\n        # undo old rotation (in reverse direction)\n        self.rotate(-self._current_phi, Z_AXIS, about_point=ORIGIN)\n        self.rotate(-self._current_theta, Y_AXIS, about_point=ORIGIN)\n\n        # do new rotation\n        self.rotate(theta, Y_AXIS, about_point=ORIGIN)\n        self.rotate(phi, Z_AXIS, about_point=ORIGIN)\n\n        # store new values\n        self._current_theta = theta\n        self._current_phi = phi\n\n    def set_direction(self, direction: Vector3DLike) -> None:\n        \"\"\"Sets the direction of the central axis of the :class:`Cylinder`.\n\n        Parameters\n        ----------\n        direction : :class:`numpy.array`\n            The direction of the central axis of the :class:`Cylinder`.\n        \"\"\"\n        # if get_norm(direction) is get_norm(self.direction):\n        #     pass\n        self.direction = direction\n        self._rotate_to_direction()\n\n    def get_direction(self) -> np.ndarray:\n        \"\"\"Returns the direction of the central axis of the :class:`Cylinder`.\n\n        Returns\n        -------\n        direction : :class:`numpy.array`\n            The direction of the central axis of the :class:`Cylinder`.\n        \"\"\"\n        return self.direction\n\n\nclass Line3D(Cylinder):\n    \"\"\"A cylindrical line, for use in ThreeDScene.\n\n    Parameters\n    ----------\n    start\n        The start point of the line.\n    end\n        The end point of the line.\n    thickness\n        The thickness of the line.\n    color\n        The color of the line.\n    resolution\n        The resolution of the line.\n        By default this value is the number of points the line will sampled at.\n        If you want the line to also come out checkered, use a tuple.\n        For example, for a line made of 24 points with 4 checker points on each\n        cylinder, pass the tuple (4, 24).\n\n    Examples\n    --------\n    .. manim:: ExampleLine3D\n        :save_last_frame:\n\n        class ExampleLine3D(ThreeDScene):\n            def construct(self):\n                axes = ThreeDAxes()\n                line = Line3D(start=np.array([0, 0, 0]), end=np.array([2, 2, 2]))\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                self.add(axes, line)\n    \"\"\"\n\n    def __init__(\n        self,\n        start: Point3DLike = LEFT,\n        end: Point3DLike = RIGHT,\n        thickness: float = 0.02,\n        color: ParsableManimColor | None = None,\n        resolution: int | tuple[int, int] = 24,\n        **kwargs: Any,\n    ):\n        self.thickness = thickness\n        self.resolution: tuple[int, int] = (\n            (2, resolution) if isinstance(resolution, int) else resolution\n        )\n\n        start = np.array(start, dtype=np.float64)\n        end = np.array(end, dtype=np.float64)\n\n        self.set_start_and_end_attrs(start, end, **kwargs)\n        if color is not None:\n            self.set_color(color)\n\n    def set_start_and_end_attrs(\n        self, start: Point3DLike, end: Point3DLike, **kwargs: Any\n    ) -> None:\n        \"\"\"Sets the start and end points of the line.\n\n        If either ``start`` or ``end`` are :class:`Mobjects <.Mobject>`,\n        this gives their centers.\n\n        Parameters\n        ----------\n        start\n            Starting point or :class:`Mobject`.\n        end\n            Ending point or :class:`Mobject`.\n        \"\"\"\n        rough_start = self.pointify(start)\n        rough_end = self.pointify(end)\n        self.vect = rough_end - rough_start\n        self.length = np.linalg.norm(self.vect)\n        self.direction: Vector3D = normalize(self.vect)\n        # Now that we know the direction between them,\n        # we can the appropriate boundary point from\n        # start and end, if they're mobjects\n        self.start = self.pointify(start, self.direction)\n        self.end = self.pointify(end, -self.direction)\n        super().__init__(\n            height=np.linalg.norm(self.vect),\n            radius=self.thickness,\n            direction=self.direction,\n            resolution=self.resolution,\n            **kwargs,\n        )\n        self.shift((self.start + self.end) / 2)\n\n    def pointify(\n        self,\n        mob_or_point: Mobject | Point3DLike,\n        direction: Vector3DLike | None = None,\n    ) -> Point3D:\n        \"\"\"Gets a point representing the center of the :class:`Mobjects <.Mobject>`.\n\n        Parameters\n        ----------\n        mob_or_point\n            :class:`Mobjects <.Mobject>` or point whose center should be returned.\n        direction\n            If an edge of a :class:`Mobjects <.Mobject>` should be returned, the direction of the edge.\n\n        Returns\n        -------\n        :class:`numpy.array`\n            Center of the :class:`Mobjects <.Mobject>` or point, or edge if direction is given.\n        \"\"\"\n        if isinstance(mob_or_point, (Mobject, OpenGLMobject)):\n            mob = mob_or_point\n            if direction is None:\n                return mob.get_center()\n            else:\n                return mob.get_boundary_point(direction)\n        return np.array(mob_or_point)\n\n    def get_start(self) -> Point3D:\n        \"\"\"Returns the starting point of the :class:`Line3D`.\n\n        Returns\n        -------\n        start : :class:`numpy.array`\n            Starting point of the :class:`Line3D`.\n        \"\"\"\n        return self.start\n\n    def get_end(self) -> Point3D:\n        \"\"\"Returns the ending point of the :class:`Line3D`.\n\n        Returns\n        -------\n        end : :class:`numpy.array`\n            Ending point of the :class:`Line3D`.\n        \"\"\"\n        return self.end\n\n    @classmethod\n    def parallel_to(\n        cls,\n        line: Line3D,\n        point: Point3DLike = ORIGIN,\n        length: float = 5,\n        **kwargs: Any,\n    ) -> Line3D:\n        \"\"\"Returns a line parallel to another line going through\n        a given point.\n\n        Parameters\n        ----------\n        line\n            The line to be parallel to.\n        point\n            The point to pass through.\n        length\n            Length of the parallel line.\n        kwargs\n            Additional parameters to be passed to the class.\n\n        Returns\n        -------\n        :class:`Line3D`\n            Line parallel to ``line``.\n\n        Examples\n        --------\n        .. manim:: ParallelLineExample\n            :save_last_frame:\n\n            class ParallelLineExample(ThreeDScene):\n                def construct(self):\n                    self.set_camera_orientation(PI / 3, -PI / 4)\n                    ax = ThreeDAxes((-5, 5), (-5, 5), (-5, 5), 10, 10, 10)\n                    line1 = Line3D(RIGHT * 2, UP + OUT, color=RED)\n                    line2 = Line3D.parallel_to(line1, color=YELLOW)\n                    self.add(ax, line1, line2)\n        \"\"\"\n        np_point = np.asarray(point)\n        vect = normalize(line.vect)\n        return cls(\n            np_point + vect * length / 2,\n            np_point - vect * length / 2,\n            **kwargs,\n        )\n\n    @classmethod\n    def perpendicular_to(\n        cls,\n        line: Line3D,\n        point: Point3DLike = ORIGIN,\n        length: float = 5,\n        **kwargs: Any,\n    ) -> Line3D:\n        \"\"\"Returns a line perpendicular to another line going through\n        a given point.\n\n        Parameters\n        ----------\n        line\n            The line to be perpendicular to.\n        point\n            The point to pass through.\n        length\n            Length of the perpendicular line.\n        kwargs\n            Additional parameters to be passed to the class.\n\n        Returns\n        -------\n        :class:`Line3D`\n            Line perpendicular to ``line``.\n\n        Examples\n        --------\n        .. manim:: PerpLineExample\n            :save_last_frame:\n\n            class PerpLineExample(ThreeDScene):\n                def construct(self):\n                    self.set_camera_orientation(PI / 3, -PI / 4)\n                    ax = ThreeDAxes((-5, 5), (-5, 5), (-5, 5), 10, 10, 10)\n                    line1 = Line3D(RIGHT * 2, UP + OUT, color=RED)\n                    line2 = Line3D.perpendicular_to(line1, color=BLUE)\n                    self.add(ax, line1, line2)\n        \"\"\"\n        np_point = np.asarray(point)\n\n        norm = np.cross(line.vect, np_point - line.start)\n        if all(np.linalg.norm(norm) == np.zeros(3)):\n            raise ValueError(\"Could not find the perpendicular.\")\n\n        start, end = perpendicular_bisector([line.start, line.end], norm)\n        vect = normalize(end - start)\n        return cls(\n            np_point + vect * length / 2,\n            np_point - vect * length / 2,\n            **kwargs,\n        )\n\n\nclass Arrow3D(Line3D):\n    \"\"\"An arrow made out of a cylindrical line and a conical tip.\n\n    Parameters\n    ----------\n    start\n        The start position of the arrow.\n    end\n        The end position of the arrow.\n    thickness\n        The thickness of the arrow.\n    height\n        The height of the conical tip.\n    base_radius\n        The base radius of the conical tip.\n    color\n        The color of the arrow.\n    resolution\n        The resolution of the arrow line.\n\n    Examples\n    --------\n    .. manim:: ExampleArrow3D\n        :save_last_frame:\n\n        class ExampleArrow3D(ThreeDScene):\n            def construct(self):\n                axes = ThreeDAxes()\n                arrow = Arrow3D(\n                    start=np.array([0, 0, 0]),\n                    end=np.array([2, 2, 2]),\n                    resolution=8\n                )\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                self.add(axes, arrow)\n    \"\"\"\n\n    def __init__(\n        self,\n        start: Point3DLike = LEFT,\n        end: Point3DLike = RIGHT,\n        thickness: float = 0.02,\n        height: float = 0.3,\n        base_radius: float = 0.08,\n        color: ParsableManimColor = WHITE,\n        resolution: int | tuple[int, int] = 24,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(\n            start=start,\n            end=end,\n            thickness=thickness,\n            color=color,\n            resolution=resolution,\n            **kwargs,\n        )\n\n        self.length = np.linalg.norm(self.vect)\n        self.set_start_and_end_attrs(\n            self.start,\n            self.end - height * self.direction,\n            **kwargs,\n        )\n        self.cone = Cone(\n            direction=self.direction,\n            base_radius=base_radius,\n            height=height,\n            **kwargs,\n        )\n        np_end = np.asarray(end, dtype=np.float64)\n        self.cone.shift(np_end)\n        self.end_point = VectorizedPoint(np_end)\n        self.add(self.end_point, self.cone)\n        self.set_color(color)\n\n    def get_end(self) -> np.ndarray:\n        return self.end_point.get_center()\n\n\nclass Torus(Surface):\n    \"\"\"A torus.\n\n    Parameters\n    ----------\n    major_radius\n        Distance from the center of the tube to the center of the torus.\n    minor_radius\n        Radius of the tube.\n    u_range\n        The range of the ``u`` variable: ``(u_min, u_max)``.\n    v_range\n        The range of the ``v`` variable: ``(v_min, v_max)``.\n    resolution\n        The number of samples taken of the :class:`Torus`. A tuple can be\n        used to define different resolutions for ``u`` and ``v`` respectively.\n\n    Examples\n    --------\n    .. manim :: ExampleTorus\n        :save_last_frame:\n\n        class ExampleTorus(ThreeDScene):\n            def construct(self):\n                axes = ThreeDAxes()\n                torus = Torus()\n                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n                self.add(axes, torus)\n    \"\"\"\n\n    def __init__(\n        self,\n        major_radius: float = 3,\n        minor_radius: float = 1,\n        u_range: tuple[float, float] = (0, TAU),\n        v_range: tuple[float, float] = (0, TAU),\n        resolution: int | tuple[int, int] | None = None,\n        **kwargs: Any,\n    ) -> None:\n        if config.renderer == RendererType.OPENGL:\n            res_value = (101, 101)\n        elif config.renderer == RendererType.CAIRO:\n            res_value = (24, 24)\n\n        resolution = resolution if resolution is not None else res_value\n\n        self.R = major_radius\n        self.r = minor_radius\n        super().__init__(\n            self.func,\n            u_range=u_range,\n            v_range=v_range,\n            resolution=resolution,\n            **kwargs,\n        )\n\n    def func(self, u: float, v: float) -> Point3D:\n        \"\"\"The z values defining the :class:`Torus` being plotted.\n\n        Returns\n        -------\n        :class:`numpy.ndarray`\n            The z values defining the :class:`Torus`.\n        \"\"\"\n        P = np.array([np.cos(u), np.sin(u), 0])\n        return (self.R - self.r * np.cos(v)) * P - self.r * np.sin(v) * OUT\n"
  },
  {
    "path": "manim/mobject/types/__init__.py",
    "content": "\"\"\"Specialized mobject base classes.\n\nModules\n=======\n\n.. autosummary::\n    :toctree: ../reference\n\n    ~image_mobject\n    ~point_cloud_mobject\n    ~vectorized_mobject\n\"\"\"\n"
  },
  {
    "path": "manim/mobject/types/image_mobject.py",
    "content": "\"\"\"Mobjects representing raster images.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"AbstractImageMobject\", \"ImageMobject\", \"ImageMobjectFromCamera\"]\n\nimport pathlib\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\nfrom PIL import Image\nfrom PIL.Image import Resampling\n\nfrom manim.mobject.geometry.shape_matchers import SurroundingRectangle\n\nfrom ... import config\nfrom ...camera.moving_camera import MovingCamera\nfrom ...constants import *\nfrom ...mobject.mobject import Mobject\nfrom ...utils.bezier import interpolate\nfrom ...utils.color import (\n    WHITE,\n    YELLOW_C,\n    ManimColor,\n    ParsableManimColor,\n    color_to_int_rgb,\n)\nfrom ...utils.images import change_to_rgba_array, get_full_raster_image_path\n\n__all__ = [\"ImageMobject\", \"ImageMobjectFromCamera\"]\n\nif TYPE_CHECKING:\n    from typing import Self\n\n    import numpy.typing as npt\n\n    from manim.typing import PixelArray, StrPath\n\n    from ...camera.moving_camera import MovingCamera\n\n\nclass AbstractImageMobject(Mobject):\n    \"\"\"\n    Automatically filters out black pixels\n\n    Parameters\n    ----------\n    scale_to_resolution\n        At this resolution the image is placed pixel by pixel onto the screen, so it\n        will look the sharpest and best.\n        This is a custom parameter of ImageMobject so that rendering a scene with\n        e.g. the ``--quality low`` or ``--quality medium`` flag for faster rendering\n        won't effect the position of the image on the screen.\n    \"\"\"\n\n    def __init__(\n        self,\n        scale_to_resolution: int,\n        pixel_array_dtype: str = \"uint8\",\n        resampling_algorithm: Resampling = Resampling.BICUBIC,\n        **kwargs: Any,\n    ) -> None:\n        self.pixel_array_dtype = pixel_array_dtype\n        self.scale_to_resolution = scale_to_resolution\n        self.set_resampling_algorithm(resampling_algorithm)\n        super().__init__(**kwargs)\n\n    def get_pixel_array(self) -> PixelArray:\n        raise NotImplementedError()\n\n    def set_color(\n        self,\n        color: ParsableManimColor = YELLOW_C,\n        alpha: Any = None,\n        family: bool = True,\n    ) -> AbstractImageMobject:\n        # Likely to be implemented in subclasses, but no obligation\n        raise NotImplementedError()\n\n    def set_resampling_algorithm(self, resampling_algorithm: int) -> Self:\n        \"\"\"\n        Sets the interpolation method for upscaling the image. By default the image is\n        interpolated using bicubic algorithm. This method lets you change it.\n        Interpolation is done internally using Pillow, and the function besides the\n        string constants describing the algorithm accepts the Pillow integer constants.\n\n        Parameters\n        ----------\n        resampling_algorithm\n            An integer constant described in the Pillow library,\n            or one from the RESAMPLING_ALGORITHMS global dictionary,\n            under the following keys:\n\n            * 'bicubic' or 'cubic'\n            * 'nearest' or 'none'\n            * 'box'\n            * 'bilinear' or 'linear'\n            * 'hamming'\n            * 'lanczos' or 'antialias'\n        \"\"\"\n        if resampling_algorithm not in RESAMPLING_ALGORITHMS.values():\n            raise ValueError(\n                \"resampling_algorithm has to be an int, one of the values defined in \"\n                \"RESAMPLING_ALGORITHMS or a Pillow resampling filter constant. \"\n                \"Available algorithms: 'bicubic' (or 'cubic'), 'nearest' (or 'none'), \"\n                \"'bilinear' (or 'linear').\",\n            )\n\n        self.resampling_algorithm = resampling_algorithm\n        return self\n\n    def reset_points(self) -> Self:\n        \"\"\"Sets :attr:`points` to be the four image corners.\"\"\"\n        self.points = np.array(\n            [\n                UP + LEFT,\n                UP + RIGHT,\n                DOWN + LEFT,\n                DOWN + RIGHT,\n            ],\n        )\n        self.center()\n        h, w = self.get_pixel_array().shape[:2]\n        if self.scale_to_resolution:\n            height = h / self.scale_to_resolution * config[\"frame_height\"]\n        else:\n            height = 3  # this is the case for ImageMobjectFromCamera\n        self.stretch_to_fit_height(height)\n        self.stretch_to_fit_width(height * w / h)\n        return self\n\n\nclass ImageMobject(AbstractImageMobject):\n    \"\"\"Displays an Image from a numpy array or a file.\n\n    Parameters\n    ----------\n    scale_to_resolution\n        At this resolution the image is placed pixel by pixel onto the screen, so it\n        will look the sharpest and best.\n        This is a custom parameter of ImageMobject so that rendering a scene with\n        e.g. the ``--quality low`` or ``--quality medium`` flag for faster rendering\n        won't effect the position of the image on the screen.\n\n\n    Example\n    -------\n    .. manim:: ImageFromArray\n        :save_last_frame:\n\n        class ImageFromArray(Scene):\n            def construct(self):\n                image = ImageMobject(np.uint8([[0, 100, 30, 200],\n                                               [255, 0, 5, 33]]))\n                image.height = 7\n                self.add(image)\n\n\n    Changing interpolation style:\n\n    .. manim:: ImageInterpolationEx\n        :save_last_frame:\n\n        class ImageInterpolationEx(Scene):\n            def construct(self):\n                img = ImageMobject(np.uint8([[63, 0, 0, 0],\n                                                [0, 127, 0, 0],\n                                                [0, 0, 191, 0],\n                                                [0, 0, 0, 255]\n                                                ]))\n\n                img.height = 3\n\n                group = Group()\n                algorithm_texts = [\"nearest\", \"linear\", \"cubic\"]\n                for algorithm_text in algorithm_texts:\n                    algorithm = RESAMPLING_ALGORITHMS[algorithm_text]\n                    img_copy = img.copy().set_resampling_algorithm(algorithm)\n                    img_copy.add(Text(algorithm_text).scale(0.5).next_to(img_copy, UP))\n                    group.add(img_copy)\n\n                group.arrange()\n                self.add(group)\n    \"\"\"\n\n    def __init__(\n        self,\n        filename_or_array: StrPath | npt.NDArray,\n        scale_to_resolution: int = QUALITIES[DEFAULT_QUALITY][\"pixel_height\"],\n        invert: bool = False,\n        image_mode: str = \"RGBA\",\n        **kwargs: Any,\n    ) -> None:\n        self.fill_opacity: float = 1\n        self.stroke_opacity: float = 1\n        self.invert_image = invert\n        self.image_mode = image_mode\n        if isinstance(filename_or_array, (str, pathlib.PurePath)):\n            path = get_full_raster_image_path(filename_or_array)\n            image = Image.open(path).convert(self.image_mode)\n            self.pixel_array = np.array(image)\n            self.path = path\n        else:\n            self.pixel_array = np.array(filename_or_array)\n        self.pixel_array_dtype = kwargs.get(\"pixel_array_dtype\", \"uint8\")\n        self.pixel_array = change_to_rgba_array(\n            self.pixel_array, self.pixel_array_dtype\n        )\n        if self.invert_image:\n            self.pixel_array[:, :, :3] = (\n                np.iinfo(self.pixel_array_dtype).max - self.pixel_array[:, :, :3]\n            )\n        self.orig_alpha_pixel_array = self.pixel_array[:, :, 3].copy()\n        super().__init__(scale_to_resolution, **kwargs)\n\n    def get_pixel_array(self) -> PixelArray:\n        \"\"\"A simple getter method.\"\"\"\n        return self.pixel_array\n\n    def set_color(\n        self,\n        color: ParsableManimColor = YELLOW_C,\n        alpha: Any = None,\n        family: bool = True,\n    ) -> Self:\n        rgb = color_to_int_rgb(color)\n        self.pixel_array[:, :, :3] = rgb\n        if alpha is not None:\n            self.pixel_array[:, :, 3] = int(255 * alpha)\n        for submob in self.submobjects:\n            submob.set_color(color, alpha, family)\n        self.color = ManimColor(color)\n        return self\n\n    def set_opacity(self, alpha: float) -> Self:\n        \"\"\"Sets the image's opacity.\n\n        Parameters\n        ----------\n        alpha\n            The alpha value of the object, 1 being opaque and 0 being\n            transparent.\n        \"\"\"\n        self.pixel_array[:, :, 3] = self.orig_alpha_pixel_array * alpha\n        self.stroke_opacity = alpha\n        return self\n\n    def fade(self, darkness: float = 0.5, family: bool = True) -> Self:\n        \"\"\"Sets the image's opacity using a 1 - alpha relationship.\n\n        Parameters\n        ----------\n        darkness\n            The alpha value of the object, 1 being transparent and 0 being\n            opaque.\n        family\n            Whether the submobjects of the ImageMobject should be affected.\n        \"\"\"\n        self.set_opacity(1 - darkness)\n        super().fade(darkness, family)\n        return self\n\n    def interpolate_color(\n        self, mobject1: Mobject, mobject2: Mobject, alpha: float\n    ) -> None:\n        \"\"\"Interpolates the array of pixel color values from one ImageMobject\n        into an array of equal size in the target ImageMobject.\n\n        Parameters\n        ----------\n        mobject1\n            The ImageMobject to transform from.\n\n        mobject2\n            The ImageMobject to transform into.\n\n        alpha\n            Used to track the lerp relationship. Not opacity related.\n        \"\"\"\n        assert isinstance(mobject1, ImageMobject)\n        assert isinstance(mobject2, ImageMobject)\n        assert mobject1.pixel_array.shape == mobject2.pixel_array.shape, (\n            f\"Mobject pixel array shapes incompatible for interpolation.\\n\"\n            f\"Mobject 1 ({mobject1}) : {mobject1.pixel_array.shape}\\n\"\n            f\"Mobject 2 ({mobject2}) : {mobject2.pixel_array.shape}\"\n        )\n        self.fill_opacity = interpolate(\n            mobject1.fill_opacity,\n            mobject2.fill_opacity,\n            alpha,\n        )\n        self.stroke_opacity = interpolate(\n            mobject1.stroke_opacity,\n            mobject2.stroke_opacity,\n            alpha,\n        )\n        self.pixel_array = interpolate(\n            mobject1.pixel_array,\n            mobject2.pixel_array,\n            alpha,\n        ).astype(self.pixel_array_dtype)\n\n    def get_style(self) -> dict[str, Any]:\n        return {\n            \"fill_color\": ManimColor(self.color.to_rgb()).to_hex(),\n            \"fill_opacity\": self.fill_opacity,\n        }\n\n\n# TODO, add the ability to have the dimensions/orientation of this\n# mobject more strongly tied to the frame of the camera it contains,\n# in the case where that's a MovingCamera\n\n\nclass ImageMobjectFromCamera(AbstractImageMobject):\n    def __init__(\n        self,\n        camera: MovingCamera,\n        default_display_frame_config: dict[str, Any] | None = None,\n        **kwargs: Any,\n    ) -> None:\n        self.camera = camera\n        if default_display_frame_config is None:\n            default_display_frame_config = {\n                \"stroke_width\": 3,\n                \"stroke_color\": WHITE,\n                \"buff\": 0,\n            }\n        self.default_display_frame_config = default_display_frame_config\n        self.pixel_array = self.camera.pixel_array\n        super().__init__(scale_to_resolution=False, **kwargs)\n\n    # TODO: Get rid of this.\n    def get_pixel_array(self) -> PixelArray:\n        self.pixel_array = self.camera.pixel_array\n        return self.pixel_array\n\n    def add_display_frame(self, **kwargs: Any) -> Self:\n        config = dict(self.default_display_frame_config)\n        config.update(kwargs)\n        self.display_frame = SurroundingRectangle(self, **config)\n        self.add(self.display_frame)\n        return self\n\n    def interpolate_color(\n        self, mobject1: Mobject, mobject2: Mobject, alpha: float\n    ) -> None:\n        assert isinstance(mobject1, ImageMobjectFromCamera)\n        assert isinstance(mobject2, ImageMobjectFromCamera)\n        assert mobject1.pixel_array.shape == mobject2.pixel_array.shape, (\n            f\"Mobject pixel array shapes incompatible for interpolation.\\n\"\n            f\"Mobject 1 ({mobject1}) : {mobject1.pixel_array.shape}\\n\"\n            f\"Mobject 2 ({mobject2}) : {mobject2.pixel_array.shape}\"\n        )\n        self.pixel_array = interpolate(\n            mobject1.pixel_array,\n            mobject2.pixel_array,\n            alpha,\n        ).astype(self.pixel_array_dtype)\n"
  },
  {
    "path": "manim/mobject/types/point_cloud_mobject.py",
    "content": "\"\"\"Mobjects representing point clouds.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"PMobject\", \"Mobject1D\", \"Mobject2D\", \"PGroup\", \"PointCloudDot\", \"Point\"]\n\nfrom collections.abc import Callable\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.opengl.opengl_point_cloud_mobject import OpenGLPMobject\n\nfrom ...constants import *\nfrom ...mobject.mobject import Mobject\nfrom ...utils.bezier import interpolate\nfrom ...utils.color import (\n    BLACK,\n    PURE_YELLOW,\n    WHITE,\n    ManimColor,\n    ParsableManimColor,\n    color_gradient,\n    color_to_rgba,\n    rgba_to_color,\n)\nfrom ...utils.iterables import stretch_array_to_length\n\n__all__ = [\"PMobject\", \"Mobject1D\", \"Mobject2D\", \"PGroup\", \"PointCloudDot\", \"Point\"]\n\nif TYPE_CHECKING:\n    from typing import Self\n\n    import numpy.typing as npt\n\n    from manim.typing import (\n        FloatRGBA_Array,\n        FloatRGBALike_Array,\n        ManimFloat,\n        Point3D_Array,\n        Point3DLike,\n        Point3DLike_Array,\n    )\n\n\nclass PMobject(Mobject, metaclass=ConvertToOpenGL):\n    \"\"\"A disc made of a cloud of Dots\n\n    Examples\n    --------\n\n    .. manim:: PMobjectExample\n        :save_last_frame:\n\n        class PMobjectExample(Scene):\n            def construct(self):\n\n                pG = PGroup()  # This is just a collection of PMobject's\n\n                # As the scale factor increases, the number of points\n                # removed increases.\n                for sf in range(1, 9 + 1):\n                    p = PointCloudDot(density=20, radius=1).thin_out(sf)\n                    # PointCloudDot is a type of PMobject\n                    # and can therefore be added to a PGroup\n                    pG.add(p)\n\n                # This organizes all the shapes in a grid.\n                pG.arrange_in_grid()\n\n                self.add(pG)\n\n    \"\"\"\n\n    def __init__(self, stroke_width: int = DEFAULT_STROKE_WIDTH, **kwargs: Any) -> None:\n        self.stroke_width = stroke_width\n        super().__init__(**kwargs)\n\n    def reset_points(self) -> Self:\n        self.rgbas: FloatRGBA_Array = np.zeros((0, 4))\n        self.points: Point3D_Array = np.zeros((0, 3))\n        return self\n\n    def get_array_attrs(self) -> list[str]:\n        return super().get_array_attrs() + [\"rgbas\"]\n\n    def add_points(\n        self,\n        points: Point3DLike_Array,\n        rgbas: FloatRGBALike_Array | None = None,\n        color: ParsableManimColor | None = None,\n        alpha: float = 1.0,\n    ) -> Self:\n        \"\"\"Add points.\n\n        Points must be a Nx3 numpy array.\n        Rgbas must be a Nx4 numpy array if it is not None.\n        \"\"\"\n        if not isinstance(points, np.ndarray):\n            points = np.array(points)\n        num_new_points = len(points)\n        self.points = np.append(self.points, points, axis=0)\n        if rgbas is None:\n            color = ManimColor(color) if color else self.color\n            rgbas = np.repeat([color_to_rgba(color, alpha)], num_new_points, axis=0)\n        elif len(rgbas) != len(points):\n            raise ValueError(\"points and rgbas must have same length\")\n        self.rgbas = np.append(self.rgbas, rgbas, axis=0)\n        return self\n\n    def set_color(\n        self, color: ParsableManimColor = PURE_YELLOW, family: bool = True\n    ) -> Self:\n        rgba = color_to_rgba(color)\n        mobs = self.family_members_with_points() if family else [self]\n        for mob in mobs:\n            mob.rgbas[:, :] = rgba\n        self.color = ManimColor.parse(color)\n        return self\n\n    def get_stroke_width(self) -> int:\n        return self.stroke_width\n\n    def set_stroke_width(self, width: int, family: bool = True) -> Self:\n        mobs = self.family_members_with_points() if family else [self]\n        for mob in mobs:\n            mob.stroke_width = width\n        return self\n\n    def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self:\n        self.rgbas = np.array(\n            list(map(color_to_rgba, color_gradient(colors, len(self.points)))),\n        )\n        return self\n\n    def set_colors_by_radial_gradient(\n        self,\n        center: Point3DLike | None = None,\n        radius: float = 1,\n        inner_color: ParsableManimColor = WHITE,\n        outer_color: ParsableManimColor = BLACK,\n    ) -> Self:\n        start_rgba, end_rgba = list(map(color_to_rgba, [inner_color, outer_color]))\n        if center is None:\n            center = self.get_center()\n        for mob in self.family_members_with_points():\n            distances = np.abs(self.points - center)\n            alphas = np.linalg.norm(distances, axis=1) / radius\n\n            mob.rgbas = np.array(\n                np.array(\n                    [interpolate(start_rgba, end_rgba, alpha) for alpha in alphas],\n                ),\n            )\n        return self\n\n    def match_colors(self, mobject: Mobject) -> Self:\n        Mobject.align_data(self, mobject)\n        self.rgbas = np.array(mobject.rgbas)\n        return self\n\n    def filter_out(self, condition: npt.NDArray) -> Self:\n        for mob in self.family_members_with_points():\n            to_eliminate = ~np.apply_along_axis(condition, 1, mob.points)\n            mob.points = mob.points[to_eliminate]\n            mob.rgbas = mob.rgbas[to_eliminate]\n        return self\n\n    def thin_out(self, factor: int = 5) -> Self:\n        \"\"\"Removes all but every nth point for n = factor\"\"\"\n        for mob in self.family_members_with_points():\n            num_points = self.get_num_points()\n            mob.apply_over_attr_arrays(\n                lambda arr, n=num_points: arr[np.arange(0, n, factor)],  # type: ignore[misc]\n            )\n        return self\n\n    def sort_points(\n        self, function: Callable[[npt.NDArray[ManimFloat]], float] = lambda p: p[0]\n    ) -> Self:\n        \"\"\"Function is any map from R^3 to R\"\"\"\n        for mob in self.family_members_with_points():\n            indices = np.argsort(np.apply_along_axis(function, 1, mob.points))\n            mob.apply_over_attr_arrays(lambda arr, idx=indices: arr[idx])  # type: ignore[misc]\n        return self\n\n    def fade_to(\n        self, color: ParsableManimColor, alpha: float, family: bool = True\n    ) -> Self:\n        self.rgbas = interpolate(self.rgbas, color_to_rgba(color), alpha)\n        for mob in self.submobjects:\n            mob.fade_to(color, alpha, family)\n        return self\n\n    def get_all_rgbas(self) -> npt.NDArray:\n        return self.get_merged_array(\"rgbas\")\n\n    def ingest_submobjects(self) -> Self:\n        attrs = self.get_array_attrs()\n        arrays = list(map(self.get_merged_array, attrs))\n        for attr, array in zip(attrs, arrays, strict=True):\n            setattr(self, attr, array)\n        self.submobjects = []\n        return self\n\n    def get_color(self) -> ManimColor:\n        return rgba_to_color(self.rgbas[0, :])\n\n    def point_from_proportion(self, alpha: float) -> Any:\n        index = alpha * (self.get_num_points() - 1)\n        return self.points[np.floor(index)]\n\n    @staticmethod\n    def get_mobject_type_class() -> type[PMobject]:\n        return PMobject\n\n    # Alignment\n    def align_points_with_larger(self, larger_mobject: Mobject) -> None:\n        assert isinstance(larger_mobject, PMobject)\n        self.apply_over_attr_arrays(\n            lambda a: stretch_array_to_length(a, larger_mobject.get_num_points()),\n        )\n\n    def get_point_mobject(self, center: Point3DLike | None = None) -> Point:\n        if center is None:\n            center = self.get_center()\n        return Point(center)\n\n    def interpolate_color(\n        self, mobject1: Mobject, mobject2: Mobject, alpha: float\n    ) -> Self:\n        self.rgbas = interpolate(mobject1.rgbas, mobject2.rgbas, alpha)\n        self.set_stroke_width(\n            interpolate(\n                mobject1.get_stroke_width(),\n                mobject2.get_stroke_width(),\n                alpha,\n            ),\n        )\n        return self\n\n    def pointwise_become_partial(self, mobject: Mobject, a: float, b: float) -> None:\n        lower_index, upper_index = (int(x * mobject.get_num_points()) for x in (a, b))\n        for attr in self.get_array_attrs():\n            full_array = getattr(mobject, attr)\n            partial_array = full_array[lower_index:upper_index]\n            setattr(self, attr, partial_array)\n\n\n# TODO, Make the two implementations below non-redundant\nclass Mobject1D(PMobject, metaclass=ConvertToOpenGL):\n    def __init__(self, density: int = DEFAULT_POINT_DENSITY_1D, **kwargs: Any) -> None:\n        self.density = density\n        self.epsilon = 1.0 / self.density\n        super().__init__(**kwargs)\n\n    def add_line(\n        self,\n        start: npt.NDArray,\n        end: npt.NDArray,\n        color: ParsableManimColor | None = None,\n    ) -> None:\n        start, end = list(map(np.array, [start, end]))\n        length = np.linalg.norm(end - start)\n        if length == 0:\n            points = np.array([start])\n        else:\n            epsilon = self.epsilon / length\n            points = np.array(\n                [interpolate(start, end, t) for t in np.arange(0, 1, epsilon)]\n            )\n        self.add_points(points, color=color)\n\n\nclass Mobject2D(PMobject, metaclass=ConvertToOpenGL):\n    def __init__(self, density: int = DEFAULT_POINT_DENSITY_2D, **kwargs: Any) -> None:\n        self.density = density\n        self.epsilon = 1.0 / self.density\n        super().__init__(**kwargs)\n\n\nclass PGroup(PMobject):\n    \"\"\"A group for several point mobjects.\n\n    Examples\n    --------\n\n    .. manim:: PgroupExample\n        :save_last_frame:\n\n        class PgroupExample(Scene):\n            def construct(self):\n\n                p1 = PointCloudDot(radius=1, density=20, color=BLUE)\n                p1.move_to(4.5 * LEFT)\n                p2 = PointCloudDot()\n                p3 = PointCloudDot(radius=1.5, stroke_width=2.5, color=PINK)\n                p3.move_to(4.5 * RIGHT)\n                pList = PGroup(p1, p2, p3)\n\n                self.add(pList)\n\n    \"\"\"\n\n    def __init__(self, *pmobs: Any, **kwargs: Any) -> None:\n        if not all(isinstance(m, (PMobject, OpenGLPMobject)) for m in pmobs):\n            raise ValueError(\n                \"All submobjects must be of type PMobject or OpenGLPMObject\"\n                \" if using the opengl renderer\",\n            )\n        super().__init__(**kwargs)\n        self.add(*pmobs)\n\n    def fade_to(\n        self, color: ParsableManimColor, alpha: float, family: bool = True\n    ) -> Self:\n        if family:\n            for mob in self.submobjects:\n                mob.fade_to(color, alpha, family)\n        return self\n\n\nclass PointCloudDot(Mobject1D):\n    \"\"\"A disc made of a cloud of dots.\n\n    Examples\n    --------\n    .. manim:: PointCloudDotExample\n        :save_last_frame:\n\n        class PointCloudDotExample(Scene):\n            def construct(self):\n                cloud_1 = PointCloudDot(color=RED)\n                cloud_2 = PointCloudDot(stroke_width=4, radius=1)\n                cloud_3 = PointCloudDot(density=15)\n\n                group = Group(cloud_1, cloud_2, cloud_3).arrange()\n                self.add(group)\n\n    .. manim:: PointCloudDotExample2\n\n        class PointCloudDotExample2(Scene):\n            def construct(self):\n                plane = ComplexPlane()\n                cloud = PointCloudDot(color=RED)\n                self.add(\n                    plane, cloud\n                )\n                self.wait()\n                self.play(\n                    cloud.animate.apply_complex_function(lambda z: np.exp(z))\n                )\n    \"\"\"\n\n    def __init__(\n        self,\n        center: Point3DLike = ORIGIN,\n        radius: float = 2.0,\n        stroke_width: int = 2,\n        density: int = DEFAULT_POINT_DENSITY_1D,\n        color: ManimColor = PURE_YELLOW,\n        **kwargs: Any,\n    ) -> None:\n        self.radius = radius\n        self.epsilon = 1.0 / density\n        super().__init__(\n            stroke_width=stroke_width, density=density, color=color, **kwargs\n        )\n        self.shift(center)\n\n    def init_points(self) -> None:\n        self.reset_points()\n        self.generate_points()\n\n    def generate_points(self) -> None:\n        self.add_points(\n            np.array(\n                [\n                    r * (np.cos(theta) * RIGHT + np.sin(theta) * UP)\n                    for r in np.arange(self.epsilon, self.radius, self.epsilon)\n                    # Num is equal to int(stop - start)/ (step + 1) reformulated.\n                    for theta in np.linspace(\n                        0,\n                        2 * np.pi,\n                        num=int(2 * np.pi * (r + self.epsilon) / self.epsilon),\n                    )\n                ]\n            ),\n        )\n\n\nclass Point(PMobject):\n    \"\"\"A mobject representing a point.\n\n    Examples\n    --------\n\n    .. manim:: ExamplePoint\n        :save_last_frame:\n\n        class ExamplePoint(Scene):\n            def construct(self):\n                colorList = [RED, GREEN, BLUE, YELLOW]\n                for i in range(200):\n                    point = Point(location=[0.63 * np.random.randint(-4, 4), 0.37 * np.random.randint(-4, 4), 0], color=np.random.choice(colorList))\n                    self.add(point)\n                for i in range(200):\n                    point = Point(location=[0.37 * np.random.randint(-4, 4), 0.63 * np.random.randint(-4, 4), 0], color=np.random.choice(colorList))\n                    self.add(point)\n                self.add(point)\n    \"\"\"\n\n    def __init__(\n        self, location: Point3DLike = ORIGIN, color: ManimColor = BLACK, **kwargs: Any\n    ) -> None:\n        self.location = location\n        super().__init__(color=color, **kwargs)\n\n    def init_points(self) -> None:\n        self.reset_points()\n        self.generate_points()\n        self.set_points([self.location])\n\n    def generate_points(self) -> None:\n        self.add_points(np.array([self.location]))\n"
  },
  {
    "path": "manim/mobject/types/vectorized_mobject.py",
    "content": "\"\"\"Mobjects that use vector graphics.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"VMobject\",\n    \"VGroup\",\n    \"VDict\",\n    \"VectorizedPoint\",\n    \"CurvesAsSubmobjects\",\n    \"DashedVMobject\",\n]\n\nimport itertools as it\nimport sys\nfrom collections.abc import Callable, Hashable, Iterable, Mapping, Sequence\nfrom typing import TYPE_CHECKING, Any, Literal\n\nimport numpy as np\nfrom PIL.Image import Image\n\nfrom manim import config\nfrom manim.constants import *\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject\nfrom manim.mobject.three_d.three_d_utils import (\n    get_3d_vmob_gradient_start_and_end_points,\n)\nfrom manim.utils.bezier import (\n    bezier,\n    bezier_remap,\n    get_smooth_cubic_bezier_handle_points,\n    integer_interpolate,\n    interpolate,\n    partial_bezier_points,\n    proportions_along_bezier_curve_for_point,\n)\nfrom manim.utils.color import BLACK, WHITE, ManimColor, ParsableManimColor\nfrom manim.utils.iterables import (\n    make_even,\n    resize_array,\n    stretch_array_to_length,\n    tuplify,\n)\nfrom manim.utils.space_ops import rotate_vector, shoelace_direction\n\nif TYPE_CHECKING:\n    from collections.abc import Iterator\n    from typing import Self\n\n    import numpy.typing as npt\n\n    from manim.typing import (\n        CubicBezierPath,\n        CubicBezierPointsLike,\n        CubicSpline,\n        FloatRGBA,\n        FloatRGBA_Array,\n        ManimFloat,\n        MappingFunction,\n        Point2DLike,\n        Point3D,\n        Point3D_Array,\n        Point3DLike,\n        Point3DLike_Array,\n        Vector3D,\n        Vector3DLike,\n    )\n\n# TODO\n# - Change cubic curve groups to have 4 points instead of 3\n# - Change sub_path idea accordingly\n# - No more mark_paths_closed, instead have the camera test\n#   if last point in close to first point\n# - Think about length of self.points.  Always 0 or 1 mod 4?\n#   That's kind of weird.\n\n\nclass VMobject(Mobject):\n    \"\"\"A vectorized mobject.\n\n    Parameters\n    ----------\n    background_stroke_color\n        The purpose of background stroke is to have something\n        that won't overlap fill, e.g.  For text against some\n        textured background.\n    sheen_factor\n        When a color c is set, there will be a second color\n        computed based on interpolating c to WHITE by with\n        sheen_factor, and the display will gradient to this\n        secondary color in the direction of sheen_direction.\n    close_new_points\n        Indicates that it will not be displayed, but\n        that it should count in parent mobject's path\n    tolerance_for_point_equality\n        This is within a pixel\n    joint_type\n        The line joint type used to connect the curve segments\n        of this vectorized mobject. See :class:`.LineJointType`\n        for options.\n    \"\"\"\n\n    sheen_factor = 0.0\n    target: VMobject\n\n    def __init__(\n        self,\n        fill_color: ParsableManimColor | None = None,\n        fill_opacity: float = 0.0,\n        stroke_color: ParsableManimColor | None = None,\n        stroke_opacity: float = 1.0,\n        stroke_width: float = DEFAULT_STROKE_WIDTH,\n        background_stroke_color: ParsableManimColor | None = BLACK,\n        background_stroke_opacity: float = 1.0,\n        background_stroke_width: float = 0,\n        sheen_factor: float = 0.0,\n        joint_type: LineJointType | None = None,\n        sheen_direction: Vector3DLike = UL,\n        close_new_points: bool = False,\n        pre_function_handle_to_anchor_scale_factor: float = 0.01,\n        make_smooth_after_applying_functions: bool = False,\n        background_image: Image | str | None = None,\n        shade_in_3d: bool = False,\n        # TODO, do we care about accounting for varying zoom levels?\n        tolerance_for_point_equality: float = 1e-6,\n        n_points_per_cubic_curve: int = 4,\n        cap_style: CapStyleType = CapStyleType.AUTO,\n        **kwargs: Any,\n    ):\n        self.fill_opacity = fill_opacity\n        self.stroke_opacity = stroke_opacity\n        self.stroke_width = stroke_width\n        if background_stroke_color is not None:\n            self.background_stroke_color: ManimColor = ManimColor(\n                background_stroke_color\n            )\n        self.background_stroke_opacity: float = background_stroke_opacity\n        self.background_stroke_width: float = background_stroke_width\n        self.sheen_factor: float = sheen_factor\n        self.joint_type: LineJointType = (\n            LineJointType.AUTO if joint_type is None else joint_type\n        )\n        self.sheen_direction = sheen_direction\n        self.close_new_points: bool = close_new_points\n        self.pre_function_handle_to_anchor_scale_factor: float = (\n            pre_function_handle_to_anchor_scale_factor\n        )\n        self.make_smooth_after_applying_functions: bool = (\n            make_smooth_after_applying_functions\n        )\n        self.background_image: Image | str | None = background_image\n        self.shade_in_3d: bool = shade_in_3d\n        self.tolerance_for_point_equality: float = tolerance_for_point_equality\n        self.n_points_per_cubic_curve: int = n_points_per_cubic_curve\n        self._bezier_t_values: npt.NDArray[float] = np.linspace(\n            0, 1, n_points_per_cubic_curve\n        )\n        self.cap_style: CapStyleType = cap_style\n        super().__init__(**kwargs)\n        self.submobjects: list[VMobject]\n\n        # TODO: Find where color overwrites are happening and remove the color doubling\n        # if \"color\" in kwargs:\n        #     fill_color = kwargs[\"color\"]\n        #     stroke_color = kwargs[\"color\"]\n        if fill_color is not None:\n            self.fill_color = ManimColor.parse(fill_color)\n        if stroke_color is not None:\n            self.stroke_color = ManimColor.parse(stroke_color)\n\n    def _assert_valid_submobjects(self, submobjects: Iterable[VMobject]) -> Self:\n        return self._assert_valid_submobjects_internal(submobjects, VMobject)\n\n    def __iter__(self) -> Iterator[VMobject]:\n        return iter(self.split())\n\n    # OpenGL compatibility\n    @property\n    def n_points_per_curve(self) -> int:\n        return self.n_points_per_cubic_curve\n\n    def get_group_class(self) -> type[VGroup]:\n        return VGroup\n\n    @staticmethod\n    def get_mobject_type_class() -> type[VMobject]:\n        return VMobject\n\n    # Colors\n    def init_colors(self, propagate_colors: bool = True) -> Self:\n        self.set_fill(\n            color=self.fill_color,\n            opacity=self.fill_opacity,\n            family=propagate_colors,\n        )\n        self.set_stroke(\n            color=self.stroke_color,\n            width=self.stroke_width,\n            opacity=self.stroke_opacity,\n            family=propagate_colors,\n        )\n        self.set_background_stroke(\n            color=self.background_stroke_color,\n            width=self.background_stroke_width,\n            opacity=self.background_stroke_opacity,\n            family=propagate_colors,\n        )\n        self.set_sheen(\n            factor=self.sheen_factor,\n            direction=self.sheen_direction,\n            family=propagate_colors,\n        )\n\n        if not propagate_colors:\n            for submobject in self.submobjects:\n                submobject.init_colors(propagate_colors=False)\n\n        return self\n\n    def generate_rgbas_array(\n        self,\n        color: ParsableManimColor | Iterable[ManimColor] | None,\n        opacity: float | Iterable[float],\n    ) -> FloatRGBA:\n        \"\"\"\n        First arg can be either a color, or a tuple/list of colors.\n        Likewise, opacity can either be a float, or a tuple of floats.\n        If self.sheen_factor is not zero, and only\n        one color was passed in, a second slightly light color\n        will automatically be added for the gradient\n        \"\"\"\n        colors: list[ManimColor] = [\n            ManimColor(c) if (c is not None) else BLACK for c in tuplify(color)\n        ]\n        opacities: list[float] = [\n            o if (o is not None) else 0.0 for o in tuplify(opacity)\n        ]\n        rgbas: FloatRGBA_Array = np.array(\n            [\n                c.to_rgba_with_alpha(o)\n                for c, o in zip(*make_even(colors, opacities), strict=True)\n            ],\n        )\n\n        sheen_factor = self.get_sheen_factor()\n        if sheen_factor != 0 and len(rgbas) == 1:\n            light_rgbas = np.array(rgbas)\n            light_rgbas[:, :3] += sheen_factor\n            np.clip(light_rgbas, 0, 1, out=light_rgbas)\n            rgbas = np.append(rgbas, light_rgbas, axis=0)\n        return rgbas\n\n    def update_rgbas_array(\n        self,\n        array_name: str,\n        color: ParsableManimColor | Iterable[ManimColor] | None = None,\n        opacity: float | None = None,\n    ) -> Self:\n        rgbas = self.generate_rgbas_array(color, opacity)\n        if not hasattr(self, array_name):\n            setattr(self, array_name, rgbas)\n            return self\n        # Match up current rgbas array with the newly calculated\n        # one. 99% of the time they'll be the same.\n        curr_rgbas = getattr(self, array_name)\n        if len(curr_rgbas) < len(rgbas):\n            curr_rgbas = stretch_array_to_length(curr_rgbas, len(rgbas))\n            setattr(self, array_name, curr_rgbas)\n        elif len(rgbas) < len(curr_rgbas):\n            rgbas = stretch_array_to_length(rgbas, len(curr_rgbas))\n        # Only update rgb if color was not None, and only\n        # update alpha channel if opacity was passed in\n        if color is not None:\n            curr_rgbas[:, :3] = rgbas[:, :3]\n        if opacity is not None:\n            curr_rgbas[:, 3] = rgbas[:, 3]\n        return self\n\n    def set_fill(\n        self,\n        color: ParsableManimColor | None = None,\n        opacity: float | None = None,\n        family: bool = True,\n    ) -> Self:\n        \"\"\"Set the fill color and fill opacity of a :class:`VMobject`.\n\n        Parameters\n        ----------\n        color\n            Fill color of the :class:`VMobject`.\n        opacity\n            Fill opacity of the :class:`VMobject`.\n        family\n            If ``True``, the fill color of all submobjects is also set.\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n\n        Examples\n        --------\n        .. manim:: SetFill\n            :save_last_frame:\n\n            class SetFill(Scene):\n                def construct(self):\n                    square = Square().scale(2).set_fill(WHITE,1)\n                    circle1 = Circle().set_fill(GREEN,0.8)\n                    circle2 = Circle().set_fill(YELLOW) # No fill_opacity\n                    circle3 = Circle().set_fill(color = '#FF2135', opacity = 0.2)\n                    group = Group(circle1,circle2,circle3).arrange()\n                    self.add(square)\n                    self.add(group)\n\n        See Also\n        --------\n        :meth:`~.VMobject.set_style`\n        \"\"\"\n        if family:\n            for submobject in self.submobjects:\n                submobject.set_fill(color, opacity, family)\n        self.update_rgbas_array(\"fill_rgbas\", color, opacity)\n        self.fill_rgbas: FloatRGBA_Array\n        if opacity is not None:\n            self.fill_opacity = opacity\n        return self\n\n    def set_stroke(\n        self,\n        color: ParsableManimColor = None,\n        width: float | None = None,\n        opacity: float | None = None,\n        background=False,\n        family: bool = True,\n    ) -> Self:\n        if family:\n            for submobject in self.submobjects:\n                submobject.set_stroke(color, width, opacity, background, family)\n        if background:\n            array_name = \"background_stroke_rgbas\"\n            width_name = \"background_stroke_width\"\n            opacity_name = \"background_stroke_opacity\"\n        else:\n            array_name = \"stroke_rgbas\"\n            width_name = \"stroke_width\"\n            opacity_name = \"stroke_opacity\"\n        self.update_rgbas_array(array_name, color, opacity)\n        if width is not None:\n            setattr(self, width_name, width)\n        if opacity is not None:\n            setattr(self, opacity_name, opacity)\n        if color is not None and background:\n            if isinstance(color, (list, tuple)):\n                self.background_stroke_color = ManimColor.parse(color)\n            else:\n                self.background_stroke_color = ManimColor(color)\n        return self\n\n    def set_cap_style(self, cap_style: CapStyleType) -> Self:\n        \"\"\"\n        Sets the cap style of the :class:`VMobject`.\n\n        Parameters\n        ----------\n        cap_style\n            The cap style to be set. See :class:`.CapStyleType` for options.\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n\n        Examples\n        --------\n        .. manim:: CapStyleExample\n            :save_last_frame:\n\n            class CapStyleExample(Scene):\n                def construct(self):\n                    line = Line(LEFT, RIGHT, color=YELLOW, stroke_width=20)\n                    line.set_cap_style(CapStyleType.ROUND)\n                    self.add(line)\n        \"\"\"\n        self.cap_style = cap_style\n        return self\n\n    def set_background_stroke(self, **kwargs) -> Self:\n        kwargs[\"background\"] = True\n        self.set_stroke(**kwargs)\n        return self\n\n    def set_style(\n        self,\n        fill_color: ParsableManimColor | None = None,\n        fill_opacity: float | None = None,\n        stroke_color: ParsableManimColor | None = None,\n        stroke_width: float | None = None,\n        stroke_opacity: float | None = None,\n        background_stroke_color: ParsableManimColor | None = None,\n        background_stroke_width: float | None = None,\n        background_stroke_opacity: float | None = None,\n        sheen_factor: float | None = None,\n        sheen_direction: Vector3DLike | None = None,\n        background_image: Image | str | None = None,\n        family: bool = True,\n    ) -> Self:\n        self.set_fill(color=fill_color, opacity=fill_opacity, family=family)\n        self.set_stroke(\n            color=stroke_color,\n            width=stroke_width,\n            opacity=stroke_opacity,\n            family=family,\n        )\n        self.set_background_stroke(\n            color=background_stroke_color,\n            width=background_stroke_width,\n            opacity=background_stroke_opacity,\n            family=family,\n        )\n        if sheen_factor:\n            self.set_sheen(\n                factor=sheen_factor,\n                direction=sheen_direction,\n                family=family,\n            )\n        if background_image:\n            self.color_using_background_image(background_image)\n        return self\n\n    def get_style(self, simple: bool = False) -> dict:\n        ret = {\n            \"stroke_opacity\": self.get_stroke_opacity(),\n            \"stroke_width\": self.get_stroke_width(),\n        }\n\n        # TODO: FIX COLORS HERE\n        if simple:\n            ret[\"fill_color\"] = self.get_fill_color()\n            ret[\"fill_opacity\"] = self.get_fill_opacity()\n            ret[\"stroke_color\"] = self.get_stroke_color()\n        else:\n            ret[\"fill_color\"] = self.get_fill_colors()\n            ret[\"fill_opacity\"] = self.get_fill_opacities()\n            ret[\"stroke_color\"] = self.get_stroke_colors()\n            ret[\"background_stroke_color\"] = self.get_stroke_colors(background=True)\n            ret[\"background_stroke_width\"] = self.get_stroke_width(background=True)\n            ret[\"background_stroke_opacity\"] = self.get_stroke_opacity(background=True)\n            ret[\"sheen_factor\"] = self.get_sheen_factor()\n            ret[\"sheen_direction\"] = self.get_sheen_direction()\n            ret[\"background_image\"] = self.get_background_image()\n\n        return ret\n\n    def match_style(self, vmobject: VMobject, family: bool = True) -> Self:\n        self.set_style(**vmobject.get_style(), family=False)\n\n        if family:\n            # Does its best to match up submobject lists, and\n            # match styles accordingly\n            submobs1, submobs2 = self.submobjects, vmobject.submobjects\n            if len(submobs1) == 0:\n                return self\n            elif len(submobs2) == 0:\n                submobs2 = [vmobject]\n            for sm1, sm2 in zip(*make_even(submobs1, submobs2), strict=True):\n                sm1.match_style(sm2)\n        return self\n\n    def set_color(self, color: ParsableManimColor, family: bool = True) -> Self:\n        self.set_fill(color, family=family)\n        self.set_stroke(color, family=family)\n        return self\n\n    def set_opacity(self, opacity: float, family: bool = True) -> Self:\n        self.set_fill(opacity=opacity, family=family)\n        self.set_stroke(opacity=opacity, family=family)\n        self.set_stroke(opacity=opacity, family=family, background=True)\n        return self\n\n    def scale(\n        self,\n        scale_factor: float,\n        scale_stroke: bool = False,\n        *,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n    ) -> Self:\n        r\"\"\"Scale the size by a factor.\n\n        Default behavior is to scale about the center of the vmobject.\n\n        Parameters\n        ----------\n        scale_factor\n            The scaling factor :math:`\\alpha`. If :math:`0 < |\\alpha| < 1`, the mobject\n            will shrink, and for :math:`|\\alpha| > 1` it will grow. Furthermore,\n            if :math:`\\alpha < 0`, the mobject is also flipped.\n        scale_stroke\n            Boolean determining if the object's outline is scaled when the object is scaled.\n            If enabled, and object with 2px outline is scaled by a factor of .5, it will have an outline of 1px.\n        kwargs\n            Additional keyword arguments passed to\n            :meth:`~.Mobject.scale`.\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n\n        Examples\n        --------\n\n        .. manim:: MobjectScaleExample\n            :save_last_frame:\n\n            class MobjectScaleExample(Scene):\n                def construct(self):\n                    c1 = Circle(1, RED).set_x(-1)\n                    c2 = Circle(1, GREEN).set_x(1)\n\n                    vg = VGroup(c1, c2)\n                    vg.set_stroke(width=50)\n                    self.add(vg)\n\n                    self.play(\n                        c1.animate.scale(.25),\n                        c2.animate.scale(.25,\n                            scale_stroke=True)\n                    )\n\n        See also\n        --------\n        :meth:`move_to`\n\n        \"\"\"\n        if scale_stroke:\n            self.set_stroke(width=abs(scale_factor) * self.get_stroke_width())\n            self.set_stroke(\n                width=abs(scale_factor) * self.get_stroke_width(background=True),\n                background=True,\n            )\n        super().scale(scale_factor, about_point=about_point, about_edge=about_edge)\n        return self\n\n    def fade(self, darkness: float = 0.5, family: bool = True) -> Self:\n        factor = 1.0 - darkness\n        self.set_fill(opacity=factor * self.get_fill_opacity(), family=False)\n        self.set_stroke(opacity=factor * self.get_stroke_opacity(), family=False)\n        self.set_background_stroke(\n            opacity=factor * self.get_stroke_opacity(background=True),\n            family=False,\n        )\n        super().fade(darkness, family)\n        return self\n\n    def get_fill_rgbas(self) -> FloatRGBA_Array:\n        try:\n            return self.fill_rgbas\n        except AttributeError:\n            return np.zeros((1, 4))\n\n    def get_fill_color(self) -> ManimColor:\n        \"\"\"\n        If there are multiple colors (for gradient)\n        this returns the first one\n        \"\"\"\n        return self.get_fill_colors()[0]\n\n    fill_color = property(get_fill_color, set_fill)\n\n    def get_fill_opacity(self) -> ManimFloat:\n        \"\"\"\n        If there are multiple opacities, this returns the\n        first\n        \"\"\"\n        return self.get_fill_opacities()[0]\n\n    # TODO: Does this just do a copy?\n    # TODO: I have the feeling that this function should not return None, does that have any usage ?\n    def get_fill_colors(self) -> list[ManimColor | None]:\n        return [\n            ManimColor(rgba[:3]) if rgba.any() else None\n            for rgba in self.get_fill_rgbas()\n        ]\n\n    def get_fill_opacities(self) -> npt.NDArray[ManimFloat]:\n        return self.get_fill_rgbas()[:, 3]\n\n    def get_stroke_rgbas(self, background: bool = False) -> FloatRGBA_Array:\n        try:\n            if background:\n                self.background_stroke_rgbas: FloatRGBA_Array\n                rgbas = self.background_stroke_rgbas\n            else:\n                self.stroke_rgbas: FloatRGBA_Array\n                rgbas = self.stroke_rgbas\n            return rgbas\n        except AttributeError:\n            return np.zeros((1, 4))\n\n    def get_stroke_color(self, background: bool = False) -> ManimColor | None:\n        return self.get_stroke_colors(background)[0]\n\n    stroke_color = property(get_stroke_color, set_stroke)\n\n    def get_stroke_width(self, background: bool = False) -> float:\n        if background:\n            width = self.background_stroke_width\n        else:\n            width = self.stroke_width\n            if isinstance(width, str):\n                width = int(width)\n        return max(0.0, width)\n\n    def get_stroke_opacity(self, background: bool = False) -> ManimFloat:\n        return self.get_stroke_opacities(background)[0]\n\n    def get_stroke_colors(self, background: bool = False) -> list[ManimColor | None]:\n        return [\n            ManimColor(rgba[:3]) if rgba.any() else None\n            for rgba in self.get_stroke_rgbas(background)\n        ]\n\n    def get_stroke_opacities(self, background: bool = False) -> npt.NDArray[ManimFloat]:\n        return self.get_stroke_rgbas(background)[:, 3]\n\n    def get_color(self) -> ManimColor:\n        if np.all(self.get_fill_opacities() == 0):\n            return self.get_stroke_color()\n        return self.get_fill_color()\n\n    color: ManimColor = property(get_color, set_color)\n\n    def nonempty_submobjects(self) -> Sequence[VMobject]:\n        return [\n            submob\n            for submob in self.submobjects\n            if len(submob.submobjects) != 0 or len(submob.points) != 0\n        ]\n\n    def split(self) -> list[VMobject]:\n        result: list[VMobject] = [self] if len(self.points) > 0 else []\n        return result + self.submobjects\n\n    def set_sheen_direction(self, direction: Vector3DLike, family: bool = True) -> Self:\n        \"\"\"Sets the direction of the applied sheen.\n\n        Parameters\n        ----------\n        direction\n            Direction from where the gradient is applied.\n\n        Examples\n        --------\n        Normal usage::\n\n            Circle().set_sheen_direction(UP)\n\n        See Also\n        --------\n        :meth:`~.VMobject.set_sheen`\n        :meth:`~.VMobject.rotate_sheen_direction`\n        \"\"\"\n        direction_copy = np.array(direction)\n        if family:\n            for submob in self.get_family():\n                submob.sheen_direction = direction_copy.copy()\n        else:\n            self.sheen_direction = direction_copy\n        return self\n\n    def rotate_sheen_direction(\n        self, angle: float, axis: Vector3DLike = OUT, family: bool = True\n    ) -> Self:\n        \"\"\"Rotates the direction of the applied sheen.\n\n        Parameters\n        ----------\n        angle\n            Angle by which the direction of sheen is rotated.\n        axis\n            Axis of rotation.\n\n        Examples\n        --------\n        Normal usage::\n\n            Circle().set_sheen_direction(UP).rotate_sheen_direction(PI)\n\n        See Also\n        --------\n        :meth:`~.VMobject.set_sheen_direction`\n        \"\"\"\n        if family:\n            for submob in self.get_family():\n                submob.sheen_direction = rotate_vector(\n                    submob.sheen_direction,\n                    angle,\n                    axis,\n                )\n        else:\n            self.sheen_direction = rotate_vector(self.sheen_direction, angle, axis)\n        return self\n\n    def set_sheen(\n        self, factor: float, direction: Vector3DLike | None = None, family: bool = True\n    ) -> Self:\n        \"\"\"Applies a color gradient from a direction.\n\n        Parameters\n        ----------\n        factor\n            The extent of lustre/gradient to apply. If negative, the gradient\n            starts from black, if positive the gradient starts from white and\n            changes to the current color.\n        direction\n            Direction from where the gradient is applied.\n\n        Examples\n        --------\n        .. manim:: SetSheen\n            :save_last_frame:\n\n            class SetSheen(Scene):\n                def construct(self):\n                    circle = Circle(fill_opacity=1).set_sheen(-0.3, DR)\n                    self.add(circle)\n        \"\"\"\n        if family:\n            for submob in self.submobjects:\n                submob.set_sheen(factor, direction, family)\n        self.sheen_factor: float = factor\n        if direction is not None:\n            # family set to false because recursion will\n            # already be handled above\n            self.set_sheen_direction(direction, family=False)\n        # Reset color to put sheen_factor into effect\n        if factor != 0:\n            self.set_stroke(self.get_stroke_color(), family=family)\n            self.set_fill(self.get_fill_color(), family=family)\n        return self\n\n    def get_sheen_direction(self) -> Vector3D:\n        return np.array(self.sheen_direction)\n\n    def get_sheen_factor(self) -> float:\n        return self.sheen_factor\n\n    def get_gradient_start_and_end_points(self) -> tuple[Point3D, Point3D]:\n        if self.shade_in_3d:\n            return get_3d_vmob_gradient_start_and_end_points(self)\n        else:\n            direction = self.get_sheen_direction()\n            c = self.get_center()\n            bases = np.array(\n                [self.get_edge_center(vect) - c for vect in [RIGHT, UP, OUT]],\n            ).transpose()\n            offset = np.dot(bases, direction)\n            return (c - offset, c + offset)\n\n    def color_using_background_image(self, background_image: Image | str) -> Self:\n        self.background_image: Image | str = background_image\n        self.set_color(WHITE)\n        for submob in self.submobjects:\n            submob.color_using_background_image(background_image)\n        return self\n\n    def get_background_image(self) -> Image | str:\n        return self.background_image\n\n    def match_background_image(self, vmobject: VMobject) -> Self:\n        self.color_using_background_image(vmobject.get_background_image())\n        return self\n\n    def set_shade_in_3d(\n        self, value: bool = True, z_index_as_group: bool = False\n    ) -> Self:\n        for submob in self.get_family():\n            submob.shade_in_3d = value\n            if z_index_as_group:\n                submob.z_index_group = self\n        return self\n\n    def set_points(self, points: Point3DLike_Array) -> Self:\n        self.points: Point3D_Array = np.array(points)\n        return self\n\n    def resize_points(\n        self,\n        new_length: int,\n        resize_func: Callable[[Point3D_Array, int], Point3D_Array] = resize_array,\n    ) -> Self:\n        \"\"\"Resize the array of anchor points and handles to have\n        the specified size.\n\n        Parameters\n        ----------\n        new_length\n            The new (total) number of points.\n        resize_func\n            A function mapping a Numpy array (the points) and an integer\n            (the target size) to a Numpy array. The default implementation\n            is based on Numpy's ``resize`` function.\n        \"\"\"\n        if new_length != len(self.points):\n            self.points = resize_func(self.points, new_length)\n        return self\n\n    def set_anchors_and_handles(\n        self,\n        anchors1: Point3DLike_Array,\n        handles1: Point3DLike_Array,\n        handles2: Point3DLike_Array,\n        anchors2: Point3DLike_Array,\n    ) -> Self:\n        \"\"\"Given two sets of anchors and handles, process them to set them as anchors\n        and handles of the VMobject.\n\n        anchors1[i], handles1[i], handles2[i] and anchors2[i] define the i-th bezier\n        curve of the vmobject. There are four hardcoded parameters and this is a\n        problem as it makes the number of points per cubic curve unchangeable from 4\n        (two anchors and two handles).\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n        \"\"\"\n        assert len(anchors1) == len(handles1) == len(handles2) == len(anchors2)\n        nppcc = self.n_points_per_cubic_curve  # 4\n        total_len = nppcc * len(anchors1)\n        self.points = np.empty((total_len, self.dim))\n        # the following will, from the four sets, dispatch them in points such that\n        # self.points = [\n        #     anchors1[0], handles1[0], handles2[0], anchors1[0], anchors1[1],\n        #     handles1[1], ...\n        # ]\n        arrays = [anchors1, handles1, handles2, anchors2]\n        for index, array in enumerate(arrays):\n            self.points[index::nppcc] = array\n        return self\n\n    def clear_points(self) -> None:\n        # TODO: shouldn't this return self instead of None?\n        self.points = np.zeros((0, self.dim))\n\n    def append_points(self, new_points: Point3DLike_Array) -> Self:\n        \"\"\"Append the given ``new_points`` to the end of\n        :attr:`VMobject.points`.\n\n        Parameters\n        ----------\n        new_points\n            An array of 3D points to append.\n\n        Returns\n        -------\n        :class:`VMobject`\n            The VMobject itself, after appending ``new_points``.\n        \"\"\"\n        # TODO, check that number new points is a multiple of 4?\n        # or else that if len(self.points) % 4 == 1, then\n        # len(new_points) % 4 == 3?\n        n = len(self.points)\n        points = np.empty((n + len(new_points), self.dim))\n        points[:n] = self.points\n        points[n:] = new_points\n        self.points = points\n        return self\n\n    def start_new_path(self, point: Point3DLike) -> Self:\n        \"\"\"Append a ``point`` to the :attr:`VMobject.points`, which will be the\n        beginning of a new Bézier curve in the path given by the points. If\n        there's an unfinished curve at the end of :attr:`VMobject.points`,\n        complete it by appending the last Bézier curve's start anchor as many\n        times as needed.\n\n        Parameters\n        ----------\n        point\n            A 3D point to append to :attr:`VMobject.points`.\n\n        Returns\n        -------\n        :class:`VMobject`\n            The VMobject itself, after appending ``point`` and starting a new\n            curve.\n        \"\"\"\n        n_points = len(self.points)\n        nppc = self.n_points_per_curve\n        if n_points % nppc != 0:\n            # close the open path by appending the last\n            # start anchor sufficiently often\n            last_anchor = self.get_start_anchors()[-1]\n            closure = [last_anchor] * (nppc - (n_points % nppc))\n            self.append_points(closure + [point])\n        else:\n            self.append_points([point])\n        return self\n\n    def add_cubic_bezier_curve(\n        self,\n        anchor1: Point3DLike,\n        handle1: Point3DLike,\n        handle2: Point3DLike,\n        anchor2: Point3DLike,\n    ) -> None:\n        # TODO, check the len(self.points) % 4 == 0?\n        self.append_points([anchor1, handle1, handle2, anchor2])\n\n    # what type is curves?\n    def add_cubic_bezier_curves(self, curves) -> None:\n        self.append_points(curves.flatten())\n\n    def add_cubic_bezier_curve_to(\n        self,\n        handle1: Point3DLike,\n        handle2: Point3DLike,\n        anchor: Point3DLike,\n    ) -> Self:\n        \"\"\"Add cubic bezier curve to the path.\n\n        NOTE : the first anchor is not a parameter as by default the end of the last sub-path!\n\n        Parameters\n        ----------\n        handle1\n            first handle\n        handle2\n            second handle\n        anchor\n            anchor\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n        \"\"\"\n        self.throw_error_if_no_points()\n        new_points = [handle1, handle2, anchor]\n        if self.has_new_path_started():\n            self.append_points(new_points)\n        else:\n            self.append_points([self.get_last_point()] + new_points)\n        return self\n\n    def add_quadratic_bezier_curve_to(\n        self,\n        handle: Point3DLike,\n        anchor: Point3DLike,\n    ) -> Self:\n        \"\"\"Add Quadratic bezier curve to the path.\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n        \"\"\"\n        # How does one approximate a quadratic with a cubic?\n        # refer to the Wikipedia page on Bezier curves\n        # https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Degree_elevation, accessed Jan 20, 2021\n        # 1. Copy the end points, and then\n        # 2. Place the 2 middle control points 2/3 along the line segments\n        # from the end points to the quadratic curve's middle control point.\n        # I think that's beautiful.\n        self.add_cubic_bezier_curve_to(\n            2 / 3 * handle + 1 / 3 * self.get_last_point(),\n            2 / 3 * handle + 1 / 3 * anchor,\n            anchor,\n        )\n        return self\n\n    def add_line_to(self, point: Point3DLike) -> Self:\n        \"\"\"Add a straight line from the last point of VMobject to the given point.\n\n        Parameters\n        ----------\n\n        point\n            The end of the straight line.\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n        \"\"\"\n        self.add_cubic_bezier_curve_to(\n            *(\n                interpolate(self.get_last_point(), point, t)\n                for t in self._bezier_t_values[1:]\n            )\n        )\n        return self\n\n    def add_smooth_curve_to(self, *points: Point3DLike) -> Self:\n        \"\"\"Creates a smooth curve from given points and add it to the VMobject. If two points are passed in, the first is interpreted\n        as a handle, the second as an anchor.\n\n        Parameters\n        ----------\n        points\n            Points (anchor and handle, or just anchor) to add a smooth curve from\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n\n        Raises\n        ------\n        ValueError\n            If 0 or more than 2 points are given.\n        \"\"\"\n        # TODO remove the value error and just add two parameters with one optional\n        if len(points) == 1:\n            handle2 = None\n            new_anchor = points[0]\n        elif len(points) == 2:\n            handle2, new_anchor = points\n        else:\n            name = sys._getframe(0).f_code.co_name\n            raise ValueError(f\"Only call {name} with 1 or 2 points\")\n\n        if self.has_new_path_started():\n            self.add_line_to(new_anchor)\n        else:\n            self.throw_error_if_no_points()\n            last_h2, last_a2 = self.points[-2:]\n            last_tangent = last_a2 - last_h2\n            handle1 = last_a2 + last_tangent\n            if handle2 is None:\n                to_anchor_vect = new_anchor - last_a2\n                new_tangent = rotate_vector(last_tangent, PI, axis=to_anchor_vect)\n                handle2 = new_anchor - new_tangent\n            self.append_points([last_a2, handle1, handle2, new_anchor])\n        return self\n\n    def has_new_path_started(self) -> bool:\n        nppcc = self.n_points_per_cubic_curve  # 4\n        # A new path starting is defined by a control point which is not part of a bezier subcurve.\n        return len(self.points) % nppcc == 1\n\n    def get_last_point(self) -> Point3D:\n        return self.points[-1]\n\n    def is_closed(self) -> bool:\n        # TODO use consider_points_equals_2d ?\n        return self.consider_points_equals(self.points[0], self.points[-1])\n\n    def close_path(self) -> None:\n        if not self.is_closed():\n            self.add_line_to(self.get_subpaths()[-1][0])\n\n    def add_points_as_corners(self, points: Point3DLike_Array) -> Self:\n        \"\"\"Append multiple straight lines at the end of\n        :attr:`VMobject.points`, which connect the given ``points`` in order\n        starting from the end of the current path. These ``points`` would be\n        therefore the corners of the new polyline appended to the path.\n\n        Parameters\n        ----------\n        points\n            An array of 3D points representing the corners of the polyline to\n            append to :attr:`VMobject.points`.\n\n        Returns\n        -------\n        :class:`VMobject`\n            The VMobject itself, after appending the straight lines to its\n            path.\n        \"\"\"\n        self.throw_error_if_no_points()\n\n        points = np.asarray(points).reshape(-1, self.dim)\n        num_points = points.shape[0]\n        if num_points == 0:\n            return self\n\n        start_corners = np.empty((num_points, self.dim))\n        start_corners[0] = self.points[-1]\n        start_corners[1:] = points[:-1]\n        end_corners = points\n\n        if self.has_new_path_started():\n            # Remove the last point from the new path\n            self.points = self.points[:-1]\n\n        nppcc = self.n_points_per_cubic_curve\n        new_points = np.empty((nppcc * start_corners.shape[0], self.dim))\n        new_points[::nppcc] = start_corners\n        new_points[nppcc - 1 :: nppcc] = end_corners\n        for i, t in enumerate(self._bezier_t_values):\n            new_points[i::nppcc] = interpolate(start_corners, end_corners, t)\n\n        self.append_points(new_points)\n        return self\n\n    def set_points_as_corners(self, points: Point3DLike_Array) -> Self:\n        \"\"\"Given an array of points, set them as corners of the\n        :class:`VMobject`.\n\n        To achieve that, this algorithm sets handles aligned with the anchors\n        such that the resultant Bézier curve will be the segment between the\n        two anchors.\n\n        Parameters\n        ----------\n        points\n            Array of points that will be set as corners.\n\n        Returns\n        -------\n        :class:`VMobject`\n            The VMobject itself, after setting the new points as corners.\n\n\n        Examples\n        --------\n        .. manim:: PointsAsCornersExample\n            :save_last_frame:\n\n            class PointsAsCornersExample(Scene):\n                def construct(self):\n                    corners = (\n                        # create square\n                        UR, UL,\n                        DL, DR,\n                        UR,\n                        # create crosses\n                        DL, UL,\n                        DR\n                    )\n                    vmob = VMobject(stroke_color=RED)\n                    vmob.set_points_as_corners(corners).scale(2)\n                    self.add(vmob)\n        \"\"\"\n        points = np.array(points)\n        # This will set the handles aligned with the anchors.\n        # Id est, a bezier curve will be the segment from the two anchors such that the handles belongs to this segment.\n        self.set_anchors_and_handles(\n            *(interpolate(points[:-1], points[1:], t) for t in self._bezier_t_values)\n        )\n        return self\n\n    def set_points_smoothly(self, points: Point3DLike_Array) -> Self:\n        self.set_points_as_corners(points)\n        self.make_smooth()\n        return self\n\n    def change_anchor_mode(self, mode: Literal[\"jagged\", \"smooth\"]) -> Self:\n        \"\"\"Changes the anchor mode of the bezier curves. This will modify the handles.\n\n        There can be only two modes, \"jagged\", and \"smooth\".\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n        \"\"\"\n        assert mode in [\"jagged\", \"smooth\"], 'mode must be either \"jagged\" or \"smooth\"'\n        nppcc = self.n_points_per_cubic_curve\n        for submob in self.family_members_with_points():\n            subpaths = submob.get_subpaths()\n            submob.clear_points()\n            # A subpath can be composed of several bezier curves.\n            for subpath in subpaths:\n                # This will retrieve the anchors of the subpath, by selecting every n element in the array subpath\n                # The append is needed as the last element is not reached when slicing with numpy.\n                anchors = np.append(subpath[::nppcc], subpath[-1:], 0)\n                if mode == \"smooth\":\n                    h1, h2 = get_smooth_cubic_bezier_handle_points(anchors)\n                else:  # mode == \"jagged\"\n                    # The following will make the handles aligned with the anchors, thus making the bezier curve a segment\n                    a1 = anchors[:-1]\n                    a2 = anchors[1:]\n                    h1 = interpolate(a1, a2, 1.0 / 3)\n                    h2 = interpolate(a1, a2, 2.0 / 3)\n                new_subpath = np.array(subpath)\n                new_subpath[1::nppcc] = h1\n                new_subpath[2::nppcc] = h2\n                submob.append_points(new_subpath)\n        return self\n\n    def make_smooth(self) -> Self:\n        return self.change_anchor_mode(\"smooth\")\n\n    def make_jagged(self) -> Self:\n        return self.change_anchor_mode(\"jagged\")\n\n    def add_subpath(self, points: CubicBezierPathLike) -> Self:\n        assert len(points) % 4 == 0\n        self.append_points(points)\n        return self\n\n    def append_vectorized_mobject(self, vectorized_mobject: VMobject) -> None:\n        if self.has_new_path_started():\n            # Remove last point, which is starting\n            # a new path\n            self.points = self.points[:-1]\n        self.append_points(vectorized_mobject.points)\n\n    def apply_function(\n        self,\n        function: MappingFunction,\n        *,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n    ) -> Self:\n        factor = self.pre_function_handle_to_anchor_scale_factor\n        self.scale_handle_to_anchor_distances(factor)\n        super().apply_function(function)\n        self.scale_handle_to_anchor_distances(1.0 / factor)\n        if self.make_smooth_after_applying_functions:\n            self.make_smooth()\n        return self\n\n    def rotate(\n        self,\n        angle: float,\n        axis: Vector3DLike = OUT,\n        *,\n        about_point: Point3DLike | None = None,\n        about_edge: Vector3DLike | None = None,\n    ) -> Self:\n        self.rotate_sheen_direction(angle, axis)\n        super().rotate(angle, axis, about_point=about_point, about_edge=about_edge)\n        return self\n\n    def scale_handle_to_anchor_distances(self, factor: float) -> Self:\n        \"\"\"If the distance between a given handle point H and its associated\n        anchor point A is d, then it changes H to be a distances factor*d\n        away from A, but so that the line from A to H doesn't change.\n        This is mostly useful in the context of applying a (differentiable)\n        function, to preserve tangency properties.  One would pull all the\n        handles closer to their anchors, apply the function then push them out\n        again.\n\n        Parameters\n        ----------\n        factor\n            The factor used for scaling.\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n        \"\"\"\n        for submob in self.family_members_with_points():\n            if len(submob.points) < self.n_points_per_cubic_curve:\n                # The case that a bezier quad is not complete (there is no bezier curve as there is not enough control points.)\n                continue\n            a1, h1, h2, a2 = submob.get_anchors_and_handles()\n            a1_to_h1 = h1 - a1\n            a2_to_h2 = h2 - a2\n            new_h1 = a1 + factor * a1_to_h1\n            new_h2 = a2 + factor * a2_to_h2\n            submob.set_anchors_and_handles(a1, new_h1, new_h2, a2)\n        return self\n\n    #\n    def consider_points_equals(self, p0: Point3DLike, p1: Point3DLike) -> bool:\n        return np.allclose(p0, p1, atol=self.tolerance_for_point_equality)\n\n    def consider_points_equals_2d(self, p0: Point2DLike, p1: Point2DLike) -> bool:\n        \"\"\"Determine if two points are close enough to be considered equal.\n\n        This uses the algorithm from np.isclose(), but expanded here for the\n        2D point case. NumPy is overkill for such a small question.\n        Parameters\n        ----------\n        p0\n            first point\n        p1\n            second point\n\n        Returns\n        -------\n        bool\n            whether two points considered close.\n        \"\"\"\n        rtol = 1.0e-5  # default from np.isclose()\n        atol = self.tolerance_for_point_equality\n        if abs(p0[0] - p1[0]) > atol + rtol * abs(p1[0]):\n            return False\n        return abs(p0[1] - p1[1]) <= atol + rtol * abs(p1[1])\n\n    # Information about line\n    def get_cubic_bezier_tuples_from_points(\n        self, points: CubicBezierPathLike\n    ) -> CubicBezierPoints_Array:\n        return np.array(self.gen_cubic_bezier_tuples_from_points(points))\n\n    def gen_cubic_bezier_tuples_from_points(\n        self, points: CubicBezierPathLike\n    ) -> tuple[CubicBezierPointsLike, ...]:\n        \"\"\"Returns the bezier tuples from an array of points.\n\n        self.points is a list of the anchors and handles of the bezier curves of the mobject (ie [anchor1, handle1, handle2, anchor2, anchor3 ..])\n        This algorithm basically retrieve them by taking an element every n, where n is the number of control points\n        of the bezier curve.\n\n\n        Parameters\n        ----------\n        points\n            Points from which control points will be extracted.\n\n        Returns\n        -------\n        tuple\n            Bezier control points.\n        \"\"\"\n        nppcc = self.n_points_per_cubic_curve\n        remainder = len(points) % nppcc\n        points = points[: len(points) - remainder]\n        # Basically take every nppcc element.\n        return tuple(points[i : i + nppcc] for i in range(0, len(points), nppcc))\n\n    def get_cubic_bezier_tuples(self) -> CubicBezierPoints_Array:\n        return self.get_cubic_bezier_tuples_from_points(self.points)\n\n    def _gen_subpaths_from_points(\n        self,\n        points: CubicBezierPath,\n        filter_func: Callable[[int], bool],\n    ) -> Iterable[CubicSpline]:\n        \"\"\"Given an array of points defining the bezier curves of the vmobject, return subpaths formed by these points.\n        Here, Two bezier curves form a path if at least two of their anchors are evaluated True by the relation defined by filter_func.\n\n        The algorithm every bezier tuple (anchors and handles) in ``self.points`` (by regrouping each n elements, where\n        n is the number of points per cubic curve)), and evaluate the relation between two anchors with filter_func.\n        NOTE : The filter_func takes an int n as parameter, and will evaluate the relation between points[n] and points[n - 1]. This should probably be changed so\n        the function takes two points as parameters.\n\n        Parameters\n        ----------\n        points\n            points defining the bezier curve.\n        filter_func\n            Filter-func defining the relation.\n\n        Returns\n        -------\n        Iterable[CubicSpline]\n            subpaths formed by the points.\n        \"\"\"\n        nppcc = self.n_points_per_cubic_curve\n        filtered = filter(filter_func, range(nppcc, len(points), nppcc))\n        split_indices = [0] + list(filtered) + [len(points)]\n        return (\n            points[i1:i2]\n            for i1, i2 in zip(split_indices[:-1], split_indices[1:], strict=True)\n            if (i2 - i1) >= nppcc\n        )\n\n    def get_subpaths_from_points(self, points: CubicBezierPath) -> list[CubicSpline]:\n        return list(\n            self._gen_subpaths_from_points(\n                points,\n                lambda n: not self.consider_points_equals(points[n - 1], points[n]),\n            ),\n        )\n\n    def gen_subpaths_from_points_2d(\n        self, points: CubicBezierPath\n    ) -> Iterable[CubicSpline]:\n        return self._gen_subpaths_from_points(\n            points,\n            lambda n: not self.consider_points_equals_2d(points[n - 1], points[n]),\n        )\n\n    def get_subpaths(self) -> list[CubicSpline]:\n        \"\"\"Returns subpaths formed by the curves of the VMobject.\n\n        Subpaths are ranges of curves with each pair of consecutive curves having their end/start points coincident.\n\n        Returns\n        -------\n        list[CubicSpline]\n            subpaths.\n        \"\"\"\n        return self.get_subpaths_from_points(self.points)\n\n    def get_nth_curve_points(self, n: int) -> CubicBezierPoints:\n        \"\"\"Returns the points defining the nth curve of the vmobject.\n\n        Parameters\n        ----------\n        n\n            index of the desired bezier curve.\n\n        Returns\n        -------\n        CubicBezierPoints\n            points defining the nth bezier curve (anchors, handles)\n        \"\"\"\n        assert n < self.get_num_curves()\n        nppcc = self.n_points_per_cubic_curve\n        return self.points[nppcc * n : nppcc * (n + 1)]\n\n    def get_nth_curve_function(self, n: int) -> Callable[[float], Point3D]:\n        \"\"\"Returns the expression of the nth curve.\n\n        Parameters\n        ----------\n        n\n            index of the desired curve.\n\n        Returns\n        -------\n        Callable[float, Point3D]\n            expression of the nth bezier curve.\n        \"\"\"\n        return bezier(self.get_nth_curve_points(n))\n\n    def get_nth_curve_length_pieces(\n        self,\n        n: int,\n        sample_points: int | None = None,\n    ) -> npt.NDArray[ManimFloat]:\n        \"\"\"Returns the array of short line lengths used for length approximation.\n\n        Parameters\n        ----------\n        n\n            The index of the desired curve.\n        sample_points\n            The number of points to sample to find the length.\n\n        Returns\n        -------\n            The short length-pieces of the nth curve.\n        \"\"\"\n        if sample_points is None:\n            sample_points = 10\n\n        curve = self.get_nth_curve_function(n)\n        points = np.array([curve(a) for a in np.linspace(0, 1, sample_points)])\n        diffs = points[1:] - points[:-1]\n        norms = np.linalg.norm(diffs, axis=1)\n\n        return norms\n\n    def get_nth_curve_length(\n        self,\n        n: int,\n        sample_points: int | None = None,\n    ) -> float:\n        \"\"\"Returns the (approximate) length of the nth curve.\n\n        Parameters\n        ----------\n        n\n            The index of the desired curve.\n        sample_points\n            The number of points to sample to find the length.\n\n        Returns\n        -------\n        length : :class:`float`\n            The length of the nth curve.\n        \"\"\"\n        _, length = self.get_nth_curve_function_with_length(n, sample_points)\n\n        return length\n\n    def get_nth_curve_function_with_length(\n        self,\n        n: int,\n        sample_points: int | None = None,\n    ) -> tuple[Callable[[float], Point3D], float]:\n        \"\"\"Returns the expression of the nth curve along with its (approximate) length.\n\n        Parameters\n        ----------\n        n\n            The index of the desired curve.\n        sample_points\n            The number of points to sample to find the length.\n\n        Returns\n        -------\n        curve : Callable[[float], Point3D]\n            The function for the nth curve.\n        length : :class:`float`\n            The length of the nth curve.\n        \"\"\"\n        curve = self.get_nth_curve_function(n)\n        norms = self.get_nth_curve_length_pieces(n, sample_points=sample_points)\n        length = np.sum(norms)\n\n        return curve, length\n\n    def get_num_curves(self) -> int:\n        \"\"\"Returns the number of curves of the vmobject.\n\n        Returns\n        -------\n        int\n            number of curves of the vmobject.\n        \"\"\"\n        nppcc = self.n_points_per_cubic_curve\n        return len(self.points) // nppcc\n\n    def get_curve_functions(\n        self,\n    ) -> Iterable[Callable[[float], Point3D]]:\n        \"\"\"Gets the functions for the curves of the mobject.\n\n        Returns\n        -------\n        Iterable[Callable[[float], Point3D]]\n            The functions for the curves.\n        \"\"\"\n        num_curves = self.get_num_curves()\n\n        for n in range(num_curves):\n            yield self.get_nth_curve_function(n)\n\n    def get_curve_functions_with_lengths(\n        self, **kwargs\n    ) -> Iterable[tuple[Callable[[float], Point3D], float]]:\n        \"\"\"Gets the functions and lengths of the curves for the mobject.\n\n        Parameters\n        ----------\n        **kwargs\n            The keyword arguments passed to :meth:`get_nth_curve_function_with_length`\n\n        Returns\n        -------\n        Iterable[tuple[Callable[[float], Point3D], float]]\n            The functions and lengths of the curves.\n        \"\"\"\n        num_curves = self.get_num_curves()\n\n        for n in range(num_curves):\n            yield self.get_nth_curve_function_with_length(n, **kwargs)\n\n    def point_from_proportion(self, alpha: float) -> Point3D:\n        \"\"\"Gets the point at a proportion along the path of the :class:`VMobject`.\n\n        Parameters\n        ----------\n        alpha\n            The proportion along the the path of the :class:`VMobject`.\n\n        Returns\n        -------\n        :class:`numpy.ndarray`\n            The point on the :class:`VMobject`.\n\n        Raises\n        ------\n        :exc:`ValueError`\n            If ``alpha`` is not between 0 and 1.\n        :exc:`Exception`\n            If the :class:`VMobject` has no points.\n\n        Example\n        -------\n        .. manim:: PointFromProportion\n            :save_last_frame:\n\n            class PointFromProportion(Scene):\n                def construct(self):\n                    line = Line(2*DL, 2*UR)\n                    self.add(line)\n                    colors = (RED, BLUE, YELLOW)\n                    proportions = (1/4, 1/2, 3/4)\n                    for color, proportion in zip(colors, proportions):\n                        self.add(Dot(color=color).move_to(\n                                line.point_from_proportion(proportion)\n                        ))\n        \"\"\"\n        if alpha < 0 or alpha > 1:\n            raise ValueError(f\"Alpha {alpha} not between 0 and 1.\")\n\n        self.throw_error_if_no_points()\n        if alpha == 1:\n            return self.points[-1]\n\n        curves_and_lengths = tuple(self.get_curve_functions_with_lengths())\n\n        target_length = alpha * sum(length for _, length in curves_and_lengths)\n        current_length = 0\n\n        for curve, length in curves_and_lengths:\n            if current_length + length >= target_length:\n                if length != 0:\n                    residue = (target_length - current_length) / length\n                else:\n                    residue = 0\n\n                return curve(residue)\n\n            current_length += length\n        raise Exception(\n            \"Not sure how you reached here, please file a bug report at https://github.com/ManimCommunity/manim/issues/new/choose\"\n        )\n\n    def proportion_from_point(\n        self,\n        point: Point3DLike,\n    ) -> float:\n        \"\"\"Returns the proportion along the path of the :class:`VMobject`\n        a particular given point is at.\n\n        Parameters\n        ----------\n        point\n            The Cartesian coordinates of the point which may or may not lie on the :class:`VMobject`\n\n        Returns\n        -------\n        float\n            The proportion along the path of the :class:`VMobject`.\n\n        Raises\n        ------\n        :exc:`ValueError`\n            If ``point`` does not lie on the curve.\n        :exc:`Exception`\n            If the :class:`VMobject` has no points.\n        \"\"\"\n        self.throw_error_if_no_points()\n\n        # Iterate over each bezier curve that the ``VMobject`` is composed of, checking\n        # if the point lies on that curve. If it does not lie on that curve, add\n        # the whole length of the curve to ``target_length`` and move onto the next\n        # curve. If the point does lie on the curve, add how far along the curve\n        # the point is to ``target_length``.\n        # Then, divide ``target_length`` by the total arc length of the shape to get\n        # the proportion along the ``VMobject`` the point is at.\n\n        num_curves = self.get_num_curves()\n        total_length = self.get_arc_length()\n        target_length = 0\n        for n in range(num_curves):\n            control_points = self.get_nth_curve_points(n)\n            length = self.get_nth_curve_length(n)\n            proportions_along_bezier = proportions_along_bezier_curve_for_point(\n                point,\n                control_points,\n            )\n            if len(proportions_along_bezier) > 0:\n                proportion_along_nth_curve = max(proportions_along_bezier)\n                target_length += length * proportion_along_nth_curve\n                break\n            target_length += length\n        else:\n            raise ValueError(f\"Point {point} does not lie on this curve.\")\n\n        alpha = target_length / total_length\n\n        return alpha\n\n    def get_anchors_and_handles(self) -> list[Point3D_Array]:\n        \"\"\"Returns anchors1, handles1, handles2, anchors2,\n        where (anchors1[i], handles1[i], handles2[i], anchors2[i])\n        will be four points defining a cubic bezier curve\n        for any i in range(0, len(anchors1))\n\n        Returns\n        -------\n        `list[Point3D_Array]`\n            Iterable of the anchors and handles.\n        \"\"\"\n        nppcc = self.n_points_per_cubic_curve\n        return [self.points[i::nppcc] for i in range(nppcc)]\n\n    def get_start_anchors(self) -> Point3D_Array:\n        \"\"\"Returns the start anchors of the bezier curves.\n\n        Returns\n        -------\n        Point3D_Array\n            Starting anchors\n        \"\"\"\n        return self.points[:: self.n_points_per_cubic_curve]\n\n    def get_end_anchors(self) -> Point3D_Array:\n        \"\"\"Return the end anchors of the bezier curves.\n\n        Returns\n        -------\n        Point3D_Array\n            Starting anchors\n        \"\"\"\n        nppcc = self.n_points_per_cubic_curve\n        return self.points[nppcc - 1 :: nppcc]\n\n    def get_anchors(self) -> list[Point3D]:\n        \"\"\"Returns the anchors of the curves forming the VMobject.\n\n        Returns\n        -------\n        Point3D_Array\n            The anchors.\n        \"\"\"\n        if self.points.shape[0] == 1:\n            return self.points\n\n        s = self.get_start_anchors()\n        e = self.get_end_anchors()\n        return list(it.chain.from_iterable(zip(s, e, strict=True)))\n\n    def get_points_defining_boundary(self) -> Point3D_Array:\n        # Probably returns all anchors, but this is weird regarding  the name of the method.\n        return np.array(\n            tuple(it.chain(*(sm.get_anchors() for sm in self.get_family())))\n        )\n\n    def get_arc_length(self, sample_points_per_curve: int | None = None) -> float:\n        \"\"\"Return the approximated length of the whole curve.\n\n        Parameters\n        ----------\n        sample_points_per_curve\n            Number of sample points per curve used to approximate the length. More points result in a better approximation.\n\n        Returns\n        -------\n        float\n            The length of the :class:`VMobject`.\n        \"\"\"\n        return sum(\n            length\n            for _, length in self.get_curve_functions_with_lengths(\n                sample_points=sample_points_per_curve,\n            )\n        )\n\n    # Alignment\n    def align_points(self, vmobject: VMobject) -> Self:\n        \"\"\"Adds points to self and vmobject so that they both have the same number of subpaths, with\n        corresponding subpaths each containing the same number of points.\n\n        Points are added either by subdividing curves evenly along the subpath, or by creating new subpaths consisting\n        of a single point repeated.\n\n        Parameters\n        ----------\n        vmobject\n            The object to align points with.\n\n        Returns\n        -------\n        :class:`VMobject`\n           ``self``\n\n        See also\n        --------\n        :meth:`~.Mobject.interpolate`, :meth:`~.Mobject.align_data`\n        \"\"\"\n        self.align_rgbas(vmobject)\n        # TODO: This shortcut can be a bit over eager. What if they have the same length, but different subpath lengths?\n        if self.get_num_points() == vmobject.get_num_points():\n            return\n\n        for mob in self, vmobject:\n            # If there are no points, add one to\n            # wherever the \"center\" is\n            if mob.has_no_points():\n                mob.start_new_path(mob.get_center())\n            # If there's only one point, turn it into\n            # a null curve\n            if mob.has_new_path_started():\n                mob.add_line_to(mob.get_last_point())\n\n        # Figure out what the subpaths are\n        subpaths1 = self.get_subpaths()\n        subpaths2 = vmobject.get_subpaths()\n        n_subpaths = max(len(subpaths1), len(subpaths2))\n        # Start building new ones\n        new_path1 = np.zeros((0, self.dim))\n        new_path2 = np.zeros((0, self.dim))\n\n        nppcc = self.n_points_per_cubic_curve\n\n        def get_nth_subpath(path_list, n):\n            if n >= len(path_list):\n                # Create a null path at the very end\n                if len(path_list) == 0:\n                    return np.tile(np.zeros(3), (nppcc, 1))\n                return np.tile(path_list[-1][-1], (nppcc, 1))\n            path = path_list[n]\n            # Check for useless points at the end of the path and remove them\n            # https://github.com/ManimCommunity/manim/issues/1959\n            while len(path) > nppcc:\n                # If the last nppc points are all equal to the preceding point\n                if self.consider_points_equals(path[-nppcc:], path[-nppcc - 1]):\n                    path = path[:-nppcc]\n                else:\n                    break\n            return path\n\n        for n in range(n_subpaths):\n            # For each pair of subpaths, add points until they are the same length\n            sp1 = get_nth_subpath(subpaths1, n)\n            sp2 = get_nth_subpath(subpaths2, n)\n            diff1 = max(0, (len(sp2) - len(sp1)) // nppcc)\n            diff2 = max(0, (len(sp1) - len(sp2)) // nppcc)\n            sp1 = self.insert_n_curves_to_point_list(diff1, sp1)\n            sp2 = self.insert_n_curves_to_point_list(diff2, sp2)\n            new_path1 = np.append(new_path1, sp1, axis=0)\n            new_path2 = np.append(new_path2, sp2, axis=0)\n        self.set_points(new_path1)\n        vmobject.set_points(new_path2)\n        return self\n\n    def insert_n_curves(self, n: int) -> Self:\n        \"\"\"Inserts n curves to the bezier curves of the vmobject.\n\n        Parameters\n        ----------\n        n\n            Number of curves to insert.\n\n        Returns\n        -------\n        :class:`VMobject`\n            ``self``\n        \"\"\"\n        new_path_point = None\n        if self.has_new_path_started():\n            new_path_point = self.get_last_point()\n\n        new_points = self.insert_n_curves_to_point_list(n, self.points)\n        self.set_points(new_points)\n\n        if new_path_point is not None:\n            self.append_points([new_path_point])\n        return self\n\n    def insert_n_curves_to_point_list(\n        self, n: int, points: BezierPathLike\n    ) -> BezierPath:\n        \"\"\"Given an array of k points defining a bezier curves (anchors and handles), returns points defining exactly k + n bezier curves.\n\n        Parameters\n        ----------\n        n\n            Number of desired curves.\n        points\n            Starting points.\n\n        Returns\n        -------\n            Points generated.\n        \"\"\"\n        if len(points) == 1:\n            nppcc = self.n_points_per_cubic_curve\n            return np.repeat(points, nppcc * n, 0)\n        bezier_tuples = self.get_cubic_bezier_tuples_from_points(points)\n        current_number_of_curves = len(bezier_tuples)\n        new_number_of_curves = current_number_of_curves + n\n        new_bezier_tuples = bezier_remap(bezier_tuples, new_number_of_curves)\n        new_points = new_bezier_tuples.reshape(-1, 3)\n        return new_points\n\n    def align_rgbas(self, vmobject: VMobject) -> Self:\n        attrs = [\"fill_rgbas\", \"stroke_rgbas\", \"background_stroke_rgbas\"]\n        for attr in attrs:\n            a1 = getattr(self, attr)\n            a2 = getattr(vmobject, attr)\n            if len(a1) > len(a2):\n                new_a2 = stretch_array_to_length(a2, len(a1))\n                setattr(vmobject, attr, new_a2)\n            elif len(a2) > len(a1):\n                new_a1 = stretch_array_to_length(a1, len(a2))\n                setattr(self, attr, new_a1)\n        return self\n\n    def get_point_mobject(self, center: Point3DLike | None = None) -> VectorizedPoint:\n        if center is None:\n            center = self.get_center()\n        point = VectorizedPoint(center)\n        point.match_style(self)\n        return point\n\n    def interpolate_color(\n        self, mobject1: VMobject, mobject2: VMobject, alpha: float\n    ) -> None:\n        attrs = [\n            \"fill_rgbas\",\n            \"stroke_rgbas\",\n            \"background_stroke_rgbas\",\n            \"stroke_width\",\n            \"background_stroke_width\",\n            \"sheen_direction\",\n            \"sheen_factor\",\n        ]\n        for attr in attrs:\n            setattr(\n                self,\n                attr,\n                interpolate(getattr(mobject1, attr), getattr(mobject2, attr), alpha),\n            )\n            if alpha == 1.0:\n                val = getattr(mobject2, attr)\n                if isinstance(val, np.ndarray):\n                    val = val.copy()\n                setattr(self, attr, val)\n\n    def pointwise_become_partial(\n        self,\n        vmobject: VMobject,\n        a: float,\n        b: float,\n    ) -> Self:\n        \"\"\"Given a 2nd :class:`.VMobject` ``vmobject``, a lower bound ``a`` and\n        an upper bound ``b``, modify this :class:`.VMobject`'s points to\n        match the portion of the Bézier spline described by ``vmobject.points``\n        with the parameter ``t`` between ``a`` and ``b``.\n\n        Parameters\n        ----------\n        vmobject\n            The :class:`.VMobject` that will serve as a model.\n        a\n            The lower bound for ``t``.\n        b\n            The upper bound for ``t``\n\n        Returns\n        -------\n        :class:`.VMobject`\n            The :class:`.VMobject` itself, after the transformation.\n\n        Raises\n        ------\n        TypeError\n            If ``vmobject`` is not an instance of :class:`VMobject`.\n        \"\"\"\n        if not isinstance(vmobject, VMobject):\n            raise TypeError(\n                f\"Expected a VMobject, got value {vmobject} of type \"\n                f\"{type(vmobject).__name__}.\"\n            )\n        # Partial curve includes three portions:\n        # - A middle section, which matches the curve exactly.\n        # - A start, which is some ending portion of an inner cubic.\n        # - An end, which is the starting portion of a later inner cubic.\n        if a <= 0 and b >= 1:\n            self.set_points(vmobject.points)\n            return self\n        num_curves = vmobject.get_num_curves()\n        if num_curves == 0:\n            return self\n\n        # The following two lines will compute which Bézier curves of the given Mobject must be processed.\n        # The residue indicates the proportion of the selected Bézier curve which must be selected.\n        #\n        # Example: if num_curves is 10, a is 0.34 and b is 0.78, then:\n        # - lower_index is 3 and lower_residue is 0.4, which means the algorithm will look at the 3rd Bézier\n        #   and select its part which ranges from t=0.4 to t=1.\n        # - upper_index is 7 and upper_residue is 0.8, which means the algorithm will look at the 7th Bézier\n        #   and select its part which ranges from t=0 to t=0.8.\n        lower_index, lower_residue = integer_interpolate(0, num_curves, a)\n        upper_index, upper_residue = integer_interpolate(0, num_curves, b)\n\n        nppc = self.n_points_per_curve\n\n        # Copy vmobject.points if vmobject is self to prevent unintended in-place modification\n        vmobject_points = (\n            vmobject.points.copy() if self is vmobject else vmobject.points\n        )\n\n        # If both indices coincide, get a part of a single Bézier curve.\n        if lower_index == upper_index:\n            # Look at the \"lower_index\"-th Bézier curve and select its part from\n            # t=lower_residue to t=upper_residue.\n            self.points = partial_bezier_points(\n                vmobject_points[nppc * lower_index : nppc * (lower_index + 1)],\n                lower_residue,\n                upper_residue,\n            )\n        else:\n            # Allocate space for (upper_index-lower_index+1) Bézier curves.\n            self.points = np.empty((nppc * (upper_index - lower_index + 1), self.dim))\n            # Look at the \"lower_index\"-th Bezier curve and select its part from\n            # t=lower_residue to t=1. This is the first curve in self.points.\n            self.points[:nppc] = partial_bezier_points(\n                vmobject_points[nppc * lower_index : nppc * (lower_index + 1)],\n                lower_residue,\n                1,\n            )\n            # If there are more curves between the \"lower_index\"-th and the\n            # \"upper_index\"-th Béziers, add them all to self.points.\n            self.points[nppc:-nppc] = vmobject_points[\n                nppc * (lower_index + 1) : nppc * upper_index\n            ]\n            # Look at the \"upper_index\"-th Bézier curve and select its part from\n            # t=0 to t=upper_residue. This is the last curve in self.points.\n            self.points[-nppc:] = partial_bezier_points(\n                vmobject_points[nppc * upper_index : nppc * (upper_index + 1)],\n                0,\n                upper_residue,\n            )\n\n        return self\n\n    def get_subcurve(self, a: float, b: float) -> Self:\n        \"\"\"Returns the subcurve of the VMobject between the interval [a, b].\n        The curve is a VMobject itself.\n\n        Parameters\n        ----------\n\n        a\n            The lower bound.\n        b\n            The upper bound.\n\n        Returns\n        -------\n        VMobject\n            The subcurve between of [a, b]\n        \"\"\"\n        if self.is_closed() and a > b:\n            vmob = self.copy()\n            vmob.pointwise_become_partial(self, a, 1)\n            vmob2 = self.copy()\n            vmob2.pointwise_become_partial(self, 0, b)\n            vmob.append_vectorized_mobject(vmob2)\n        else:\n            vmob = self.copy()\n            vmob.pointwise_become_partial(self, a, b)\n        return vmob\n\n    def get_direction(self) -> Literal[\"CW\", \"CCW\"]:\n        \"\"\"Uses :func:`~.space_ops.shoelace_direction` to calculate the direction.\n        The direction of points determines in which direction the\n        object is drawn, clockwise or counterclockwise.\n\n        Examples\n        --------\n        The default direction of a :class:`~.Circle` is counterclockwise::\n\n            >>> from manim import Circle\n            >>> Circle().get_direction()\n            'CCW'\n\n        Returns\n        -------\n        :class:`str`\n            Either ``\"CW\"`` or ``\"CCW\"``.\n        \"\"\"\n        return shoelace_direction(self.get_start_anchors())\n\n    def reverse_direction(self) -> Self:\n        \"\"\"Reverts the point direction by inverting the point order.\n\n        Returns\n        -------\n        :class:`VMobject`\n            Returns self.\n\n        Examples\n        --------\n        .. manim:: ChangeOfDirection\n\n            class ChangeOfDirection(Scene):\n                def construct(self):\n                    ccw = RegularPolygon(5)\n                    ccw.shift(LEFT)\n                    cw = RegularPolygon(5)\n                    cw.shift(RIGHT).reverse_direction()\n\n                    self.play(Create(ccw), Create(cw),\n                    run_time=4)\n        \"\"\"\n        self.points = self.points[::-1]\n        return self\n\n    def force_direction(self, target_direction: Literal[\"CW\", \"CCW\"]) -> Self:\n        \"\"\"Makes sure that points are either directed clockwise or\n        counterclockwise.\n\n        Parameters\n        ----------\n        target_direction\n            Either ``\"CW\"`` or ``\"CCW\"``.\n        \"\"\"\n        if target_direction not in (\"CW\", \"CCW\"):\n            raise ValueError('Invalid input for force_direction. Use \"CW\" or \"CCW\"')\n        if self.get_direction() != target_direction:\n            # Since we already assured the input is CW or CCW,\n            # and the directions don't match, we just reverse\n            self.reverse_direction()\n        return self\n\n\nclass VGroup(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A group of vectorized mobjects.\n\n    This can be used to group multiple :class:`~.VMobject` instances together\n    in order to scale, move, ... them together.\n\n    Notes\n    -----\n    When adding the same mobject more than once, repetitions are ignored.\n    Use :meth:`.Mobject.copy` to create a separate copy which can then\n    be added to the group.\n\n    Examples\n    --------\n\n    To add :class:`~.VMobject`s to a :class:`~.VGroup`, you can either use the\n    :meth:`~.VGroup.add` method, or use the `+` and `+=` operators. Similarly, you\n    can subtract elements of a VGroup via :meth:`~.VGroup.remove` method, or\n    `-` and `-=` operators:\n\n        >>> from manim import Triangle, Square, VGroup\n        >>> vg = VGroup()\n        >>> triangle, square = Triangle(), Square()\n        >>> vg.add(triangle)\n        VGroup(Triangle)\n        >>> vg + square  # a new VGroup is constructed\n        VGroup(Triangle, Square)\n        >>> vg  # not modified\n        VGroup(Triangle)\n        >>> vg += square\n        >>> vg  # modifies vg\n        VGroup(Triangle, Square)\n        >>> vg.remove(triangle)\n        VGroup(Square)\n        >>> vg - square  # a new VGroup is constructed\n        VGroup()\n        >>> vg  # not modified\n        VGroup(Square)\n        >>> vg -= square\n        >>> vg  # modifies vg\n        VGroup()\n\n    .. manim:: ArcShapeIris\n        :save_last_frame:\n\n        class ArcShapeIris(Scene):\n            def construct(self):\n                colors = [DARK_BROWN, BLUE_E, BLUE_D, BLUE_A, TEAL_B, GREEN_B, YELLOW_E]\n                radius = [1 + rad * 0.1 for rad in range(len(colors))]\n\n                circles_group = VGroup()\n\n                # zip(radius, color) makes the iterator [(radius[i], color[i]) for i in range(radius)]\n                circles_group.add(*[Circle(radius=rad, stroke_width=10, color=col)\n                                    for rad, col in zip(radius, colors)])\n                self.add(circles_group)\n\n    \"\"\"\n\n    def __init__(\n        self, *vmobjects: VMobject | Iterable[VMobject], **kwargs: Any\n    ) -> None:\n        super().__init__(**kwargs)\n        self.add(*vmobjects)\n\n    def __repr__(self) -> str:\n        return f\"{self.__class__.__name__}({', '.join(str(mob) for mob in self.submobjects)})\"\n\n    def __str__(self) -> str:\n        return (\n            f\"{self.__class__.__name__} of {len(self.submobjects)} \"\n            f\"submobject{'s' if len(self.submobjects) > 0 else ''}\"\n        )\n\n    def add(\n        self,\n        *vmobjects: VMobject | Iterable[VMobject],\n    ) -> Self:\n        \"\"\"Checks if all passed elements are an instance, or iterables of VMobject and then adds them to submobjects\n\n        Parameters\n        ----------\n        vmobjects\n            List or iterable of VMobjects to add\n\n        Returns\n        -------\n        :class:`VGroup`\n\n        Raises\n        ------\n        TypeError\n            If one element of the list, or iterable is not an instance of VMobject\n\n        Examples\n        --------\n        The following example shows how to add individual or multiple `VMobject` instances through the `VGroup`\n        constructor and its `.add()` method.\n\n        .. manim:: AddToVGroup\n\n            class AddToVGroup(Scene):\n                def construct(self):\n                    circle_red = Circle(color=RED)\n                    circle_green = Circle(color=GREEN)\n                    circle_blue = Circle(color=BLUE)\n                    circle_red.shift(LEFT)\n                    circle_blue.shift(RIGHT)\n                    gr = VGroup(circle_red, circle_green)\n                    gr2 = VGroup(circle_blue) # Constructor uses add directly\n                    self.add(gr,gr2)\n                    self.wait()\n                    gr += gr2 # Add group to another\n                    self.play(\n                        gr.animate.shift(DOWN),\n                    )\n                    gr -= gr2 # Remove group\n                    self.play( # Animate groups separately\n                        gr.animate.shift(LEFT),\n                        gr2.animate.shift(UP),\n                    )\n                    self.play( #Animate groups without modification\n                        (gr+gr2).animate.shift(RIGHT)\n                    )\n                    self.play( # Animate group without component\n                        (gr-circle_red).animate.shift(RIGHT)\n                    )\n\n        A `VGroup` can be created using iterables as well. Keep in mind that all generated values from an\n        iterable must be an instance of `VMobject`. This is demonstrated below:\n\n        .. manim:: AddIterableToVGroupExample\n            :save_last_frame:\n\n            class AddIterableToVGroupExample(Scene):\n                def construct(self):\n                    v = VGroup(\n                        Square(),               # Singular VMobject instance\n                        [Circle(), Triangle()], # List of VMobject instances\n                        Dot(),\n                        (Dot() for _ in range(2)), # Iterable that generates VMobjects\n                    )\n                    v.arrange()\n                    self.add(v)\n\n        To facilitate this, the iterable is unpacked before its individual instances are added to the `VGroup`.\n        As a result, when you index a `VGroup`, you will never get back an iterable.\n        Instead, you will always receive `VMobject` instances, including those\n        that were part of the iterable/s that you originally added to the `VGroup`.\n        \"\"\"\n\n        def get_type_error_message(invalid_obj, invalid_indices):\n            return (\n                f\"Only values of type {vmobject_render_type.__name__} can be added \"\n                \"as submobjects of VGroup, but the value \"\n                f\"{repr(invalid_obj)} (at index {invalid_indices[1]} of \"\n                f\"parameter {invalid_indices[0]}) is of type \"\n                f\"{type(invalid_obj).__name__}.\"\n            )\n\n        vmobject_render_type = (\n            OpenGLVMobject if config.renderer == RendererType.OPENGL else VMobject\n        )\n        valid_vmobjects = []\n\n        for i, vmobject in enumerate(vmobjects):\n            if isinstance(vmobject, vmobject_render_type):\n                valid_vmobjects.append(vmobject)\n            elif isinstance(vmobject, Iterable) and not isinstance(\n                vmobject, (Mobject, OpenGLMobject)\n            ):\n                for j, subvmobject in enumerate(vmobject):\n                    if not isinstance(subvmobject, vmobject_render_type):\n                        raise TypeError(get_type_error_message(subvmobject, (i, j)))\n                    valid_vmobjects.append(subvmobject)\n            elif isinstance(vmobject, Iterable) and isinstance(\n                vmobject, (Mobject, OpenGLMobject)\n            ):\n                raise TypeError(\n                    f\"{get_type_error_message(vmobject, (i, 0))} \"\n                    \"You can try adding this value into a Group instead.\"\n                )\n            else:\n                raise TypeError(get_type_error_message(vmobject, (i, 0)))\n\n        return super().add(*valid_vmobjects)\n\n    def __add__(self, vmobject: VMobject) -> Self:\n        return VGroup(*self.submobjects, vmobject)\n\n    def __iadd__(self, vmobject: VMobject) -> Self:\n        return self.add(vmobject)\n\n    def __sub__(self, vmobject: VMobject) -> Self:\n        copy = VGroup(*self.submobjects)\n        copy.remove(vmobject)\n        return copy\n\n    def __isub__(self, vmobject: VMobject) -> Self:\n        return self.remove(vmobject)\n\n    def __setitem__(self, key: int, value: VMobject | Sequence[VMobject]) -> None:\n        \"\"\"Override the [] operator for item assignment.\n\n        Parameters\n        ----------\n        key\n            The index of the submobject to be assigned\n        value\n            The vmobject value to assign to the key\n\n        Returns\n        -------\n        None\n\n        Tests\n        -----\n        Check that item assignment does not raise error::\n            >>> vgroup = VGroup(VMobject())\n            >>> new_obj = VMobject()\n            >>> vgroup[0] = new_obj\n        \"\"\"\n        self._assert_valid_submobjects(tuplify(value))\n        self.submobjects[key] = value\n\n    def __getitem__(self, key: int | slice) -> VMobject:\n        if isinstance(key, slice):\n            return VGroup(self.submobjects[key])\n        return self.submobjects[key]\n\n\nclass VDict(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A VGroup-like class, also offering submobject access by\n    key, like a python dict\n\n    Parameters\n    ----------\n    mapping_or_iterable\n            The parameter specifying the key-value mapping of keys and mobjects.\n    show_keys\n            Whether to also display the key associated with\n            the mobject. This might be useful when debugging,\n            especially when there are a lot of mobjects in the\n            :class:`VDict`. Defaults to False.\n    kwargs\n            Other arguments to be passed to `Mobject`.\n\n    Attributes\n    ----------\n    show_keys : :class:`bool`\n            Whether to also display the key associated with\n            the mobject. This might be useful when debugging,\n            especially when there are a lot of mobjects in the\n            :class:`VDict`. When displayed, the key is towards\n            the left of the mobject.\n            Defaults to False.\n    submob_dict : :class:`dict`\n            Is the actual python dictionary that is used to bind\n            the keys to the mobjects.\n\n    Examples\n    --------\n\n    .. manim:: ShapesWithVDict\n\n        class ShapesWithVDict(Scene):\n            def construct(self):\n                square = Square().set_color(RED)\n                circle = Circle().set_color(YELLOW).next_to(square, UP)\n\n                # create dict from list of tuples each having key-mobject pair\n                pairs = [(\"s\", square), (\"c\", circle)]\n                my_dict = VDict(pairs, show_keys=True)\n\n                # display it just like a VGroup\n                self.play(Create(my_dict))\n                self.wait()\n\n                text = Tex(\"Some text\").set_color(GREEN).next_to(square, DOWN)\n\n                # add a key-value pair by wrapping it in a single-element list of tuple\n                # after attrs branch is merged, it will be easier like `.add(t=text)`\n                my_dict.add([(\"t\", text)])\n                self.wait()\n\n                rect = Rectangle().next_to(text, DOWN)\n                # can also do key assignment like a python dict\n                my_dict[\"r\"] = rect\n\n                # access submobjects like a python dict\n                my_dict[\"t\"].set_color(PURPLE)\n                self.play(my_dict[\"t\"].animate.scale(3))\n                self.wait()\n\n                # also supports python dict styled reassignment\n                my_dict[\"t\"] = Tex(\"Some other text\").set_color(BLUE)\n                self.wait()\n\n                # remove submobject by key\n                my_dict.remove(\"t\")\n                self.wait()\n\n                self.play(Uncreate(my_dict[\"s\"]))\n                self.wait()\n\n                self.play(FadeOut(my_dict[\"c\"]))\n                self.wait()\n\n                self.play(FadeOut(my_dict[\"r\"], shift=DOWN))\n                self.wait()\n\n                # you can also make a VDict from an existing dict of mobjects\n                plain_dict = {\n                    1: Integer(1).shift(DOWN),\n                    2: Integer(2).shift(2 * DOWN),\n                    3: Integer(3).shift(3 * DOWN),\n                }\n\n                vdict_from_plain_dict = VDict(plain_dict)\n                vdict_from_plain_dict.shift(1.5 * (UP + LEFT))\n                self.play(Create(vdict_from_plain_dict))\n\n                # you can even use zip\n                vdict_using_zip = VDict(zip([\"s\", \"c\", \"r\"], [Square(), Circle(), Rectangle()]))\n                vdict_using_zip.shift(1.5 * RIGHT)\n                self.play(Create(vdict_using_zip))\n                self.wait()\n    \"\"\"\n\n    def __init__(\n        self,\n        mapping_or_iterable: (\n            Mapping[Hashable, VMobject] | Iterable[tuple[Hashable, VMobject]]\n        ) = {},\n        show_keys: bool = False,\n        **kwargs,\n    ) -> None:\n        super().__init__(**kwargs)\n        self.show_keys = show_keys\n        self.submob_dict = {}\n        self.add(mapping_or_iterable)\n\n    def __repr__(self) -> str:\n        return f\"{self.__class__.__name__}({repr(self.submob_dict)})\"\n\n    def add(\n        self,\n        mapping_or_iterable: (\n            Mapping[Hashable, VMobject] | Iterable[tuple[Hashable, VMobject]]\n        ),\n    ) -> Self:\n        \"\"\"Adds the key-value pairs to the :class:`VDict` object.\n\n        Also, it internally adds the value to the `submobjects` :class:`list`\n        of :class:`~.Mobject`, which is responsible for actual on-screen display.\n\n        Parameters\n        ---------\n        mapping_or_iterable\n            The parameter specifying the key-value mapping of keys and mobjects.\n\n        Returns\n        -------\n        :class:`VDict`\n            Returns the :class:`VDict` object on which this method was called.\n\n        Examples\n        --------\n        Normal usage::\n\n            square_obj = Square()\n            my_dict.add([(\"s\", square_obj)])\n        \"\"\"\n        for key, value in dict(mapping_or_iterable).items():\n            self.add_key_value_pair(key, value)\n\n        return self\n\n    def remove(self, key: Hashable) -> Self:\n        \"\"\"Removes the mobject from the :class:`VDict` object having the key `key`\n\n        Also, it internally removes the mobject from the `submobjects` :class:`list`\n        of :class:`~.Mobject`, (which is responsible for removing it from the screen)\n\n        Parameters\n        ----------\n        key\n            The key of the submoject to be removed.\n\n        Returns\n        -------\n        :class:`VDict`\n            Returns the :class:`VDict` object on which this method was called.\n\n        Examples\n        --------\n        Normal usage::\n\n            my_dict.remove(\"square\")\n        \"\"\"\n        if key not in self.submob_dict:\n            raise KeyError(f\"The given key '{key!s}' is not present in the VDict\")\n        super().remove(self.submob_dict[key])\n        del self.submob_dict[key]\n        return self\n\n    def __getitem__(self, key: Hashable):\n        \"\"\"Override the [] operator for item retrieval.\n\n        Parameters\n        ----------\n        key\n           The key of the submoject to be accessed\n\n        Returns\n        -------\n        :class:`VMobject`\n           The submobject corresponding to the key `key`\n\n        Examples\n        --------\n        Normal usage::\n\n           self.play(Create(my_dict[\"s\"]))\n        \"\"\"\n        submob = self.submob_dict[key]\n        return submob\n\n    def __setitem__(self, key: Hashable, value: VMobject) -> None:\n        \"\"\"Override the [] operator for item assignment.\n\n        Parameters\n        ----------\n        key\n            The key of the submoject to be assigned\n        value\n            The submobject to bind the key to\n\n        Returns\n        -------\n        None\n\n        Examples\n        --------\n        Normal usage::\n\n            square_obj = Square()\n            my_dict[\"sq\"] = square_obj\n        \"\"\"\n        if key in self.submob_dict:\n            self.remove(key)\n        self.add([(key, value)])\n\n    def __delitem__(self, key: Hashable):\n        \"\"\"Override the del operator for deleting an item.\n\n        Parameters\n        ----------\n        key\n            The key of the submoject to be deleted\n\n        Returns\n        -------\n        None\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import *\n            >>> my_dict = VDict({'sq': Square()})\n            >>> 'sq' in my_dict\n            True\n            >>> del my_dict['sq']\n            >>> 'sq' in my_dict\n            False\n\n        Notes\n        -----\n        Removing an item from a VDict does not remove that item from any Scene\n        that the VDict is part of.\n\n        \"\"\"\n        del self.submob_dict[key]\n\n    def __contains__(self, key: Hashable):\n        \"\"\"Override the in operator.\n\n        Parameters\n        ----------\n        key\n            The key to check membership of.\n\n        Returns\n        -------\n        :class:`bool`\n\n        Examples\n        --------\n        ::\n\n            >>> from manim import *\n            >>> my_dict = VDict({'sq': Square()})\n            >>> 'sq' in my_dict\n            True\n\n        \"\"\"\n        return key in self.submob_dict\n\n    def get_all_submobjects(self) -> list[list]:\n        \"\"\"To get all the submobjects associated with a particular :class:`VDict` object\n\n        Returns\n        -------\n        :class:`dict_values`\n            All the submobjects associated with the :class:`VDict` object\n\n        Examples\n        --------\n        Normal usage::\n\n            for submob in my_dict.get_all_submobjects():\n                self.play(Create(submob))\n        \"\"\"\n        submobjects = self.submob_dict.values()\n        return submobjects\n\n    def add_key_value_pair(self, key: Hashable, value: VMobject) -> None:\n        \"\"\"A utility function used by :meth:`add` to add the key-value pair\n        to :attr:`submob_dict`. Not really meant to be used externally.\n\n        Parameters\n        ----------\n        key\n            The key of the submobject to be added.\n        value\n            The mobject associated with the key\n\n        Returns\n        -------\n        None\n\n        Raises\n        ------\n        TypeError\n            If the value is not an instance of VMobject\n\n        Examples\n        --------\n        Normal usage::\n\n            square_obj = Square()\n            self.add_key_value_pair(\"s\", square_obj)\n\n        \"\"\"\n        self._assert_valid_submobjects([value])\n        mob = value\n        if self.show_keys:\n            # This import is here and not at the top to avoid circular import\n            from manim.mobject.text.tex_mobject import Tex\n\n            key_text = Tex(str(key)).next_to(value, LEFT)\n            mob.add(key_text)\n\n        self.submob_dict[key] = mob\n        super().add(value)\n\n\nclass VectorizedPoint(VMobject, metaclass=ConvertToOpenGL):\n    def __init__(\n        self,\n        location: Point3DLike = ORIGIN,\n        color: ManimColor = BLACK,\n        fill_opacity: float = 0,\n        stroke_width: float = 0,\n        artificial_width: float = 0.01,\n        artificial_height: float = 0.01,\n        **kwargs,\n    ) -> None:\n        self.artificial_width = artificial_width\n        self.artificial_height = artificial_height\n        super().__init__(\n            color=color,\n            fill_opacity=fill_opacity,\n            stroke_width=stroke_width,\n            **kwargs,\n        )\n        self.set_points(np.array([location]))\n\n    basecls = OpenGLVMobject if config.renderer == RendererType.OPENGL else VMobject\n\n    @basecls.width.getter\n    def width(self) -> float:\n        return self.artificial_width\n\n    @basecls.height.getter\n    def height(self) -> float:\n        return self.artificial_height\n\n    def get_location(self) -> Point3D:\n        return np.array(self.points[0])\n\n    def set_location(self, new_loc: Point3D):\n        self.set_points(np.array([new_loc]))\n\n\nclass CurvesAsSubmobjects(VGroup):\n    \"\"\"Convert a curve's elements to submobjects.\n\n    Examples\n    --------\n    .. manim:: LineGradientExample\n        :save_last_frame:\n\n        class LineGradientExample(Scene):\n            def construct(self):\n                curve = ParametricFunction(lambda t: [t, np.sin(t), 0], t_range=[-PI, PI, 0.01], stroke_width=10)\n                new_curve = CurvesAsSubmobjects(curve)\n                new_curve.set_color_by_gradient(BLUE, RED)\n                self.add(new_curve.shift(UP), curve)\n\n    \"\"\"\n\n    def __init__(self, vmobject: VMobject, **kwargs) -> None:\n        super().__init__(**kwargs)\n        tuples = vmobject.get_cubic_bezier_tuples()\n        for tup in tuples:\n            part = VMobject()\n            part.set_points(tup)\n            part.match_style(vmobject)\n            self.add(part)\n\n    def point_from_proportion(self, alpha: float) -> Point3D:\n        \"\"\"Gets the point at a proportion along the path of the :class:`CurvesAsSubmobjects`.\n\n        Parameters\n        ----------\n        alpha\n            The proportion along the the path of the :class:`CurvesAsSubmobjects`.\n\n        Returns\n        -------\n        :class:`numpy.ndarray`\n            The point on the :class:`CurvesAsSubmobjects`.\n\n        Raises\n        ------\n        :exc:`ValueError`\n            If ``alpha`` is not between 0 and 1.\n        :exc:`Exception`\n            If the :class:`CurvesAsSubmobjects` has no submobjects, or no submobject has points.\n        \"\"\"\n        if alpha < 0 or alpha > 1:\n            raise ValueError(f\"Alpha {alpha} not between 0 and 1.\")\n\n        self._throw_error_if_no_submobjects()\n        submobjs_with_pts = self._get_submobjects_with_points()\n\n        if alpha == 1:\n            return submobjs_with_pts[-1].points[-1]\n\n        submobjs_arc_lengths = tuple(\n            part.get_arc_length() for part in submobjs_with_pts\n        )\n\n        total_length = sum(submobjs_arc_lengths)\n        target_length = alpha * total_length\n        current_length = 0\n\n        for i, part in enumerate(submobjs_with_pts):\n            part_length = submobjs_arc_lengths[i]\n            if current_length + part_length >= target_length:\n                residue = (target_length - current_length) / part_length\n                return part.point_from_proportion(residue)\n\n            current_length += part_length\n\n    def _throw_error_if_no_submobjects(self):\n        if len(self.submobjects) == 0:\n            caller_name = sys._getframe(1).f_code.co_name\n            raise Exception(\n                f\"Cannot call CurvesAsSubmobjects. {caller_name} for a CurvesAsSubmobject with no submobjects\"\n            )\n\n    def _get_submobjects_with_points(self):\n        submobjs_with_pts = tuple(\n            part for part in self.submobjects if len(part.points) > 0\n        )\n        if len(submobjs_with_pts) == 0:\n            caller_name = sys._getframe(1).f_code.co_name\n            raise Exception(\n                f\"Cannot call CurvesAsSubmobjects. {caller_name} for a CurvesAsSubmobject whose submobjects have no points\"\n            )\n        return submobjs_with_pts\n\n\nclass DashedVMobject(VMobject, metaclass=ConvertToOpenGL):\n    \"\"\"A :class:`VMobject` composed of dashes instead of lines.\n\n    Parameters\n    ----------\n        vmobject\n            The object that will get dashed\n        num_dashes\n            Number of dashes to add.\n        dashed_ratio\n            Ratio of dash to empty space.\n        dash_offset\n            Shifts the starting point of dashes along the\n            path. Value 1 shifts by one full dash length.\n        equal_lengths\n            If ``True``, dashes will be (approximately) equally long.\n            If ``False``, dashes will be split evenly in the curve's\n            input t variable (legacy behavior).\n\n    Examples\n    --------\n    .. manim:: DashedVMobjectExample\n        :save_last_frame:\n\n        class DashedVMobjectExample(Scene):\n            def construct(self):\n                r = 0.5\n\n                top_row = VGroup()  # Increasing num_dashes\n                for dashes in range(1, 12):\n                    circ = DashedVMobject(Circle(radius=r, color=WHITE), num_dashes=dashes)\n                    top_row.add(circ)\n\n                middle_row = VGroup()  # Increasing dashed_ratio\n                for ratio in np.arange(1 / 11, 1, 1 / 11):\n                    circ = DashedVMobject(\n                        Circle(radius=r, color=WHITE), dashed_ratio=ratio\n                    )\n                    middle_row.add(circ)\n\n                func1 = FunctionGraph(lambda t: t**5,[-1,1],color=WHITE)\n                func_even = DashedVMobject(func1,num_dashes=6,equal_lengths=True)\n                func_stretched = DashedVMobject(func1, num_dashes=6, equal_lengths=False)\n                bottom_row = VGroup(func_even,func_stretched)\n\n\n                top_row.arrange(buff=0.3)\n                middle_row.arrange()\n                bottom_row.arrange(buff=1)\n                everything = VGroup(top_row, middle_row, bottom_row).arrange(DOWN, buff=1)\n                self.add(everything)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        vmobject: VMobject,\n        num_dashes: int = 15,\n        dashed_ratio: float = 0.5,\n        dash_offset: float = 0,\n        color: ManimColor = WHITE,\n        equal_lengths: bool = True,\n        **kwargs,\n    ) -> None:\n        self.dashed_ratio = dashed_ratio\n        self.num_dashes = num_dashes\n        super().__init__(color=color, **kwargs)\n\n        # Work on a copy to avoid mutating the caller's mobject (e.g. removing tips).\n        base_vmobject = vmobject\n        vmobject = base_vmobject.copy()\n\n        # TipableVMobject instances (Arrow, Vector, etc.) carry tips as submobjects.\n        # When dashing such objects, each subcurve would otherwise include its own\n        # tip, leading to many overlapping arrowheads. Pop tips from the working\n        # copy and re-attach them only once after the dashes are created.\n        tips = None\n        if hasattr(vmobject, \"pop_tips\"):\n            popped_tips = vmobject.pop_tips()\n            if len(popped_tips.submobjects) > 0:\n                tips = popped_tips\n\n        r = self.dashed_ratio\n        n = self.num_dashes\n        if n > 0:\n            # Assuming total length is 1\n            dash_len = r / n\n            if vmobject.is_closed():\n                void_len = (1 - r) / n\n            else:\n                void_len = 1 - r if n == 1 else (1 - r) / (n - 1)\n\n            period = dash_len + void_len\n            phase_shift = (dash_offset % 1) * period\n\n            if vmobject.is_closed():  # noqa: SIM108\n                # closed curves have equal amount of dashes and voids\n                pattern_len = 1\n            else:\n                # open curves start and end with a dash, so the whole dash pattern with the last void is longer\n                pattern_len = 1 + void_len\n\n            dash_starts = [((i * period + phase_shift) % pattern_len) for i in range(n)]\n            dash_ends = [\n                ((i * period + dash_len + phase_shift) % pattern_len) for i in range(n)\n            ]\n\n            # closed shapes can handle overflow at the 0-point\n            # open shapes need special treatment for it\n            if not vmobject.is_closed():\n                # due to phase shift being [0...1] range, always the last dash element needs attention for overflow\n                # if an entire dash moves out of the shape end:\n                if dash_ends[-1] > 1 and dash_starts[-1] > 1:\n                    # remove the last element since it is out-of-bounds\n                    dash_ends.pop()\n                    dash_starts.pop()\n                elif dash_ends[-1] < dash_len:  # if it overflowed\n                    if (\n                        dash_starts[-1] < 1\n                    ):  # if the beginning of the piece is still in range\n                        dash_starts.append(0)\n                        dash_ends.append(dash_ends[-1])\n                        dash_ends[-2] = 1\n                    else:\n                        dash_starts[-1] = 0\n                elif dash_starts[-1] > (1 - dash_len):\n                    dash_ends[-1] = 1\n\n            if equal_lengths:\n                # calculate the entire length by adding up short line-pieces\n                norms = np.array(0)\n                for k in range(vmobject.get_num_curves()):\n                    norms = np.append(norms, vmobject.get_nth_curve_length_pieces(k))\n                # add up length-pieces in array form\n                length_vals = np.cumsum(norms)\n                ref_points = np.linspace(0, 1, length_vals.size)\n                curve_length = length_vals[-1]\n                self.add(\n                    *(\n                        vmobject.get_subcurve(\n                            np.interp(\n                                dash_starts[i] * curve_length,\n                                length_vals,\n                                ref_points,\n                            ),\n                            np.interp(\n                                dash_ends[i] * curve_length,\n                                length_vals,\n                                ref_points,\n                            ),\n                        )\n                        for i in range(len(dash_starts))\n                    )\n                )\n            else:\n                self.add(\n                    *(\n                        vmobject.get_subcurve(\n                            dash_starts[i],\n                            dash_ends[i],\n                        )\n                        for i in range(len(dash_starts))\n                    )\n                )\n        # Family is already taken care of by get_subcurve\n        # implementation\n        if config.renderer == RendererType.OPENGL:\n            self.match_style(base_vmobject, recurse=False)\n        else:\n            self.match_style(base_vmobject, family=False)\n\n        if tips is not None:\n            self.add(*tips.submobjects)\n"
  },
  {
    "path": "manim/mobject/utils.py",
    "content": "\"\"\"Utilities for working with mobjects.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"get_mobject_class\",\n    \"get_point_mobject_class\",\n    \"get_vectorized_mobject_class\",\n]\n\nfrom .._config import config\nfrom ..constants import RendererType\nfrom .mobject import Mobject\nfrom .opengl.opengl_mobject import OpenGLMobject\nfrom .opengl.opengl_point_cloud_mobject import OpenGLPMobject\nfrom .opengl.opengl_vectorized_mobject import OpenGLVMobject\nfrom .types.point_cloud_mobject import PMobject\nfrom .types.vectorized_mobject import VMobject\n\n\ndef get_mobject_class() -> type:\n    \"\"\"Gets the base mobject class, depending on the currently active renderer.\n\n    .. NOTE::\n\n        This method is intended to be used in the code base of Manim itself\n        or in plugins where code should work independent of the selected\n        renderer.\n\n    Examples\n    --------\n\n    The function has to be explicitly imported. We test that\n    the name of the returned class is one of the known mobject\n    base classes::\n\n        >>> from manim.mobject.utils import get_mobject_class\n        >>> get_mobject_class().__name__ in ['Mobject', 'OpenGLMobject']\n        True\n    \"\"\"\n    if config.renderer == RendererType.CAIRO:\n        return Mobject\n    if config.renderer == RendererType.OPENGL:\n        return OpenGLMobject\n    raise NotImplementedError(\n        \"Base mobjects are not implemented for the active renderer.\"\n    )\n\n\ndef get_vectorized_mobject_class() -> type:\n    \"\"\"Gets the vectorized mobject class, depending on the currently\n    active renderer.\n\n    .. NOTE::\n\n        This method is intended to be used in the code base of Manim itself\n        or in plugins where code should work independent of the selected\n        renderer.\n\n    Examples\n    --------\n\n    The function has to be explicitly imported. We test that\n    the name of the returned class is one of the known mobject\n    base classes::\n\n        >>> from manim.mobject.utils import get_vectorized_mobject_class\n        >>> get_vectorized_mobject_class().__name__ in ['VMobject', 'OpenGLVMobject']\n        True\n    \"\"\"\n    if config.renderer == RendererType.CAIRO:\n        return VMobject\n    if config.renderer == RendererType.OPENGL:\n        return OpenGLVMobject\n    raise NotImplementedError(\n        \"Vectorized mobjects are not implemented for the active renderer.\"\n    )\n\n\ndef get_point_mobject_class() -> type:\n    \"\"\"Gets the point cloud mobject class, depending on the currently\n    active renderer.\n\n    .. NOTE::\n\n        This method is intended to be used in the code base of Manim itself\n        or in plugins where code should work independent of the selected\n        renderer.\n\n    Examples\n    --------\n\n    The function has to be explicitly imported. We test that\n    the name of the returned class is one of the known mobject\n    base classes::\n\n        >>> from manim.mobject.utils import get_point_mobject_class\n        >>> get_point_mobject_class().__name__ in ['PMobject', 'OpenGLPMobject']\n        True\n    \"\"\"\n    if config.renderer == RendererType.CAIRO:\n        return PMobject\n    if config.renderer == RendererType.OPENGL:\n        return OpenGLPMobject\n    raise NotImplementedError(\n        \"Point cloud mobjects are not implemented for the active renderer.\"\n    )\n"
  },
  {
    "path": "manim/mobject/value_tracker.py",
    "content": "\"\"\"Simple mobjects that can be used for storing (and updating) a value.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"ValueTracker\", \"ComplexValueTracker\"]\n\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.utils.paths import straight_path\n\nif TYPE_CHECKING:\n    from typing import Self\n\n    from manim.typing import PathFuncType\n\n\nclass ValueTracker(Mobject, metaclass=ConvertToOpenGL):\n    \"\"\"A mobject that can be used for tracking (real-valued) parameters.\n    Useful for animating parameter changes.\n\n    Not meant to be displayed.  Instead the position encodes some\n    number, often one which another animation or continual_animation\n    uses for its update function, and by treating it as a mobject it can\n    still be animated and manipulated just like anything else.\n\n    This value changes continuously when animated using the :attr:`animate` syntax.\n\n    Examples\n    --------\n    .. manim:: ValueTrackerExample\n\n        class ValueTrackerExample(Scene):\n            def construct(self):\n                number_line = NumberLine()\n                pointer = Vector(DOWN)\n                label = MathTex(\"x\").add_updater(lambda m: m.next_to(pointer, UP))\n\n                tracker = ValueTracker(0)\n                pointer.add_updater(\n                    lambda m: m.next_to(\n                                number_line.n2p(tracker.get_value()),\n                                UP\n                            )\n                )\n                self.add(number_line, pointer,label)\n                tracker += 1.5\n                self.wait(1)\n                tracker -= 4\n                self.wait(0.5)\n                self.play(tracker.animate.set_value(5))\n                self.wait(0.5)\n                self.play(tracker.animate.set_value(3))\n                self.play(tracker.animate.increment_value(-2))\n                self.wait(0.5)\n\n    .. note::\n\n        You can also link ValueTrackers to updaters. In this case, you have to make sure that the\n        ValueTracker is added to the scene by ``add``\n\n    .. manim:: ValueTrackerExample\n\n        class ValueTrackerExample(Scene):\n            def construct(self):\n                tracker = ValueTracker(0)\n                label = Dot(radius=3).add_updater(lambda x : x.set_x(tracker.get_value()))\n                self.add(label)\n                self.add(tracker)\n                tracker.add_updater(lambda mobject, dt: mobject.increment_value(dt))\n                self.wait(2)\n\n    \"\"\"\n\n    def __init__(self, value: float = 0, **kwargs: Any) -> None:\n        super().__init__(**kwargs)\n        self.set(points=np.zeros((1, 3)))\n        self.set_value(value)\n\n    def get_value(self) -> float:\n        \"\"\"Get the current value of this ValueTracker.\"\"\"\n        value: float = self.points[0, 0]\n        return value\n\n    def set_value(self, value: float) -> Self:\n        \"\"\"Sets a new scalar value to the ValueTracker.\"\"\"\n        self.points[0, 0] = value\n        return self\n\n    def increment_value(self, d_value: float) -> Self:\n        \"\"\"Increments (adds) a scalar value to the ValueTracker.\"\"\"\n        self.set_value(self.get_value() + d_value)\n        return self\n\n    def __bool__(self) -> bool:\n        \"\"\"Return whether the value of this ValueTracker evaluates as true.\"\"\"\n        return bool(self.get_value())\n\n    def __add__(self, d_value: float | Mobject) -> ValueTracker:\n        \"\"\"Return a new :class:`ValueTracker` whose value is the current tracker's value plus\n        ``d_value``.\n        \"\"\"\n        if isinstance(d_value, Mobject):\n            raise ValueError(\n                \"Cannot increment ValueTracker by a Mobject. Please provide a scalar value.\"\n            )\n        return ValueTracker(self.get_value() + d_value)\n\n    def __iadd__(self, d_value: float | Mobject) -> Self:\n        \"\"\"adds ``+=`` syntax to increment the value of the ValueTracker.\"\"\"\n        if isinstance(d_value, Mobject):\n            raise ValueError(\n                \"Cannot increment ValueTracker by a Mobject. Please provide a scalar value.\"\n            )\n        self.increment_value(d_value)\n        return self\n\n    def __floordiv__(self, d_value: float) -> ValueTracker:\n        \"\"\"Return a new :class:`ValueTracker` whose value is the floor division of the current\n        tracker's value by ``d_value``.\n        \"\"\"\n        return ValueTracker(self.get_value() // d_value)\n\n    def __ifloordiv__(self, d_value: float) -> Self:\n        \"\"\"Set the value of this ValueTracker to the floor division of the current value by ``d_value``.\"\"\"\n        self.set_value(self.get_value() // d_value)\n        return self\n\n    def __mod__(self, d_value: float) -> ValueTracker:\n        \"\"\"Return a new :class:`ValueTracker` whose value is the current tracker's value\n        modulo ``d_value``.\n        \"\"\"\n        return ValueTracker(self.get_value() % d_value)\n\n    def __imod__(self, d_value: float) -> Self:\n        \"\"\"Set the value of this ValueTracker to the current value modulo ``d_value``.\"\"\"\n        self.set_value(self.get_value() % d_value)\n        return self\n\n    def __mul__(self, d_value: float) -> ValueTracker:\n        \"\"\"Return a new :class:`ValueTracker` whose value is the current tracker's value multiplied by\n        ``d_value``.\n        \"\"\"\n        return ValueTracker(self.get_value() * d_value)\n\n    def __imul__(self, d_value: float) -> Self:\n        \"\"\"Set the value of this ValueTracker to the product of the current value and ``d_value``.\"\"\"\n        self.set_value(self.get_value() * d_value)\n        return self\n\n    def __pow__(self, d_value: float) -> ValueTracker:\n        \"\"\"Return a new :class:`ValueTracker` whose value is the current tracker's value raised to the\n        power of ``d_value``.\n        \"\"\"\n        return ValueTracker(self.get_value() ** d_value)\n\n    def __ipow__(self, d_value: float) -> Self:\n        \"\"\"Set the value of this ValueTracker to the current value raised to the power of ``d_value``.\"\"\"\n        self.set_value(self.get_value() ** d_value)\n        return self\n\n    def __sub__(self, d_value: float | Mobject) -> ValueTracker:\n        \"\"\"Return a new :class:`ValueTracker` whose value is the current tracker's value minus\n        ``d_value``.\n        \"\"\"\n        if isinstance(d_value, Mobject):\n            raise ValueError(\n                \"Cannot decrement ValueTracker by a Mobject. Please provide a scalar value.\"\n            )\n        return ValueTracker(self.get_value() - d_value)\n\n    def __isub__(self, d_value: float | Mobject) -> Self:\n        \"\"\"Adds ``-=`` syntax to decrement the value of the ValueTracker.\"\"\"\n        if isinstance(d_value, Mobject):\n            raise ValueError(\n                \"Cannot decrement ValueTracker by a Mobject. Please provide a scalar value.\"\n            )\n        self.increment_value(-d_value)\n        return self\n\n    def __truediv__(self, d_value: float) -> ValueTracker:\n        \"\"\"Return a new :class:`ValueTracker` whose value is the current tracker's value\n        divided by ``d_value``.\n        \"\"\"\n        return ValueTracker(self.get_value() / d_value)\n\n    def __itruediv__(self, d_value: float) -> Self:\n        \"\"\"Sets the value of this ValueTracker to the current value divided by ``d_value``.\"\"\"\n        self.set_value(self.get_value() / d_value)\n        return self\n\n    def interpolate(\n        self,\n        mobject1: Mobject,\n        mobject2: Mobject,\n        alpha: float,\n        path_func: PathFuncType = straight_path(),\n    ) -> Self:\n        \"\"\"Turns ``self`` into an interpolation between ``mobject1`` and ``mobject2``.\"\"\"\n        self.set(points=path_func(mobject1.points, mobject2.points, alpha))\n        return self\n\n\nclass ComplexValueTracker(ValueTracker):\n    \"\"\"Tracks a complex-valued parameter.\n\n    The value is internally stored as a points array [a, b, 0]. This can be accessed directly\n    to represent the value geometrically, see the usage example.\n    When the value is set through :attr:`animate`, the value will take a straight path from the\n    source point to the destination point.\n\n    Examples\n    --------\n    .. manim:: ComplexValueTrackerExample\n\n        class ComplexValueTrackerExample(Scene):\n            def construct(self):\n                tracker = ComplexValueTracker(-2+1j)\n                dot = Dot().add_updater(\n                    lambda x: x.move_to(tracker.points)\n                )\n\n                self.add(NumberPlane(), dot)\n\n                self.play(tracker.animate.set_value(3+2j))\n                self.play(tracker.animate.set_value(tracker.get_value() * 1j))\n                self.play(tracker.animate.set_value(tracker.get_value() - 2j))\n                self.play(tracker.animate.set_value(tracker.get_value() / (-2 + 3j)))\n    \"\"\"\n\n    def get_value(self) -> complex:  # type: ignore [override]\n        \"\"\"Get the current value of this ComplexValueTracker as a complex number.\"\"\"\n        return complex(*self.points[0, :2])\n\n    def set_value(self, value: complex | float) -> Self:\n        \"\"\"Sets a new complex value to the ComplexValueTracker.\"\"\"\n        z = complex(value)\n        self.points[0, :2] = (z.real, z.imag)\n        return self\n"
  },
  {
    "path": "manim/mobject/vector_field.py",
    "content": "\"\"\"Mobjects representing vector fields.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"VectorField\",\n    \"ArrowVectorField\",\n    \"StreamLines\",\n]\n\nimport itertools as it\nimport random\nfrom collections.abc import Callable, Iterable, Sequence\nfrom math import ceil, floor\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\nfrom PIL import Image\n\nfrom manim.animation.updaters.update import UpdateFromAlphaFunc\nfrom manim.mobject.geometry.line import Vector\nfrom manim.mobject.graphing.coordinate_systems import CoordinateSystem\n\nfrom .. import config\nfrom ..animation.composition import AnimationGroup, Succession\nfrom ..animation.creation import Create\nfrom ..animation.indication import ShowPassingFlash\nfrom ..constants import OUT, RIGHT, UP, RendererType\nfrom ..mobject.mobject import Mobject\nfrom ..mobject.types.vectorized_mobject import VGroup\nfrom ..mobject.utils import get_vectorized_mobject_class\nfrom ..utils.bezier import interpolate, inverse_interpolate\nfrom ..utils.color import (\n    BLUE_E,\n    GREEN,\n    RED,\n    YELLOW,\n    ManimColor,\n    ParsableManimColor,\n    color_to_rgb,\n    rgb_to_color,\n)\nfrom ..utils.rate_functions import ease_out_sine, linear\nfrom ..utils.simple_functions import sigmoid\n\nif TYPE_CHECKING:\n    from manim.typing import (\n        FloatRGB,\n        FloatRGB_Array,\n        FloatRGBA_Array,\n        Point3D,\n        Vector3D,\n    )\n\nDEFAULT_SCALAR_FIELD_COLORS: list = [BLUE_E, GREEN, YELLOW, RED]\n\n\nclass VectorField(VGroup):\n    \"\"\"A vector field.\n\n    Vector fields are based on a function defining a vector at every position.\n    This class does by default not include any visible elements but provides\n    methods to move other :class:`~.Mobject` s along the vector field.\n\n    Parameters\n    ----------\n    func\n        The function defining the rate of change at every position of the `VectorField`.\n    color\n        The color of the vector field. If set, position-specific coloring is disabled.\n    color_scheme\n        A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`.\n    min_color_scheme_value\n        The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient.\n    max_color_scheme_value\n        The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient.\n    colors\n        The colors defining the color gradient of the vector field.\n    kwargs\n        Additional arguments to be passed to the :class:`~.VGroup` constructor\n\n    \"\"\"\n\n    def __init__(\n        self,\n        func: Callable[[Point3D], Vector3D],\n        color: ParsableManimColor | None = None,\n        color_scheme: Callable[[Vector3D], float] | None = None,\n        min_color_scheme_value: float = 0,\n        max_color_scheme_value: float = 2,\n        colors: Sequence[ParsableManimColor] = DEFAULT_SCALAR_FIELD_COLORS,\n        **kwargs,\n    ):\n        super().__init__(**kwargs)\n        self.func = func\n        if color is None:\n            self.single_color = False\n            if color_scheme is None:\n\n                def color_scheme(vec: Vector3D) -> float:\n                    return np.linalg.norm(vec)\n\n            self.color_scheme = color_scheme  # TODO maybe other default for direction?\n            self.rgbs: FloatRGB_Array = np.array(list(map(color_to_rgb, colors)))\n\n            def pos_to_rgb(pos: Point3D) -> FloatRGB:\n                vec = self.func(pos)\n                color_value = np.clip(\n                    self.color_scheme(vec),\n                    min_color_scheme_value,\n                    max_color_scheme_value,\n                )\n                alpha = inverse_interpolate(\n                    min_color_scheme_value,\n                    max_color_scheme_value,\n                    color_value,\n                )\n                alpha *= len(self.rgbs) - 1\n                c1: FloatRGB = self.rgbs[int(alpha)]\n                c2: FloatRGB = self.rgbs[min(int(alpha + 1), len(self.rgbs) - 1)]\n                alpha %= 1\n                return interpolate(c1, c2, alpha)\n\n            self.pos_to_rgb = pos_to_rgb\n            self.pos_to_color = lambda pos: rgb_to_color(self.pos_to_rgb(pos))\n        else:\n            self.single_color = True\n            self.color = ManimColor.parse(color)\n        self.submob_movement_updater = None\n\n    @staticmethod\n    def shift_func(\n        func: Callable[[np.ndarray], np.ndarray],\n        shift_vector: np.ndarray,\n    ) -> Callable[[np.ndarray], np.ndarray]:\n        \"\"\"Shift a vector field function.\n\n        Parameters\n        ----------\n        func\n            The function defining a vector field.\n        shift_vector\n            The shift to be applied to the vector field.\n\n        Returns\n        -------\n        `Callable[[np.ndarray], np.ndarray]`\n            The shifted vector field function.\n\n        \"\"\"\n        return lambda p: func(p - shift_vector)\n\n    @staticmethod\n    def scale_func(\n        func: Callable[[np.ndarray], np.ndarray],\n        scalar: float,\n    ) -> Callable[[np.ndarray], np.ndarray]:\n        \"\"\"Scale a vector field function.\n\n        Parameters\n        ----------\n        func\n            The function defining a vector field.\n        scalar\n            The scalar to be applied to the vector field.\n\n        Examples\n        --------\n        .. manim:: ScaleVectorFieldFunction\n\n            class ScaleVectorFieldFunction(Scene):\n                def construct(self):\n                    func = lambda pos: np.sin(pos[1]) * RIGHT + np.cos(pos[0]) * UP\n                    vector_field = ArrowVectorField(func)\n                    self.add(vector_field)\n                    self.wait()\n\n                    func = VectorField.scale_func(func, 0.5)\n                    self.play(vector_field.animate.become(ArrowVectorField(func)))\n                    self.wait()\n\n        Returns\n        -------\n        `Callable[[np.ndarray], np.ndarray]`\n            The scaled vector field function.\n\n        \"\"\"\n        return lambda p: func(p * scalar)\n\n    def fit_to_coordinate_system(self, coordinate_system: CoordinateSystem):\n        \"\"\"Scale the vector field to fit a coordinate system.\n\n        This method is useful when the vector field is defined in a coordinate system\n        different from the one used to display the vector field.\n\n        This method can only be used once because it transforms the origin of each vector.\n\n        Parameters\n        ----------\n        coordinate_system\n            The coordinate system to fit the vector field to.\n\n        \"\"\"\n        self.apply_function(lambda pos: coordinate_system.coords_to_point(*pos))\n\n    def nudge(\n        self,\n        mob: Mobject,\n        dt: float = 1,\n        substeps: int = 1,\n        pointwise: bool = False,\n    ) -> VectorField:\n        \"\"\"Nudge a :class:`~.Mobject` along the vector field.\n\n        Parameters\n        ----------\n        mob\n            The mobject to move along the vector field\n        dt\n            A scalar to the amount the mobject is moved along the vector field.\n            The actual distance is based on the magnitude of the vector field.\n        substeps\n            The amount of steps the whole nudge is divided into. Higher values\n            give more accurate approximations.\n        pointwise\n            Whether to move the mobject along the vector field. If `False` the\n            vector field takes effect on the center of the given\n            :class:`~.Mobject`. If `True` the vector field takes effect on the\n            points of the individual points of the :class:`~.Mobject`,\n            potentially distorting it.\n\n        Returns\n        -------\n        VectorField\n            This vector field.\n\n        Examples\n        --------\n\n        .. manim:: Nudging\n\n            class Nudging(Scene):\n                def construct(self):\n                    func = lambda pos: np.sin(pos[1] / 2) * RIGHT + np.cos(pos[0] / 2) * UP\n                    vector_field = ArrowVectorField(\n                        func, x_range=[-7, 7, 1], y_range=[-4, 4, 1], length_func=lambda x: x / 2\n                    )\n                    self.add(vector_field)\n                    circle = Circle(radius=2).shift(LEFT)\n                    self.add(circle.copy().set_color(GRAY))\n                    dot = Dot().move_to(circle)\n\n                    vector_field.nudge(circle, -2, 60, True)\n                    vector_field.nudge(dot, -2, 60)\n\n                    circle.add_updater(vector_field.get_nudge_updater(pointwise=True))\n                    dot.add_updater(vector_field.get_nudge_updater())\n                    self.add(circle, dot)\n                    self.wait(6)\n\n        \"\"\"\n\n        def runge_kutta(self, p: Sequence[float], step_size: float) -> float:\n            \"\"\"Returns the change in position of a point along a vector field.\n            Parameters\n            ----------\n            p\n               The position of each point being moved along the vector field.\n            step_size\n               A scalar that is used to determine how much a point is shifted in a single step.\n\n            Returns\n            -------\n            float\n               How much the point is shifted.\n            \"\"\"\n            k_1 = self.func(p)\n            k_2 = self.func(p + step_size * (k_1 * 0.5))\n            k_3 = self.func(p + step_size * (k_2 * 0.5))\n            k_4 = self.func(p + step_size * k_3)\n            return step_size / 6.0 * (k_1 + 2.0 * k_2 + 2.0 * k_3 + k_4)\n\n        step_size = dt / substeps\n        for _ in range(substeps):\n            if pointwise:\n                mob.apply_function(lambda p: p + runge_kutta(self, p, step_size))\n            else:\n                mob.shift(runge_kutta(self, mob.get_center(), step_size))\n        return self\n\n    def nudge_submobjects(\n        self,\n        dt: float = 1,\n        substeps: int = 1,\n        pointwise: bool = False,\n    ) -> VectorField:\n        \"\"\"Apply a nudge along the vector field to all submobjects.\n\n        Parameters\n        ----------\n        dt\n            A scalar to the amount the mobject is moved along the vector field.\n            The actual distance is based on the magnitude of the vector field.\n        substeps\n            The amount of steps the whole nudge is divided into. Higher values\n            give more accurate approximations.\n        pointwise\n            Whether to move the mobject along the vector field. See :meth:`nudge` for details.\n\n        Returns\n        -------\n        VectorField\n            This vector field.\n\n        \"\"\"\n        for mob in self.submobjects:\n            self.nudge(mob, dt, substeps, pointwise)\n        return self\n\n    def get_nudge_updater(\n        self,\n        speed: float = 1,\n        pointwise: bool = False,\n    ) -> Callable[[Mobject, float], Mobject]:\n        \"\"\"Get an update function to move a :class:`~.Mobject` along the vector field.\n\n        When used with :meth:`~.Mobject.add_updater`, the mobject will move along the vector field, where its speed is determined by the magnitude of the vector field.\n\n        Parameters\n        ----------\n        speed\n            At `speed=1` the distance a mobject moves per second is equal to the magnitude of the vector field along its path. The speed value scales the speed of such a mobject.\n        pointwise\n            Whether to move the mobject along the vector field. See :meth:`nudge` for details.\n\n        Returns\n        -------\n        Callable[[Mobject, float], Mobject]\n            The update function.\n        \"\"\"\n        return lambda mob, dt: self.nudge(mob, dt * speed, pointwise=pointwise)\n\n    def start_submobject_movement(\n        self,\n        speed: float = 1,\n        pointwise: bool = False,\n    ) -> VectorField:\n        \"\"\"Start continuously moving all submobjects along the vector field.\n\n        Calling this method multiple times will result in removing the previous updater created by this method.\n\n        Parameters\n        ----------\n        speed\n            The speed at which to move the submobjects. See :meth:`get_nudge_updater` for details.\n        pointwise\n            Whether to move the mobject along the vector field. See :meth:`nudge` for details.\n\n        Returns\n        -------\n        VectorField\n            This vector field.\n\n        \"\"\"\n        self.stop_submobject_movement()\n        self.submob_movement_updater = lambda mob, dt: mob.nudge_submobjects(\n            dt * speed,\n            pointwise=pointwise,\n        )\n        self.add_updater(self.submob_movement_updater)\n        return self\n\n    def stop_submobject_movement(self) -> VectorField:\n        \"\"\"Stops the continuous movement started using :meth:`start_submobject_movement`.\n\n        Returns\n        -------\n        VectorField\n            This vector field.\n        \"\"\"\n        self.remove_updater(self.submob_movement_updater)\n        self.submob_movement_updater = None\n        return self\n\n    def get_colored_background_image(self, sampling_rate: int = 5) -> Image.Image:\n        \"\"\"Generate an image that displays the vector field.\n\n        The color at each position is calculated by passing the positing through a\n        series of steps:\n        Calculate the vector field function at that position, map that vector to a\n        single value using `self.color_scheme` and finally generate a color from\n        that value using the color gradient.\n\n        Parameters\n        ----------\n        sampling_rate\n            The stepsize at which pixels get included in the image. Lower values give\n            more accurate results, but may take a long time to compute.\n\n        Returns\n        -------\n        Image.Imgae\n            The vector field image.\n        \"\"\"\n        if self.single_color:\n            raise ValueError(\n                \"There is no point in generating an image if the vector field uses a single color.\",\n            )\n        ph = int(config[\"pixel_height\"] / sampling_rate)\n        pw = int(config[\"pixel_width\"] / sampling_rate)\n        fw = config[\"frame_width\"]\n        fh = config[\"frame_height\"]\n        points_array = np.zeros((ph, pw, 3))\n        x_array = np.linspace(-fw / 2, fw / 2, pw)\n        y_array = np.linspace(fh / 2, -fh / 2, ph)\n        x_array = x_array.reshape((1, len(x_array)))\n        y_array = y_array.reshape((len(y_array), 1))\n        x_array = x_array.repeat(ph, axis=0)\n        y_array.repeat(pw, axis=1)  # TODO why not y_array = y_array.repeat(...)?\n        points_array[:, :, 0] = x_array\n        points_array[:, :, 1] = y_array\n        rgbs = np.apply_along_axis(self.pos_to_rgb, 2, points_array)\n        return Image.fromarray((rgbs * 255).astype(\"uint8\"))\n\n    def get_vectorized_rgba_gradient_function(\n        self,\n        start: float,\n        end: float,\n        colors: Iterable[ParsableManimColor],\n    ) -> Callable[[Sequence[float], float], FloatRGBA_Array]:\n        \"\"\"\n        Generates a gradient of rgbas as a numpy array\n\n        Parameters\n        ----------\n        start\n            start value used for inverse interpolation at :func:`~.inverse_interpolate`\n        end\n            end value used for inverse interpolation at :func:`~.inverse_interpolate`\n        colors\n            list of colors to generate the gradient\n\n        Returns\n        -------\n            function to generate the gradients as numpy arrays representing rgba values\n        \"\"\"\n        rgbs: FloatRGB_Array = np.array([color_to_rgb(c) for c in colors])\n\n        def func(values: Sequence[float], opacity: float = 1.0) -> FloatRGBA_Array:\n            alphas = inverse_interpolate(start, end, np.array(values))\n            alphas = np.clip(alphas, 0, 1)\n            scaled_alphas = alphas * (len(rgbs) - 1)\n            indices = scaled_alphas.astype(int)\n            next_indices = np.clip(indices + 1, 0, len(rgbs) - 1)\n            inter_alphas = scaled_alphas % 1\n            inter_alphas = inter_alphas.repeat(3).reshape((len(indices), 3))\n            new_rgbs: FloatRGB_Array = interpolate(\n                rgbs[indices], rgbs[next_indices], inter_alphas\n            )\n            new_rgbas: FloatRGBA_Array = np.concatenate(\n                (new_rgbs, np.full([len(new_rgbs), 1], opacity)),\n                axis=1,\n            )\n            return new_rgbas\n\n        return func\n\n\nclass ArrowVectorField(VectorField):\n    \"\"\"A :class:`VectorField` represented by a set of change vectors.\n\n    Vector fields are always based on a function defining the :class:`~.Vector` at every position.\n    The values of this functions is displayed as a grid of vectors.\n    By default the color of each vector is determined by it's magnitude.\n    Other color schemes can be used however.\n\n    Parameters\n    ----------\n    func\n        The function defining the rate of change at every position of the vector field.\n    color\n        The color of the vector field. If set, position-specific coloring is disabled.\n    color_scheme\n        A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`.\n    min_color_scheme_value\n        The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient.\n    max_color_scheme_value\n        The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient.\n    colors\n        The colors defining the color gradient of the vector field.\n    x_range\n        A sequence of x_min, x_max, delta_x\n    y_range\n        A sequence of y_min, y_max, delta_y\n    z_range\n        A sequence of z_min, z_max, delta_z\n    three_dimensions\n        Enables three_dimensions. Default set to False, automatically turns True if\n        z_range is not None.\n    length_func\n        The function determining the displayed size of the vectors. The actual size\n        of the vector is passed, the returned value will be used as display size for the\n        vector. By default this is used to cap the displayed size of vectors to reduce the clutter.\n    opacity\n        The opacity of the arrows.\n    vector_config\n        Additional arguments to be passed to the :class:`~.Vector` constructor\n    kwargs\n        Additional arguments to be passed to the :class:`~.VGroup` constructor\n\n    Examples\n    --------\n\n    .. manim:: BasicUsage\n        :save_last_frame:\n\n        class BasicUsage(Scene):\n            def construct(self):\n                func = lambda pos: ((pos[0] * UR + pos[1] * LEFT) - pos) / 3\n                self.add(ArrowVectorField(func))\n\n    .. manim:: SizingAndSpacing\n\n        class SizingAndSpacing(Scene):\n            def construct(self):\n                func = lambda pos: np.sin(pos[0] / 2) * UR + np.cos(pos[1] / 2) * LEFT\n                vf = ArrowVectorField(func, x_range=[-7, 7, 1])\n                self.add(vf)\n                self.wait()\n\n                length_func = lambda x: x / 3\n                vf2 = ArrowVectorField(func, x_range=[-7, 7, 1], length_func=length_func)\n                self.play(vf.animate.become(vf2))\n                self.wait()\n\n    .. manim:: Coloring\n        :save_last_frame:\n\n        class Coloring(Scene):\n            def construct(self):\n                func = lambda pos: pos - LEFT * 5\n                colors = [RED, YELLOW, BLUE, DARK_GRAY]\n                min_radius = Circle(radius=2, color=colors[0]).shift(LEFT * 5)\n                max_radius = Circle(radius=10, color=colors[-1]).shift(LEFT * 5)\n                vf = ArrowVectorField(\n                    func, min_color_scheme_value=2, max_color_scheme_value=10, colors=colors\n                )\n                self.add(vf, min_radius, max_radius)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        func: Callable[[np.ndarray], np.ndarray],\n        color: ParsableManimColor | None = None,\n        color_scheme: Callable[[np.ndarray], float] | None = None,\n        min_color_scheme_value: float = 0,\n        max_color_scheme_value: float = 2,\n        colors: Sequence[ParsableManimColor] = DEFAULT_SCALAR_FIELD_COLORS,\n        # Determining Vector positions:\n        x_range: Sequence[float] = None,\n        y_range: Sequence[float] = None,\n        z_range: Sequence[float] = None,\n        three_dimensions: bool = False,  # Automatically True if z_range is set\n        # Takes in actual norm, spits out displayed norm\n        length_func: Callable[[float], float] = lambda norm: 0.45 * sigmoid(norm),\n        opacity: float = 1.0,\n        vector_config: dict | None = None,\n        **kwargs,\n    ):\n        self.x_range = x_range or [\n            floor(-config[\"frame_width\"] / 2),\n            ceil(config[\"frame_width\"] / 2),\n        ]\n        self.y_range = y_range or [\n            floor(-config[\"frame_height\"] / 2),\n            ceil(config[\"frame_height\"] / 2),\n        ]\n        self.ranges = [self.x_range, self.y_range]\n\n        if three_dimensions or z_range:\n            self.z_range = z_range or self.y_range.copy()\n            self.ranges += [self.z_range]\n        else:\n            self.ranges += [[0, 0]]\n\n        for i in range(len(self.ranges)):\n            if len(self.ranges[i]) == 2:\n                self.ranges[i] += [0.5]\n            self.ranges[i][1] += self.ranges[i][2]\n\n        self.x_range, self.y_range, self.z_range = self.ranges\n\n        super().__init__(\n            func,\n            color,\n            color_scheme,\n            min_color_scheme_value,\n            max_color_scheme_value,\n            colors,\n            **kwargs,\n        )\n\n        self.length_func = length_func\n        self.opacity = opacity\n        if vector_config is None:\n            vector_config = {}\n        self.vector_config = vector_config\n        self.func = func\n\n        x_range = np.arange(*self.x_range)\n        y_range = np.arange(*self.y_range)\n        z_range = np.arange(*self.z_range)\n        self.add(\n            *[\n                self.get_vector(x * RIGHT + y * UP + z * OUT)\n                for x, y, z in it.product(x_range, y_range, z_range)\n            ]\n        )\n        self.set_opacity(self.opacity)\n\n    def get_vector(self, point: np.ndarray):\n        \"\"\"Creates a vector in the vector field.\n\n        The created vector is based on the function of the vector field and is\n        rooted in the given point. Color and length fit the specifications of\n        this vector field.\n\n        Parameters\n        ----------\n        point\n            The root point of the vector.\n\n        \"\"\"\n        output = np.array(self.func(point))\n        norm = np.linalg.norm(output)\n        if norm != 0:\n            output *= self.length_func(norm) / norm\n        vect = Vector(output, **self.vector_config)\n        vect.shift(point)\n        if self.single_color:\n            vect.set_color(self.color)\n        else:\n            vect.set_color(self.pos_to_color(point))\n        return vect\n\n\nclass StreamLines(VectorField):\n    \"\"\"StreamLines represent the flow of a :class:`VectorField` using the trace of moving agents.\n\n    Vector fields are always based on a function defining the vector at every position.\n    The values of this functions is displayed by moving many agents along the vector field\n    and showing their trace.\n\n    Parameters\n    ----------\n    func\n        The function defining the rate of change at every position of the vector field.\n    color\n        The color of the vector field. If set, position-specific coloring is disabled.\n    color_scheme\n        A function mapping a vector to a single value. This value gives the position in the color gradient defined using `min_color_scheme_value`, `max_color_scheme_value` and `colors`.\n    min_color_scheme_value\n        The value of the color_scheme function to be mapped to the first color in `colors`. Lower values also result in the first color of the gradient.\n    max_color_scheme_value\n        The value of the color_scheme function to be mapped to the last color in `colors`. Higher values also result in the last color of the gradient.\n    colors\n        The colors defining the color gradient of the vector field.\n    x_range\n        A sequence of x_min, x_max, delta_x\n    y_range\n        A sequence of y_min, y_max, delta_y\n    z_range\n        A sequence of z_min, z_max, delta_z\n    three_dimensions\n        Enables three_dimensions. Default set to False, automatically turns True if\n        z_range is not None.\n    noise_factor\n        The amount by which the starting position of each agent is altered along each axis. Defaults to :code:`delta_y / 2` if not defined.\n    n_repeats\n        The number of agents generated at each starting point.\n    dt\n        The factor by which the distance an agent moves per step is stretched. Lower values result in a better approximation of the trajectories in the vector field.\n    virtual_time\n        The time the agents get to move in the vector field. Higher values therefore result in longer stream lines. However, this whole time gets simulated upon creation.\n    max_anchors_per_line\n        The maximum number of anchors per line. Lines with more anchors get reduced in complexity, not in length.\n    padding\n        The distance agents can move out of the generation area before being terminated.\n    stroke_width\n        The stroke with of the stream lines.\n    opacity\n        The opacity of the stream lines.\n\n    Examples\n    --------\n\n    .. manim:: BasicUsage\n        :save_last_frame:\n\n        class BasicUsage(Scene):\n            def construct(self):\n                func = lambda pos: ((pos[0] * UR + pos[1] * LEFT) - pos) / 3\n                self.add(StreamLines(func))\n\n    .. manim:: SpawningAndFlowingArea\n        :save_last_frame:\n\n        class SpawningAndFlowingArea(Scene):\n            def construct(self):\n                func = lambda pos: np.sin(pos[0]) * UR + np.cos(pos[1]) * LEFT + pos / 5\n                stream_lines = StreamLines(\n                    func, x_range=[-3, 3, 0.2], y_range=[-2, 2, 0.2], padding=1\n                )\n\n                spawning_area = Rectangle(width=6, height=4)\n                flowing_area = Rectangle(width=8, height=6)\n                labels = [Tex(\"Spawning Area\"), Tex(\"Flowing Area\").shift(DOWN * 2.5)]\n                for lbl in labels:\n                    lbl.add_background_rectangle(opacity=0.6, buff=0.05)\n\n                self.add(stream_lines, spawning_area, flowing_area, *labels)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        func: Callable[[np.ndarray], np.ndarray],\n        color: ParsableManimColor | None = None,\n        color_scheme: Callable[[np.ndarray], float] | None = None,\n        min_color_scheme_value: float = 0,\n        max_color_scheme_value: float = 2,\n        colors: Sequence[ParsableManimColor] = DEFAULT_SCALAR_FIELD_COLORS,\n        # Determining stream line starting positions:\n        x_range: Sequence[float] = None,\n        y_range: Sequence[float] = None,\n        z_range: Sequence[float] = None,\n        three_dimensions: bool = False,\n        noise_factor: float | None = None,\n        n_repeats=1,\n        # Determining how lines are drawn\n        dt=0.05,\n        virtual_time=3,\n        max_anchors_per_line=100,\n        padding=3,\n        # Determining stream line appearance:\n        stroke_width=1,\n        opacity=1,\n        **kwargs,\n    ):\n        self.x_range = x_range or [\n            floor(-config[\"frame_width\"] / 2),\n            ceil(config[\"frame_width\"] / 2),\n        ]\n        self.y_range = y_range or [\n            floor(-config[\"frame_height\"] / 2),\n            ceil(config[\"frame_height\"] / 2),\n        ]\n        self.ranges = [self.x_range, self.y_range]\n\n        if three_dimensions or z_range:\n            self.z_range = z_range or self.y_range.copy()\n            self.ranges += [self.z_range]\n        else:\n            self.ranges += [[0, 0]]\n\n        for i in range(len(self.ranges)):\n            if len(self.ranges[i]) == 2:\n                self.ranges[i] += [0.5]\n            self.ranges[i][1] += self.ranges[i][2]\n\n        self.x_range, self.y_range, self.z_range = self.ranges\n\n        super().__init__(\n            func,\n            color,\n            color_scheme,\n            min_color_scheme_value,\n            max_color_scheme_value,\n            colors,\n            **kwargs,\n        )\n\n        self.noise_factor = (\n            noise_factor if noise_factor is not None else self.y_range[2] / 2\n        )\n        self.n_repeats = n_repeats\n        self.virtual_time = virtual_time\n        self.max_anchors_per_line = max_anchors_per_line\n        self.padding = padding\n        self.stroke_width = stroke_width\n\n        half_noise = self.noise_factor / 2\n        rng = np.random.default_rng(0)\n        start_points = np.array(\n            [\n                (x - half_noise) * RIGHT\n                + (y - half_noise) * UP\n                + (z - half_noise) * OUT\n                + self.noise_factor * rng.random(3)\n                for n in range(self.n_repeats)\n                for x in np.arange(*self.x_range)\n                for y in np.arange(*self.y_range)\n                for z in np.arange(*self.z_range)\n            ],\n        )\n\n        def outside_box(p):\n            return (\n                p[0] < self.x_range[0] - self.padding\n                or p[0] > self.x_range[1] + self.padding - self.x_range[2]\n                or p[1] < self.y_range[0] - self.padding\n                or p[1] > self.y_range[1] + self.padding - self.y_range[2]\n                or p[2] < self.z_range[0] - self.padding\n                or p[2] > self.z_range[1] + self.padding - self.z_range[2]\n            )\n\n        max_steps = ceil(virtual_time / dt) + 1\n        if not self.single_color:\n            self.background_img = self.get_colored_background_image()\n            if config[\"renderer\"] == RendererType.OPENGL:\n                self.values_to_rgbas = self.get_vectorized_rgba_gradient_function(\n                    min_color_scheme_value,\n                    max_color_scheme_value,\n                    colors,\n                )\n        for point in start_points:\n            points = [point]\n            for _ in range(max_steps):\n                last_point = points[-1]\n                new_point = last_point + dt * func(last_point)\n                if outside_box(new_point):\n                    break\n                points.append(new_point)\n            step = max_steps\n            if not step:\n                continue\n            line = get_vectorized_mobject_class()()\n            line.duration = step * dt\n            step = max(1, int(len(points) / self.max_anchors_per_line))\n            line.set_points_smoothly(points[::step])\n            if self.single_color:\n                line.set_stroke(\n                    color=self.color, width=self.stroke_width, opacity=opacity\n                )\n            else:\n                if config.renderer == RendererType.OPENGL:\n                    # scaled for compatibility with cairo\n                    line.set_stroke(width=self.stroke_width / 4.0)\n                    norms = np.array(\n                        [np.linalg.norm(self.func(point)) for point in line.points],\n                    )\n                    line.set_rgba_array_direct(\n                        self.values_to_rgbas(norms, opacity),\n                        name=\"stroke_rgba\",\n                    )\n                else:\n                    if np.any(self.z_range != np.array([0, 0.5, 0.5])):\n                        line.set_stroke(\n                            [self.pos_to_color(p) for p in line.get_anchors()],\n                        )\n                    else:\n                        line.color_using_background_image(self.background_img)\n                    line.set_stroke(width=self.stroke_width, opacity=opacity)\n            self.add(line)\n        self.stream_lines = [*self.submobjects]\n\n    def create(\n        self,\n        lag_ratio: float | None = None,\n        run_time: Callable[[float], float] | None = None,\n        **kwargs,\n    ) -> AnimationGroup:\n        \"\"\"The creation animation of the stream lines.\n\n        The stream lines appear in random order.\n\n        Parameters\n        ----------\n        lag_ratio\n            The lag ratio of the animation.\n            If undefined, it will be selected so that the total animation length is 1.5 times the run time of each stream line creation.\n        run_time\n            The run time of every single stream line creation. The runtime of the whole animation might be longer due to the `lag_ratio`.\n            If undefined, the virtual time of the stream lines is used as run time.\n\n        Returns\n        -------\n        :class:`~.AnimationGroup`\n            The creation animation of the stream lines.\n\n        Examples\n        --------\n\n        .. manim:: StreamLineCreation\n\n            class StreamLineCreation(Scene):\n                def construct(self):\n                    func = lambda pos: (pos[0] * UR + pos[1] * LEFT) - pos\n                    stream_lines = StreamLines(\n                        func,\n                        color=YELLOW,\n                        x_range=[-7, 7, 1],\n                        y_range=[-4, 4, 1],\n                        stroke_width=3,\n                        virtual_time=1,  # use shorter lines\n                        max_anchors_per_line=5,  # better performance with fewer anchors\n                    )\n                    self.play(stream_lines.create())  # uses virtual_time as run_time\n                    self.wait()\n\n        \"\"\"\n        if run_time is None:\n            run_time = self.virtual_time\n        if lag_ratio is None:\n            lag_ratio = run_time / 2 / len(self.submobjects)\n\n        animations = [\n            Create(line, run_time=run_time, **kwargs) for line in self.stream_lines\n        ]\n        random.shuffle(animations)\n        return AnimationGroup(*animations, lag_ratio=lag_ratio)\n\n    def start_animation(\n        self,\n        warm_up: bool = True,\n        flow_speed: float = 1,\n        time_width: float = 0.3,\n        rate_func: Callable[[float], float] = linear,\n        line_animation_class: type[ShowPassingFlash] = ShowPassingFlash,\n        **kwargs,\n    ) -> None:\n        \"\"\"Animates the stream lines using an updater.\n\n        The stream lines will continuously flow\n\n        Parameters\n        ----------\n        warm_up\n            If `True` the animation is initialized line by line. Otherwise it starts with all lines shown.\n        flow_speed\n            At `flow_speed=1` the distance the flow moves per second is equal to the magnitude of the vector field along its path. The speed value scales the speed of this flow.\n        time_width\n            The proportion of the stream line shown while being animated\n        rate_func\n            The rate function of each stream line flashing\n        line_animation_class\n            The animation class being used\n\n        Examples\n        --------\n\n        .. manim:: ContinuousMotion\n\n            class ContinuousMotion(Scene):\n                def construct(self):\n                    func = lambda pos: np.sin(pos[0] / 2) * UR + np.cos(pos[1] / 2) * LEFT\n                    stream_lines = StreamLines(func, stroke_width=3, max_anchors_per_line=30)\n                    self.add(stream_lines)\n                    stream_lines.start_animation(warm_up=False, flow_speed=1.5)\n                    self.wait(stream_lines.virtual_time / stream_lines.flow_speed)\n\n        \"\"\"\n        for line in self.stream_lines:\n            run_time = line.duration / flow_speed\n            line.anim = line_animation_class(\n                line,\n                run_time=run_time,\n                rate_func=rate_func,\n                time_width=time_width,\n                **kwargs,\n            )\n            line.anim.begin()\n            line.time = random.random() * self.virtual_time\n            if warm_up:\n                line.time *= -1\n            self.add(line.anim.mobject)\n\n        def updater(mob, dt):\n            for line in mob.stream_lines:\n                line.time += dt * flow_speed\n                if line.time >= self.virtual_time:\n                    line.time -= self.virtual_time\n                line.anim.interpolate(np.clip(line.time / line.anim.run_time, 0, 1))\n\n        self.add_updater(updater)\n        self.flow_animation = updater\n        self.flow_speed = flow_speed\n        self.time_width = time_width\n\n    def end_animation(self) -> AnimationGroup:\n        \"\"\"End the stream line animation smoothly.\n\n        Returns an animation resulting in fully displayed stream lines without a noticeable cut.\n\n        Returns\n        -------\n        :class:`~.AnimationGroup`\n            The animation fading out the running stream animation.\n\n        Raises\n        ------\n        ValueError\n            if no stream line animation is running\n\n        Examples\n        --------\n\n        .. manim:: EndAnimation\n\n            class EndAnimation(Scene):\n                def construct(self):\n                    func = lambda pos: np.sin(pos[0] / 2) * UR + np.cos(pos[1] / 2) * LEFT\n                    stream_lines = StreamLines(\n                        func, stroke_width=3, max_anchors_per_line=5, virtual_time=1, color=BLUE\n                    )\n                    self.add(stream_lines)\n                    stream_lines.start_animation(warm_up=False, flow_speed=1.5, time_width=0.5)\n                    self.wait(1)\n                    self.play(stream_lines.end_animation())\n\n        \"\"\"\n        if self.flow_animation is None:\n            raise ValueError(\"You have to start the animation before fading it out.\")\n\n        def hide_and_wait(mob, alpha):\n            if alpha == 0:\n                mob.set_stroke(opacity=0)\n            elif alpha == 1:\n                mob.set_stroke(opacity=1)\n\n        def finish_updater_cycle(line, alpha):\n            line.time += dt * self.flow_speed\n            line.anim.interpolate(min(line.time / line.anim.run_time, 1))\n            if alpha == 1:\n                self.remove(line.anim.mobject)\n                line.anim.finish()\n\n        max_run_time = self.virtual_time / self.flow_speed\n        creation_rate_func = ease_out_sine\n        creation_staring_speed = creation_rate_func(0.001) * 1000\n        creation_run_time = (\n            max_run_time / (1 + self.time_width) * creation_staring_speed\n        )\n        # creation_run_time is calculated so that the creation animation starts at the same speed\n        # as the regular line flash animation but eases out.\n\n        dt = 1 / config[\"frame_rate\"]\n        animations = []\n        self.remove_updater(self.flow_animation)\n        self.flow_animation = None\n\n        for line in self.stream_lines:\n            create = Create(\n                line,\n                run_time=creation_run_time,\n                rate_func=creation_rate_func,\n            )\n            if line.time <= 0:\n                animations.append(\n                    Succession(\n                        UpdateFromAlphaFunc(\n                            line,\n                            hide_and_wait,\n                            run_time=-line.time / self.flow_speed,\n                        ),\n                        create,\n                    ),\n                )\n                self.remove(line.anim.mobject)\n                line.anim.finish()\n            else:\n                remaining_time = max_run_time - line.time / self.flow_speed\n                animations.append(\n                    Succession(\n                        UpdateFromAlphaFunc(\n                            line,\n                            finish_updater_cycle,\n                            run_time=remaining_time,\n                        ),\n                        create,\n                    ),\n                )\n        return AnimationGroup(*animations)\n\n\n# TODO: Variant of StreamLines that is able to respond to changes in the vector field function\n"
  },
  {
    "path": "manim/opengl/__init__.py",
    "content": "from __future__ import annotations\n\nimport contextlib\n\nwith contextlib.suppress(ImportError):\n    from dearpygui import dearpygui as dpg\n\n\nfrom manim.mobject.opengl.dot_cloud import *\nfrom manim.mobject.opengl.opengl_image_mobject import *\nfrom manim.mobject.opengl.opengl_mobject import *\nfrom manim.mobject.opengl.opengl_point_cloud_mobject import *\nfrom manim.mobject.opengl.opengl_surface import *\nfrom manim.mobject.opengl.opengl_three_dimensions import *\nfrom manim.mobject.opengl.opengl_vectorized_mobject import *\n\nfrom ..renderer.shader import *\nfrom ..utils.opengl import *\n"
  },
  {
    "path": "manim/plugins/__init__.py",
    "content": "from __future__ import annotations\n\nfrom manim._config import config, logger\nfrom manim.plugins.plugins_flags import get_plugins, list_plugins\n\n__all__ = [\n    \"get_plugins\",\n    \"list_plugins\",\n]\n\nrequested_plugins: set[str] = set(config[\"plugins\"])\nmissing_plugins = requested_plugins - set(get_plugins().keys())\n\n\nif missing_plugins:\n    logger.warning(\"Missing Plugins: %s\", missing_plugins)\n"
  },
  {
    "path": "manim/plugins/plugins_flags.py",
    "content": "\"\"\"Plugin Managing Utility\"\"\"\n\nfrom __future__ import annotations\n\nfrom importlib.metadata import entry_points\nfrom typing import Any\n\nfrom manim._config import console\n\n__all__ = [\"list_plugins\"]\n\n\ndef get_plugins() -> dict[str, Any]:\n    plugins: dict[str, Any] = {\n        entry_point.name: entry_point.load()\n        for entry_point in entry_points(group=\"manim.plugins\")\n    }\n    return plugins\n\n\ndef list_plugins() -> None:\n    console.print(\"[green bold]Plugins:[/green bold]\", justify=\"left\")\n\n    plugins = get_plugins()\n    for plugin_name in plugins:\n        console.print(f\" • {plugin_name}\")\n"
  },
  {
    "path": "manim/py.typed",
    "content": ""
  },
  {
    "path": "manim/renderer/__init__.py",
    "content": ""
  },
  {
    "path": "manim/renderer/cairo_renderer.py",
    "content": "from __future__ import annotations\n\nfrom collections.abc import Iterable\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom manim.utils.hashing import get_hash_from_play_call\n\nfrom .. import config, logger\nfrom ..camera.camera import Camera\nfrom ..mobject.mobject import Mobject, _AnimationBuilder\nfrom ..scene.scene_file_writer import SceneFileWriter\nfrom ..utils.exceptions import EndSceneEarlyException\nfrom ..utils.iterables import list_update\n\nif TYPE_CHECKING:\n    from manim.animation.animation import Animation\n    from manim.scene.scene import Scene\n\n    from ..typing import PixelArray\n\n__all__ = [\"CairoRenderer\"]\n\n\nclass CairoRenderer:\n    \"\"\"A renderer using Cairo.\n\n    Attributes\n    ----------\n    num_plays : int\n        Number of play() functions in the scene.\n\n    time : float\n        Time elapsed since initialisation of scene.\n    \"\"\"\n\n    def __init__(\n        self,\n        file_writer_class: type[SceneFileWriter] = SceneFileWriter,\n        camera_class: type[Camera] | None = None,\n        skip_animations: bool = False,\n        **kwargs: Any,\n    ):\n        # All of the following are set to EITHER the value passed via kwargs,\n        # OR the value stored in the global config dict at the time of\n        # _instance construction_.\n        self._file_writer_class = file_writer_class\n        camera_cls = camera_class if camera_class is not None else Camera\n        self.camera = camera_cls()\n        self._original_skipping_status = skip_animations\n        self.skip_animations = skip_animations\n        self.animations_hashes: list[str | None] = []\n        self.num_plays = 0\n        self.time = 0.0\n        self.static_image: PixelArray | None = None\n\n    def init_scene(self, scene: Scene) -> None:\n        self.file_writer: Any = self._file_writer_class(\n            self,\n            scene.__class__.__name__,\n        )\n\n    def play(\n        self,\n        scene: Scene,\n        *args: Animation | Mobject | _AnimationBuilder,\n        **kwargs: Any,\n    ) -> None:\n        # Reset skip_animations to the original state.\n        # Needed when rendering only some animations, and skipping others.\n        self.skip_animations = self._original_skipping_status\n        self.update_skipping_status()\n\n        scene.compile_animation_data(*args, **kwargs)\n\n        if self.skip_animations:\n            logger.debug(f\"Skipping animation {self.num_plays}\")\n            hash_current_animation = None\n            self.time += scene.duration\n        else:\n            if config[\"disable_caching\"]:\n                logger.info(\"Caching disabled.\")\n                hash_current_animation = f\"uncached_{self.num_plays:05}\"\n            else:\n                assert scene.animations is not None\n                hash_current_animation = get_hash_from_play_call(\n                    scene,\n                    self.camera,\n                    scene.animations,\n                    scene.mobjects,\n                )\n                if self.file_writer.is_already_cached(hash_current_animation):\n                    logger.info(\n                        f\"Animation {self.num_plays} : Using cached data (hash : %(hash_current_animation)s)\",\n                        {\"hash_current_animation\": hash_current_animation},\n                    )\n                    self.skip_animations = True\n                    self.time += scene.duration\n        # adding None as a partial movie file will make file_writer ignore the latter.\n        self.file_writer.add_partial_movie_file(hash_current_animation)\n        self.animations_hashes.append(hash_current_animation)\n        logger.debug(\n            \"List of the first few animation hashes of the scene: %(h)s\",\n            {\"h\": str(self.animations_hashes[:5])},\n        )\n\n        self.file_writer.begin_animation(not self.skip_animations)\n        scene.begin_animations()\n\n        # Save a static image, to avoid rendering non moving objects.\n        self.save_static_frame_data(scene, scene.static_mobjects)\n\n        if scene.is_current_animation_frozen_frame():\n            self.update_frame(scene, mobjects=scene.moving_mobjects)\n            # self.duration stands for the total run time of all the animations.\n            # In this case, as there is only a wait, it will be the length of the wait.\n            self.freeze_current_frame(scene.duration)\n        else:\n            scene.play_internal()\n        self.file_writer.end_animation(not self.skip_animations)\n\n        self.num_plays += 1\n\n    def update_frame(  # TODO Description in Docstring\n        self,\n        scene: Scene,\n        mobjects: Iterable[Mobject] | None = None,\n        include_submobjects: bool = True,\n        ignore_skipping: bool = True,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"Update the frame.\n\n        Parameters\n        ----------\n        scene\n\n        mobjects\n            list of mobjects\n\n        include_submobjects\n\n        ignore_skipping\n\n        **kwargs\n        \"\"\"\n        if self.skip_animations and not ignore_skipping:\n            return\n        if not mobjects:\n            mobjects = list_update(\n                scene.mobjects,\n                scene.foreground_mobjects,\n            )\n        if self.static_image is not None:\n            self.camera.set_frame_to_background(self.static_image)\n        else:\n            self.camera.reset()\n\n        kwargs[\"include_submobjects\"] = include_submobjects\n        self.camera.capture_mobjects(mobjects, **kwargs)\n\n    def render(\n        self,\n        scene: Scene,\n        time: float,\n        moving_mobjects: Iterable[Mobject] | None = None,\n    ) -> None:\n        self.update_frame(scene, moving_mobjects)\n        self.add_frame(self.get_frame())\n\n    def get_frame(self) -> PixelArray:\n        \"\"\"Gets the current frame as NumPy array.\n\n        Returns\n        -------\n        PixelArray\n            NumPy array of pixel values of each pixel in screen.\n            The shape of the array is height x width x 3.\n        \"\"\"\n        return np.array(self.camera.pixel_array)\n\n    def add_frame(self, frame: PixelArray, num_frames: int = 1) -> None:\n        \"\"\"Adds a frame to the video_file_stream\n\n        Parameters\n        ----------\n        frame\n            The frame to add, as a pixel array.\n        num_frames\n            The number of times to add frame.\n        \"\"\"\n        dt = 1 / self.camera.frame_rate\n        if self.skip_animations:\n            return\n        self.time += num_frames * dt\n        self.file_writer.write_frame(frame, num_frames=num_frames)\n\n    def freeze_current_frame(self, duration: float) -> None:\n        \"\"\"Adds a static frame to the movie for a given duration. The static frame is the current frame.\n\n        Parameters\n        ----------\n        duration\n            [description]\n        \"\"\"\n        dt = 1 / self.camera.frame_rate\n        self.add_frame(\n            self.get_frame(),\n            num_frames=int(duration / dt),\n        )\n\n    def show_frame(self, scene: Scene) -> None:\n        \"\"\"Opens the current frame in the Default Image Viewer\n        of your system.\n        \"\"\"\n        self.update_frame(scene, ignore_skipping=True)\n        self.camera.get_image().show()\n\n    def save_static_frame_data(\n        self,\n        scene: Scene,\n        static_mobjects: Iterable[Mobject],\n    ) -> PixelArray | None:\n        \"\"\"Compute and save the static frame, that will be reused at each frame\n        to avoid unnecessarily computing static mobjects.\n\n        Parameters\n        ----------\n        scene\n            The scene played.\n        static_mobjects\n            Static mobjects of the scene. If None, self.static_image is set to None.\n\n        Returns\n        -------\n        PixelArray | None\n            The static image computed. The return value is None if there are no static mobjects in the scene.\n        \"\"\"\n        self.static_image = None\n        if not static_mobjects:\n            return None\n        self.update_frame(scene, mobjects=static_mobjects)\n        self.static_image = self.get_frame()\n        return self.static_image\n\n    def update_skipping_status(self) -> None:\n        \"\"\"This method is used internally to check if the current\n        animation needs to be skipped or not. It also checks if\n        the number of animations that were played correspond to\n        the number of animations that need to be played, and\n        raises an EndSceneEarlyException if they don't correspond.\n        \"\"\"\n        # there is always at least one section -> no out of bounds here\n        if self.file_writer.sections[-1].skip_animations:\n            self.skip_animations = True\n        if config[\"save_last_frame\"]:\n            self.skip_animations = True\n        if (\n            config.from_animation_number > 0\n            and self.num_plays < config.from_animation_number\n        ):\n            self.skip_animations = True\n        if (\n            config.upto_animation_number >= 0\n            and self.num_plays > config.upto_animation_number\n        ):\n            self.skip_animations = True\n            raise EndSceneEarlyException()\n\n    def scene_finished(self, scene: Scene) -> None:\n        # If no animations in scene, render an image instead\n        if self.num_plays:\n            self.file_writer.finish()\n        elif config.write_to_movie:\n            config.save_last_frame = True\n            config.write_to_movie = False\n        else:\n            self.static_image = None\n            self.update_frame(scene)\n\n        if config[\"save_last_frame\"]:\n            self.static_image = None\n            self.update_frame(scene)\n            self.file_writer.save_image(self.camera.get_image())\n"
  },
  {
    "path": "manim/renderer/opengl_renderer.py",
    "content": "from __future__ import annotations\n\nimport contextlib\nimport itertools as it\nimport time\nimport typing\nfrom functools import cached_property\nfrom typing import TYPE_CHECKING, Any, Self\n\nimport moderngl\nimport numpy as np\nfrom moderngl import Framebuffer\nfrom PIL import Image\nfrom typing_extensions import override\n\nfrom manim import config, logger\nfrom manim.mobject.opengl.opengl_mobject import (\n    OpenGLMobject,\n    OpenGLPoint,\n)\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject\nfrom manim.typing import MatrixMN, Point3D\nfrom manim.utils.caching import handle_caching_play\nfrom manim.utils.color import color_to_rgba\nfrom manim.utils.exceptions import EndSceneEarlyException\nfrom manim.utils.paths import straight_path\n\nfrom ..constants import *\nfrom ..scene.scene_file_writer import SceneFileWriter\nfrom ..utils import opengl\nfrom ..utils.simple_functions import clip\nfrom ..utils.space_ops import (\n    angle_of_vector,\n    quaternion_from_angle_axis,\n    quaternion_mult,\n    rotation_matrix_transpose,\n    rotation_matrix_transpose_from_quaternion,\n)\nfrom .shader import Mesh, Shader\nfrom .vectorized_mobject_rendering import (\n    render_opengl_vectorized_mobject_fill,\n    render_opengl_vectorized_mobject_stroke,\n)\n\nif TYPE_CHECKING:\n    from collections.abc import Iterable\n    from typing import Self\n\n    from manim.animation.animation import Animation\n    from manim.mobject.mobject import Mobject, _AnimationBuilder\n    from manim.scene.scene import Scene\n    from manim.typing import (\n        FloatRGBA,\n        PathFuncType,\n        Point3DLike,\n        RGBAPixelArray,\n        Vector3DLike,\n    )\n    from manim.utils.color.core import ParsableManimColor\n    from manim.utils.opengl import FlattenedMatrix4x4\n\n    from .opengl_renderer_window import Window\n\n\n__all__ = [\"OpenGLCamera\", \"OpenGLRenderer\"]\n\n\nclass OpenGLCamera(OpenGLMobject):\n    \"\"\"\n    An OpenGL-based camera for 3D scene rendering.\n\n\n    Attributes\n    ----------\n    frame_shape : tuple[float, float]\n        The width and height of the camera frame.\n    center_point : np.ndarray\n        The center point of the camera in 3D space.\n    euler_angles : np.ndarray\n        The Euler angles (theta, phi, gamma) representing the camera's orientation.\n    focal_distance : float\n        The focal distance of the camera.\n    light_source_position : np.ndarray\n        The position of the light source in 3D space.\n    orthographic : bool\n        Whether the camera uses orthographic projection instead of perspective.\n    minimum_polar_angle : float\n        The minimum polar angle for camera rotation.\n    maximum_polar_angle : float\n        The maximum polar angle for camera rotation.\n    inverse_rotation_matrix : np.ndarray\n        The inverse rotation matrix of the camera.\n    \"\"\"\n\n    def __init__(\n        self,\n        frame_shape: tuple[float, float] | None = None,\n        center_point: Point3DLike | None = None,\n        # Theta, phi, gamma\n        euler_angles: Point3DLike | None = None,\n        focal_distance: float = 2.0,\n        light_source_position: Point3DLike | None = None,\n        orthographic: bool = False,\n        minimum_polar_angle: float = -PI / 2,\n        maximum_polar_angle: float = PI / 2,\n        model_matrix: MatrixMN | None = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Initializes an OpenGLCamera instance.\n\n        Parameters\n        ----------\n        frame_shape : tuple[float, float], optional\n            The width and height of the camera frame. If not provided, defaults to\n            the global manim config values `frame_width` and `frame_height`.\n        center_point : Point3DLike, optional\n            The center point of the camera in 3D space.\n            If not provided, defaults to the origin (0, 0, 0).\n        euler_angles : Point3DLike, optional\n            The Euler angles (theta, phi, gamma) representing the camera's orientation.\n            If not provided, defaults to (0, 0, 0) (i.e., no rotation).\n        focal_distance : float, optional\n            The focal distance of the camera. Default is 2.0.\n        light_source_position : Point3DLike, optional\n            The position of the light source in 3D space.\n            If not provided, defaults to (-10, 10, 10).\n        orthographic : bool, optional\n            Whether the camera uses orthographic projection instead of perspective.\n            Default is False (perspective).\n        minimum_polar_angle : float, optional\n            The minimum polar angle in radian for camera rotation. Default is -π/2,\n            i.e. no restriction.\n        maximum_polar_angle : float, optional\n            The maximum polar angle in radian for camera rotation. Default is π/2,\n            i.e. no restriction.\n        model_matrix : MatrixMN, optional\n            The initial model matrix [1]_ for the camera. If not provided,\n            defaults to a translation matrix that positions the camera at (0, 0, 11).\n        **kwargs : Any\n            Additional keyword arguments passed to the OpenGLMobject constructor.\n\n        References\n        ----------\n        .. [1] Wikipedia, \"Camera matrix\",\n               https://en.wikipedia.org/wiki/Camera_matrix\n        \"\"\"\n        self.use_z_index = True\n        self.frame_rate = 60\n        self.orthographic = orthographic\n        self.minimum_polar_angle = minimum_polar_angle\n        self.maximum_polar_angle = maximum_polar_angle\n        if self.orthographic:\n            self.projection_matrix = opengl.orthographic_projection_matrix()\n            self.unformatted_projection_matrix = opengl.orthographic_projection_matrix(\n                format_=False,\n            )\n        else:\n            self.projection_matrix = opengl.perspective_projection_matrix()\n            self.unformatted_projection_matrix = opengl.perspective_projection_matrix(\n                format_=False,\n            )\n\n        if frame_shape is None:\n            self.frame_shape = (config[\"frame_width\"], config[\"frame_height\"])\n        else:\n            self.frame_shape = frame_shape\n\n        if center_point is None:\n            self.center_point = ORIGIN\n        else:\n            self.center_point = np.asarray(center_point, dtype=float)\n\n        if model_matrix is None:\n            model_matrix = opengl.translation_matrix(0, 0, 11)\n\n        self.focal_distance = focal_distance\n\n        self.light_source_position = np.asarray(\n            light_source_position or [-10, 10, 10], dtype=float\n        )\n\n        self.light_source = OpenGLPoint(self.light_source_position)\n\n        self.default_model_matrix = model_matrix\n        super().__init__(model_matrix=model_matrix, should_render=False, **kwargs)\n\n        euler_angles = np.asarray(euler_angles or [0, 0, 0], dtype=float)\n\n        self.euler_angles: Point3D = euler_angles\n        self.refresh_rotation_matrix()\n\n    def get_position(self) -> Point3D:\n        \"\"\"Retrieve the camera's position in 3D space.\"\"\"\n        return self.model_matrix[:, 3][:3]\n\n    def set_position(self, position: Point3D) -> Self:\n        \"\"\"Set the camera's position in 3D space.\"\"\"\n        self.model_matrix[:, 3][:3] = position\n        return self\n\n    @cached_property\n    def formatted_view_matrix(self) -> FlattenedMatrix4x4:\n        \"\"\"The formatted view matrix for shader input.\"\"\"\n        return opengl.matrix_to_shader_input(self.unformatted_view_matrix)\n\n    @cached_property\n    def unformatted_view_matrix(self) -> MatrixMN:\n        return typing.cast(MatrixMN, np.linalg.inv(self.model_matrix))\n\n    def init_points(self) -> None:\n        \"\"\"Initialize the camera's points based on frame shape and center point.\"\"\"\n        self.set_points([ORIGIN, LEFT, RIGHT, DOWN, UP])\n        self.set_width(self.frame_shape[0], stretch=True)\n        self.set_height(self.frame_shape[1], stretch=True)\n        self.move_to(self.center_point)\n\n    def to_default_state(self) -> Self:\n        \"\"\"Reset the camera to its default state\n        (config frame size, centered at origin, no rotation).\n        \"\"\"\n        self.center()\n        self.set_height(config[\"frame_height\"])\n        self.set_width(config[\"frame_width\"])\n        self.set_euler_angles(0, 0, 0)\n        self.model_matrix = self.default_model_matrix\n        return self\n\n    def refresh_rotation_matrix(self) -> None:\n        \"\"\"Refresh the camera's inverse rotation matrix based on its Euler angles.\"\"\"\n        # Rotate based on camera orientation\n        theta, phi, gamma = self.euler_angles\n        quat = quaternion_mult(\n            quaternion_from_angle_axis(theta, OUT, axis_normalized=True),\n            quaternion_from_angle_axis(phi, RIGHT, axis_normalized=True),\n            quaternion_from_angle_axis(gamma, OUT, axis_normalized=True),\n        )\n        self.inverse_rotation_matrix = rotation_matrix_transpose_from_quaternion(\n            np.asarray(quat, dtype=float)\n        )\n\n    @override\n    def rotate(\n        self,\n        angle: float,\n        axis: Vector3DLike = OUT,\n        about_point: Point3DLike | None = None,\n        **kwargs: Any,\n    ) -> Self:\n        \"\"\"\n        Rotate the camera by a given angle around a specified axis.\n\n        Parameters\n        ----------\n        angle : float\n            The angle in radians to rotate the camera.\n        axis : Vector3DLike, optional\n            The axis around which to rotate the camera. Default is OUT (z-axis).\n        about_point : Point3DLike, optional\n            Ignored. For OpenGLCamera, rotation is always about the camera's center.\n\n        **kwargs : Any\n            Not used for OpenGLCamera. Passing additional keyword arguments\n            has no effect.\n\n        Returns\n        -------\n        Self\n            The rotated camera instance. Returned for chaining.\n        \"\"\"\n        curr_rot_T = self.inverse_rotation_matrix\n        added_rot_T = rotation_matrix_transpose(angle, axis)\n        new_rot_T = np.dot(curr_rot_T, added_rot_T)\n        Fz = new_rot_T[2]\n        phi = np.arccos(Fz[2])\n        theta = angle_of_vector(Fz[:2]) + PI / 2\n        partial_rot_T = np.dot(\n            rotation_matrix_transpose(phi, RIGHT),\n            rotation_matrix_transpose(theta, OUT),\n        )\n        gamma = angle_of_vector(np.dot(partial_rot_T, new_rot_T.T)[:, 0])\n        self.set_euler_angles(theta, phi, gamma)\n        return self\n\n    def set_euler_angles(\n        self,\n        theta: float | None = None,\n        phi: float | None = None,\n        gamma: float | None = None,\n    ) -> Self:\n        \"\"\"\n        Set the camera's Euler angles [1]_ (theta, phi, gamma).\n\n        Parameters\n        ----------\n        theta : float | None, optional\n            The angle in radians for rotation around the OUT (z) axis.\n            If None, the current theta value is retained.\n        phi : float | None, optional\n            The angle in radians for rotation around the RIGHT (x) axis.\n            If None, the current phi value is retained.\n        gamma : float | None, optional\n            The angle in radians for rotation around the OUT (z) axis.\n            If None, the current gamma value is retained.\n\n        Returns\n        -------\n        Self\n            The camera instance with updated Euler angles. Returned for chaining.\n\n        See Also\n        --------\n        set_theta : Set the theta Euler angle.\n        set_phi : Set the phi Euler angle.\n        set_gamma : Set the gamma Euler angle.\n\n        References\n        ----------\n        .. [1] Wikipedia, \"Euler angles\",\n               https://en.wikipedia.org/wiki/Euler_angles\n        \"\"\"\n        if theta is not None:\n            self.euler_angles[0] = theta\n        if phi is not None:\n            self.euler_angles[1] = phi\n        if gamma is not None:\n            self.euler_angles[2] = gamma\n        self.refresh_rotation_matrix()\n        return self\n\n    def set_theta(self, theta: float) -> Self:\n        \"\"\"\n        Set the camera's theta Euler angle (in radians).\n\n        See Also\n        --------\n        set_euler_angles : Set all Euler angles at once.\n        set_phi : Set the phi Euler angle.\n        set_gamma : Set the gamma Euler angle.\n        \"\"\"\n        return self.set_euler_angles(theta=theta)\n\n    def set_phi(self, phi: float) -> Self:\n        \"\"\"\n        Set the camera's phi Euler angle (in radians).\n\n        See Also\n        --------\n        set_euler_angles : Set all Euler angles at once.\n        set_theta : Set the theta Euler angle.\n        set_gamma : Set the gamma Euler angle.\n        \"\"\"\n        return self.set_euler_angles(phi=phi)\n\n    def set_gamma(self, gamma: float) -> Self:\n        \"\"\"\n        Set the camera's gamma Euler angle (in radians).\n\n        See Also\n        --------\n        set_euler_angles : Set all Euler angles at once.\n        set_theta : Set the theta Euler angle.\n        set_phi : Set the phi Euler angle.\n        \"\"\"\n        return self.set_euler_angles(gamma=gamma)\n\n    def increment_theta(self, dtheta: float) -> Self:\n        \"\"\"\n        Increment the camera's theta Euler angle by a given amount (in radians).\n\n        See Also\n        --------\n        set_euler_angles : Set all Euler angles at once.\n        set_theta : Set the theta Euler angle.\n        \"\"\"\n        self.euler_angles[0] += dtheta\n        self.refresh_rotation_matrix()\n        return self\n\n    def increment_phi(self, dphi: float) -> Self:\n        \"\"\"\n        Increment the camera's phi Euler angle by a given amount (in radians).\n\n        See Also\n        --------\n        set_euler_angles : Set all Euler angles at once.\n        set_phi : Set the phi Euler angle.\n        \"\"\"\n        phi = self.euler_angles[1]\n        new_phi = clip(phi + dphi, -PI / 2, PI / 2)\n        self.euler_angles[1] = new_phi\n        self.refresh_rotation_matrix()\n        return self\n\n    def increment_gamma(self, dgamma: float) -> Self:\n        \"\"\"\n        Increment the camera's gamma Euler angle by a given amount (in radians).\n\n        See Also\n        --------\n        set_euler_angles : Set all Euler angles at once.\n        set_gamma : Set the gamma Euler angle.\n        \"\"\"\n        self.euler_angles[2] += dgamma\n        self.refresh_rotation_matrix()\n        return self\n\n    def get_shape(self) -> tuple[float, float]:\n        \"\"\"Retrieve the width and height of the camera frame.\"\"\"\n        return (self.get_width(), self.get_height())\n\n    def get_center(self) -> Point3D:\n        \"\"\"\n        Retrieve the center point of the camera in 3D space.\n\n        Notes\n        -----\n        The center point is assumed to be the first point in the camera's points array.\n        \"\"\"\n        # Assumes first point is at the center\n        return typing.cast(Point3D, self.points[0])\n\n    def get_width(self) -> float:\n        \"\"\"Retrieve the width of the camera frame.\"\"\"\n        points = self.points\n        out = points[2, 0] - points[1, 0]\n        return float(out)\n\n    def get_height(self) -> float:\n        \"\"\"Retrieve the height of the camera frame.\"\"\"\n        points = self.points\n        out = points[4, 1] - points[3, 1]\n        return float(out)\n        # return points[4, 1] - points[3, 1]\n\n    def get_focal_distance(self) -> float:\n        \"\"\"Retrieve the focal distance of the camera.\"\"\"\n        return self.focal_distance * self.get_height()\n\n    @override\n    def interpolate(\n        self,\n        mobject1: OpenGLMobject,\n        mobject2: OpenGLMobject,\n        alpha: float,\n        path_func: PathFuncType = straight_path(),\n    ) -> Self:\n        super().interpolate(mobject1, mobject2, alpha, path_func)\n        self.refresh_rotation_matrix()\n        return self\n\n\nclass OpenGLRenderer:\n    \"\"\"\n    An OpenGL-based renderer.\n\n    Attributes\n    ----------\n    animation_elapsed_time : float\n        The elapsed time of the current animation.\n    animation_start_time : float\n        The start time of the current animation.\n    animations_hashes : list[str | None]\n        List of animation hashes for caching.\n    anti_alias_width : float\n        The width used for anti-aliasing in pixel units.\n    background_color : FloatRGBA\n        The background color of the renderer.\n    camera : OpenGLCamera\n        The camera used for rendering.\n    num_plays : float\n        The number of animation plays executed.\n    path_to_texture_id : dict[str, int]\n        Mapping from texture file paths to OpenGL texture IDs.\n    pressed_keys : set[int]\n        Set of currently pressed key codes.\n    skip_animations : bool\n        Whether animations are currently being skipped.\n    time : float\n        The total elapsed time for the renderer.\n    window : Window | None\n        The window used for previewing, if any.\n    \"\"\"\n\n    def __init__(\n        self,\n        file_writer_class: type[SceneFileWriter] = SceneFileWriter,\n        skip_animations: bool = False,\n    ) -> None:\n        \"\"\"Initializes the OpenGLRenderer.\n\n        Parameters\n        ----------\n        file_writer_class : type[SceneFileWriter], optional\n            The class to use for writing scene files, by default SceneFileWriter.\n        skip_animations : bool, optional\n            Whether to skip animations during rendering, by default False.\n        \"\"\"\n        # Measured in pixel widths, used for vector graphics\n        self.anti_alias_width = 1.5\n        self._file_writer_class = file_writer_class\n\n        self._original_skipping_status = skip_animations\n        self.skip_animations = skip_animations\n        self.animation_start_time = 0.0\n        self.animation_elapsed_time = 0.0\n        self.time = 0.0\n        self.animations_hashes: list[str | None] = []\n        self.num_plays = 0\n\n        self.camera = OpenGLCamera()\n        self.pressed_keys: set[int] = set()\n        self.window: Window | None = None\n        self.path_to_texture_id: dict[str, int] = {}\n        self.background_color = config[\"background_color\"]\n\n    def init_scene(self, scene: Scene) -> None:\n        \"\"\"\n        Initializes the OpenGL rendering context and related resources\n        for the given scene.\n\n        Set up:\n        - the file writer\n        - the background color\n        - the OpenGL context\n        - the window (if needed)\n\n        Parameters\n        ----------\n        scene : Scene\n            The scene to be rendered\n        \"\"\"\n        self.partial_movie_files: list[str | None] = []\n        self.file_writer: SceneFileWriter = self._file_writer_class(\n            self,\n            scene.__class__.__name__,\n        )\n        self.scene = scene\n\n        self.background_color = config[\"background_color\"]\n        if self.should_create_window():\n            from .opengl_renderer_window import Window\n\n            self.window = Window(self)\n            self.context = self.window.ctx\n            self.frame_buffer_object = self.context.detect_framebuffer()\n        else:\n            # self.window = None\n            try:\n                self.context = moderngl.create_context(standalone=True)\n            except Exception:\n                self.context = moderngl.create_context(\n                    standalone=True,\n                    backend=\"egl\",\n                )\n            self.frame_buffer_object = self.get_frame_buffer_object(self.context, 0)\n            self.frame_buffer_object.use()\n        self.context.enable(moderngl.BLEND)\n        self.context.wireframe = config[\"enable_wireframe\"]\n        self.context.blend_func = (\n            moderngl.SRC_ALPHA,\n            moderngl.ONE_MINUS_SRC_ALPHA,\n            moderngl.ONE,\n            moderngl.ONE,\n        )\n\n    def should_create_window(self) -> bool:\n        \"\"\"\n        Determine whether a window should be created for rendering\n        based on the current configuration.\n\n        Notes\n        -----\n        A windows is always created if the 'force_window' configuration is enabled.\n        \"\"\"\n        if config[\"force_window\"]:\n            logger.warning(\n                \"'--force_window' is enabled, this is intended for debugging purposes \"\n                \"and may impact performance if used when outputting files\",\n            )\n            return True\n        return (\n            config[\"preview\"]\n            and not config[\"save_last_frame\"]\n            and not config[\"format\"]\n            and not config[\"write_to_movie\"]\n            and not config[\"dry_run\"]\n        )\n\n    def get_pixel_shape(self) -> tuple[int, int] | None:\n        \"\"\"\n        Retrieve the pixel dimensions of the current frame buffer object (2D).\n\n        Returns\n        -------\n        width : int\n            The width of the frame buffer in pixels.\n        height : int\n            The height of the frame buffer in pixels.\n        \"\"\"\n        frame_buffer: Framebuffer | None = getattr(self, \"frame_buffer_object\", None)\n        if frame_buffer is None:\n            return None\n        _, _, pixel_width, pixel_height = frame_buffer.viewport\n        return pixel_width, pixel_height\n\n    def refresh_perspective_uniforms(self, camera: OpenGLCamera) -> None:\n        \"\"\"\n        Update the perspective-related uniform variables used in the\n        OpenGL renderer based on the current camera settings.\n\n        Parameters\n        ----------\n        camera : OpenGLCamera\n            The camera object from which to extract perspective and lighting information.\n\n        Raises\n        ------\n        ValueError\n            If the renderer's pixel shape is not available.\n        \"\"\"\n        pixel_shape = self.get_pixel_shape()\n        if pixel_shape is None:\n            msg = \"Pixel shape is None, cannot refresh perspective uniforms.\"\n            raise ValueError(msg)\n\n        pixel_width, pixel_height = pixel_shape\n        frame_width, frame_height = camera.get_shape()\n        # TODO, this should probably be a mobject uniform, with\n        # the camera taking care of the conversion factor\n        anti_alias_width = self.anti_alias_width / (pixel_height / frame_height)\n        # Orient light\n        rotation = camera.inverse_rotation_matrix\n        light_pos: Point3D = camera.light_source.get_location()\n        light_pos = np.dot(rotation, light_pos)\n\n        self.perspective_uniforms = {\n            \"frame_shape\": camera.get_shape(),\n            \"anti_alias_width\": anti_alias_width,\n            \"camera_center\": tuple(camera.get_center()),\n            \"camera_rotation\": tuple(np.array(rotation).T.flatten()),\n            \"light_source_position\": tuple(light_pos),\n            \"focal_distance\": camera.get_focal_distance(),\n        }\n\n    def render_mobject(self, mobject: OpenGLMobject | OpenGLVMobject) -> None:\n        \"\"\"\n        Render an OpenGL mobject (either OpenGLMobject or OpenGLVMobject)\n        using the appropriate shaders and rendering pipeline.\n\n        Parameters\n        ----------\n        mobject : OpenGLMobject | OpenGLVMobject\n            The mobject to render. Must be an instance of OpenGLMobject or OpenGLVMobject.\n\n        Raises\n        ------\n        TypeError\n            If a shader texture is not a moderngl.Uniform or moderngl.UniformBlock.\n        \"\"\"\n        if isinstance(mobject, OpenGLVMobject):\n            if config[\"use_projection_fill_shaders\"]:\n                render_opengl_vectorized_mobject_fill(self, mobject)\n\n            if config[\"use_projection_stroke_shaders\"]:\n                render_opengl_vectorized_mobject_stroke(self, mobject)\n\n        shader_wrapper_list = mobject.get_shader_wrapper_list()\n        # Convert ShaderWrappers to Meshes.\n        for shader_wrapper in shader_wrapper_list:\n            folder = shader_wrapper.shader_folder\n            shader = Shader(\n                context=self.context, name=str(folder) if folder is not None else None\n            )\n\n            # Set textures.\n            for name, path in shader_wrapper.texture_paths.items():\n                tid = self.get_texture_id(str(path))\n                shader_texture = shader.shader_program[name]\n                if not isinstance(\n                    shader_texture, (moderngl.Uniform, moderngl.UniformBlock)\n                ):\n                    msg = (\n                        f\"Shader texture must be a uniform, got {type(shader_texture)}\"\n                    )\n                    raise TypeError(msg)\n                shader_texture.value = tid\n\n            # Set uniforms.\n            for name, value in it.chain(\n                shader_wrapper.uniforms.items(),\n                self.perspective_uniforms.items(),\n            ):\n                with contextlib.suppress(KeyError):\n                    shader.set_uniform(name, value)\n            try:\n                # TODO: make the type of 'camera' generic in the 'Scene' class\n                # to avoid the cast here\n                cam = typing.cast(\"OpenGLCamera\", self.scene.camera)\n                shader.set_uniform(\"u_view_matrix\", cam.formatted_view_matrix)\n                shader.set_uniform(\"u_projection_matrix\", cam.projection_matrix)\n            except KeyError:\n                pass\n\n            # Set depth test.\n            if shader_wrapper.depth_test:\n                self.context.enable(moderngl.DEPTH_TEST)\n            else:\n                self.context.disable(moderngl.DEPTH_TEST)\n\n            # Render.\n            vert_indices = shader_wrapper.vert_indices\n            mesh = Mesh(\n                shader,\n                shader_wrapper.vert_data,\n                indices=np.asarray(vert_indices) if vert_indices is not None else None,\n                use_depth_test=shader_wrapper.depth_test,\n                primitive=mobject.render_primitive,\n            )\n            mesh.set_uniforms(self)\n            mesh.render()\n\n    def get_texture_id(self, path: str) -> int:\n        \"\"\"\n        Retrieves the OpenGL texture ID associated with the given image file path.\n\n        Automatically creates a new texture it it has not been loaded before.\n\n        Parameters\n        ----------\n        path : str\n            The file path to the texture image.\n\n        Returns\n        -------\n        int\n            The OpenGL texture ID corresponding to the given path.\n        \"\"\"\n        return (\n            self.path_to_texture_id[path]\n            if path in self.path_to_texture_id\n            else self._create_texture(path)\n        )\n\n    def _create_texture(self, image_path: str) -> int:\n        \"\"\"\n        Create an OpenGL texture from the given image file path, get its texture ID,\n        and store it in `self.path_to_texture_id[image_path]`.\n\n        Parameters\n        ----------\n        image_path : str\n            The file path to the image to be loaded as a texture.\n\n        Returns\n        -------\n        int\n            The texture ID assigned to the newly created texture.\n        \"\"\"\n        with Image.open(image_path) as img:\n            tid = len(self.path_to_texture_id)\n\n            # grayscale image\n            if img.mode == \"L\":\n                components = 1\n                swizzle = \"RRR1\"\n            else:\n                # convert everything to RGBA for consistency\n                img = img.convert(\"RGBA\")\n                components = 4\n                swizzle = \"RGBA\"\n\n            texture = self.context.texture(\n                size=img.size,\n                components=components,\n                data=img.tobytes(),\n            )\n        texture.repeat_x = False\n        texture.repeat_y = False\n        texture.filter = (moderngl.NEAREST, moderngl.NEAREST)\n        texture.swizzle = swizzle\n        texture.use(location=tid)\n        self.path_to_texture_id[image_path] = tid\n        return tid\n\n    def update_skipping_status(self) -> None:\n        \"\"\"\n        Check and update the skipping status for the current animation\n        (self.skip_animations flag) based on the configuration settings.\n\n        Parameters\n        ----------\n        None\n\n        Raises\n        ------\n        EndSceneEarlyException\n            If the number of played animations exceeds the configured upper bound.\n        \"\"\"\n        # there is always at least one section -> no out of bounds here\n        if self.file_writer.sections[-1].skip_animations:\n            self.skip_animations = True\n        if (\n            config.from_animation_number > 0\n            and self.num_plays < config.from_animation_number\n        ):\n            self.skip_animations = True\n        if (\n            config.upto_animation_number >= 0\n            and self.num_plays > config.upto_animation_number\n        ):\n            self.skip_animations = True\n            raise EndSceneEarlyException()\n\n    @handle_caching_play\n    def play(\n        self,\n        scene: Scene,\n        *animations: Animation | Mobject | _AnimationBuilder,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Plays the given animations or mobjects in the specified scene.\n\n        \"Playing\" here refers to the process of compiling animation data,\n        beginning the animations, updating frames, and finalizing the animation\n        in the context of the renderer.\n\n        Parameters\n        ----------\n        scene Scene\n            The scene in which to play the animations.\n        *animations Animation | Mobject | _AnimationBuilder\n            The animations, mobjects, or animation builders to play.\n        **kwargs Any\n            Additional keyword arguments to pass to the animation compilation.\n        \"\"\"\n        # TODO: Handle data locking / unlocking.\n        self.animation_start_time = time.time()\n        self.file_writer.begin_animation(not self.skip_animations)\n\n        scene.compile_animation_data(*animations, **kwargs)\n        scene.begin_animations()\n        if scene.is_current_animation_frozen_frame():\n            self.update_frame(scene)\n\n            if not self.skip_animations:\n                self.file_writer.write_frame(\n                    self, num_frames=int(config.frame_rate * scene.duration)\n                )\n\n            if self.window is not None:\n                self.window.swap_buffers()\n                while time.time() - self.animation_start_time < scene.duration:\n                    pass\n            self.animation_elapsed_time = scene.duration\n\n        else:\n            scene.play_internal()\n\n        self.file_writer.end_animation(not self.skip_animations)\n        self.time += scene.duration\n        self.num_plays += 1\n\n    def clear_screen(self) -> None:\n        \"\"\"\n        Clears the current frame buffer and updates the display window\n        accordingly.\n\n        The screen is cleared using the background color specified\n        in the renderer.\n        \"\"\"\n        self.frame_buffer_object.clear(*self.background_color)\n        if self.window is None:\n            return\n        self.window.swap_buffers()\n\n    def render(\n        self, scene: Scene, frame_offset: float, moving_mobjects: list[Mobject]\n    ) -> None:\n        \"\"\"\n        Renders a single frame of the given scene using OpenGL.\n\n        Parameters\n        ----------\n        scene : Scene\n            The scene to render.\n        frame_offset : float\n            The time offset for the current frame in seconds. If no window is present,\n            this parameter is ignored, and a frame is a true snapshot of\n            the scene at the current time.\n        moving_mobjects : list[Mobject]\n            List of mobjects that are currently moving and need to be updated.\n            Not used at all, kept for compatibility with other renderers.\n\n        Notes\n        -----\n        - Updates the frame for the scene.\n        - If animations are skipped, the method returns early.\n        - Writes the current frame using the file writer.\n        - If a window is present, swaps buffers and continues\n          updating frames until the animation elapsed time reaches the frame offset.\n        \"\"\"\n        self.update_frame(scene)\n\n        if self.skip_animations:\n            return\n\n        self.file_writer.write_frame(self)\n\n        if self.window is not None:\n            self.window.swap_buffers()\n            while self.animation_elapsed_time < frame_offset:\n                self.update_frame(scene)\n                self.window.swap_buffers()\n\n    def update_frame(self, scene: Scene) -> None:\n        \"\"\"\n        Update and render the current frame for the given scene.\n\n        Performs the following steps:\n        1. Clear the frame buffer with the background color.\n        2. Refresh camera perspective uniforms for rendering.\n        3. Iterate through all mobjects in the scene, rendering those marked for display.\n        4. Iterate through all mesh objects in the scene, setting their uniforms and rendering them.\n        5. Update the elapsed animation time.\n\n        Parameters\n        ----------\n        scene : Scene\n            The scene to render the frame for.\n        \"\"\"\n        self.frame_buffer_object.clear(*self.background_color)\n\n        # TODO: make the type of 'camera' generic in the 'Scene' class\n        # to avoid the cast here\n        cam = typing.cast(\"OpenGLCamera\", scene.camera)\n        self.refresh_perspective_uniforms(cam)\n\n        for mobject in scene.mobjects:\n            if not mobject.should_render:\n                continue\n\n            # TODO: make the type of 'mobject' generic in the 'Scene' class\n            # to avoid the cast here\n            mobj = typing.cast(\"OpenGLMobject | OpenGLVMobject\", mobject)\n            self.render_mobject(mobj)\n\n        for obj in scene.meshes:\n            for mesh in obj.get_meshes():\n                mesh.set_uniforms(self)\n                mesh.render()\n\n        self.animation_elapsed_time = time.time() - self.animation_start_time\n\n    def scene_finished(self, scene: Scene) -> None:\n        \"\"\"\n        Handle the finalization process after a scene has finished rendering.\n\n        Performs the following actions:\n        - If any plays (animations) have occurred, finalizes the file writing process.\n        - If no plays have occurred but movie writing is enabled, disables\n          movie writing to avoid creating an empty movie file.\n        - If the configuration requires saving the last frame,\n          updates and saves the final image of the scene.\n\n        Parameters\n        ----------\n        scene : Scene\n            The scene that has finished rendering.\n        \"\"\"\n        # When num_plays is 0, no images have been output, so output a single\n        # image in this case\n        if self.num_plays > 0:\n            self.file_writer.finish()\n        elif self.num_plays == 0 and config.write_to_movie:\n            config.write_to_movie = False\n\n        if self.should_save_last_frame():\n            config.save_last_frame = True\n            self.update_frame(scene)\n            self.file_writer.save_image(self.get_image())\n\n    def should_save_last_frame(self) -> bool:\n        \"\"\"\n        Determine whether the last frame of the scene should be saved,\n        i.e. if one of the following conditions is met:\n        - The configuration option 'save_last_frame' is enabled.\n        - The scene is not in interactive mode.\n        - This is the first play (i.e., num_plays == 0).\n        \"\"\"\n        if config[\"save_last_frame\"]:\n            return True\n        if self.scene.interactive_mode:\n            return False\n        return self.num_plays == 0\n\n    def get_image(self) -> Image.Image:\n        \"\"\"\n        Get the current OpenGL frame buffer as a PIL Image.\n\n        Returns\n        -------\n        Image.Image\n            The image representation of the current frame buffer.\n\n        Raises\n        ------\n        ValueError\n            If the pixel shape cannot be determined.\n\n        Notes\n        -----\n        The image is constructed from raw RGBA buffer data, with the\n        origin at the bottom-left.\n        \"\"\"\n        raw_buffer_data = self.get_raw_frame_buffer_object_data()\n        pixel_shape = self.get_pixel_shape()\n        if pixel_shape is None:\n            msg = \"Pixel shape is None, cannot get image.\"\n            raise ValueError(msg)\n\n        image = Image.frombytes(\n            \"RGBA\",  # mode (rgb, a for alpha (transparency)))\n            pixel_shape,  # size\n            raw_buffer_data,  # data\n            \"raw\",  # decoder_name\n            # *args for the decoder\n            \"RGBA\",  # raw mode\n            0,  # stride (O = no extra padding)\n            -1,  # orientation (-1 = bottom to top, 1 = top to bottom)\n        )\n        return image\n\n    def save_static_frame_data(\n        self, scene: Scene, static_mobjects: Iterable[Mobject]\n    ) -> None:\n        pass\n\n    def get_frame_buffer_object(\n        self, context: moderngl.Context, samples: int = 0\n    ) -> Framebuffer:\n        \"\"\"\n        Creates and returns a framebuffer object configured with color\n        and depth attachments.\n\n        Parameters\n        ----------\n        context : moderngl.Context\n            The ModernGL context used to create the framebuffer and\n            its attachments.\n        samples : int, optional\n            The number of samples for multisample anti-aliasing (MSAA)[1]_.\n            Default is 0 (no MSAA).\n\n        Returns\n        -------\n        Framebuffer\n            A framebuffer object with a color texture attachment and\n            a depth renderbuffer attachment, both sized according to\n            the current configuration's pixel width and height.\n\n        Notes\n        -----\n        Framebuffer's color attachment is supposed RGBA.\n        Pixel dimensions are taken from the global config of Manim.\n\n        References\n        ----------\n        .. [1] Wikipedia, \"Multisample anti-aliasing\",\n               https://en.wikipedia.org/wiki/Multisample_anti-aliasing\n        \"\"\"\n        pixel_width = config[\"pixel_width\"]\n        pixel_height = config[\"pixel_height\"]\n        num_channels = 4\n        return context.framebuffer(\n            color_attachments=context.texture(\n                (pixel_width, pixel_height),\n                components=num_channels,\n                samples=samples,\n            ),\n            depth_attachment=context.depth_renderbuffer(\n                (pixel_width, pixel_height),\n                samples=samples,\n            ),\n        )\n\n    def get_raw_frame_buffer_object_data(self, dtype: str = \"f1\") -> bytes:\n        \"\"\"\n        Get the raw data from the current frame buffer object as bytes.\n\n        This method reads the pixel data from the frame buffer object using the specified data type.\n        The data is read with 4 color channels (typically RGBA).\n\n        Args:\n            dtype (str, optional): The data type to use when reading the buffer.\n            Defaults to \"f1\" (i.e., float with 1 byte).\n\n        Returns:\n            bytes: The raw pixel data from the frame buffer object.\n        \"\"\"\n        # Copy blocks from the fbo_msaa to the drawn fbo using Blit\n        # pw, ph = self.get_pixel_shape()\n        # gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, self.fbo_msaa.glo)\n        # gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, self.fbo.glo)\n        # gl.glBlitFramebuffer(\n        #     0, 0, pw, ph, 0, 0, pw, ph, gl.GL_COLOR_BUFFER_BIT, gl.GL_LINEAR\n        # )\n        num_channels = 4\n        ret: bytes = self.frame_buffer_object.read(\n            viewport=self.frame_buffer_object.viewport,\n            components=num_channels,\n            dtype=dtype,\n        )\n        return ret\n\n    def get_frame(self) -> RGBAPixelArray:\n        \"\"\"\n        Get the current frame buffer as a Numpy array of RGBA pixel values.\n\n        Returns\n        -------\n        RGBAPixelArray\n            A Numpy array of shape (height, width, 4) containing the\n            RGBA pixel data of the current frame, with dtype uint8.\n\n        Raises\n        ------\n        ValueError\n            If the pixel shape cannot be determined.\n        \"\"\"\n        # get current pixel values as numpy data in order to test output\n        raw = self.get_raw_frame_buffer_object_data(dtype=\"f1\")\n        pixel_shape = self.get_pixel_shape()\n        if pixel_shape is None:\n            msg = \"Pixel shape is None, cannot get frame.\"\n            raise ValueError(msg)\n\n        result_dimensions = (pixel_shape[1], pixel_shape[0], 4)\n        np_buf = np.frombuffer(raw, dtype=\"uint8\").reshape(result_dimensions)\n        np_buf = np.flipud(np_buf)\n        return np_buf\n\n    # Returns offset from the bottom left corner in pixels.\n    # top_left flag should be set to True when using a GUI framework\n    # where the (0,0) is at the top left: e.g. PySide6\n    def pixel_coords_to_space_coords(\n        self, px: float, py: float, relative: bool = False, top_left: bool = False\n    ) -> Point3D:\n        \"\"\"\n        Converts pixel coordinates to space (scene) coordinates.\n\n        top_left flag should be set to True when using a GUI framework\n        where the (0,0) is at the top left: e.g. PySide6.\n\n        Parameters\n        ----------\n        px : float\n            The x-coordinate in pixel space.\n        py : float\n            The y-coordinate in pixel space.\n        relative : bool, optional\n            If True, returns coordinates relative to the frame (normalized to [-1, 1]).\n            If False, returns absolute space coordinates. Default is False.\n        top_left : bool, optional\n            If True, treats the origin (0, 0) as the top-left corner of the pixel space.\n            If False, treats the origin as the bottom-left. Default is False.\n\n        Returns\n        -------\n        Point3D\n            The corresponding coordinates in space as a NumPy array of shape (3,).\n\n        Notes\n        -----\n        If the pixel shape is not available, returns the origin [0, 0, 0].\n        \"\"\"\n        pixel_shape = self.get_pixel_shape()\n        if pixel_shape is None:\n            return typing.cast(Point3D, np.array([0.0, 0.0, 0.0]))\n        pixel_width, pixel_height = pixel_shape\n        frame_height = config[\"frame_height\"]\n        frame_center = self.camera.get_center()\n        if relative:\n            # relative -> just normalize to [-1, 1]\n            return 2 * np.array([px / pixel_width, py / pixel_height, 0])\n\n        scale = frame_height / pixel_height\n        y_direction = -1 if top_left else 1\n\n        return typing.cast(\n            Point3D,\n            frame_center\n            + scale\n            * np.array(\n                [(px - pixel_width / 2), y_direction * (py - pixel_height / 2), 0.0]\n            ),\n        )\n\n    @property\n    def background_color(self) -> FloatRGBA:\n        \"\"\"The background color of the renderer (RGBA format).\"\"\"\n        return self._background_color\n\n    @background_color.setter\n    def background_color(self, value: ParsableManimColor) -> None:\n        self._background_color = color_to_rgba(value, 1.0)\n"
  },
  {
    "path": "manim/renderer/opengl_renderer_window.py",
    "content": "from __future__ import annotations\n\nfrom typing import TYPE_CHECKING, Any\n\nimport moderngl_window as mglw\nfrom moderngl_window.context.pyglet.window import Window as PygletWindow\nfrom moderngl_window.timers.clock import Timer\nfrom screeninfo import Monitor, get_monitors\n\nfrom .. import __version__, config\n\nif TYPE_CHECKING:\n    from .opengl_renderer import OpenGLRenderer\n\n__all__ = [\"Window\"]\n\n\nclass Window(PygletWindow):\n    fullscreen = False\n    resizable = True\n    gl_version = (3, 3)\n    vsync = True\n    cursor = True\n\n    def __init__(\n        self,\n        renderer: OpenGLRenderer,\n        window_size: str | tuple[int, ...] = config.window_size,\n        **kwargs: Any,\n    ) -> None:\n        monitors = get_monitors()\n        mon_index = config.window_monitor\n        monitor = monitors[min(mon_index, len(monitors) - 1)]\n\n        invalid_window_size_error_message = (\n            \"window_size must be specified either as 'default', a string of the form \"\n            \"'width,height', or a tuple of 2 ints of the form (width, height).\"\n        )\n\n        if isinstance(window_size, tuple):\n            if len(window_size) != 2:\n                raise ValueError(invalid_window_size_error_message)\n            size = window_size\n        elif window_size == \"default\":\n            # make window_width half the width of the monitor\n            # but make it full screen if --fullscreen\n            window_width = monitor.width\n            if not config.fullscreen:\n                window_width //= 2\n\n            #  by default window_height = 9/16 * window_width\n            window_height = int(\n                window_width * config.frame_height // config.frame_width,\n            )\n            size = (window_width, window_height)\n        elif len(window_size.split(\",\")) == 2:\n            (window_width, window_height) = tuple(map(int, window_size.split(\",\")))\n            size = (window_width, window_height)\n        else:\n            raise ValueError(invalid_window_size_error_message)\n\n        super().__init__(size=size)\n\n        self.title = f\"Manim Community {__version__}\"\n        self.size = size\n        self.renderer = renderer\n\n        mglw.activate_context(window=self)\n        self.timer = Timer()\n        self.config = mglw.WindowConfig(ctx=self.ctx, wnd=self, timer=self.timer)\n        self.timer.start()\n\n        self.swap_buffers()\n\n        initial_position = self.find_initial_position(size, monitor)\n        self.position = initial_position\n\n    # Delegate event handling to scene.\n    def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> None:\n        super().on_mouse_motion(x, y, dx, dy)\n        point = self.renderer.pixel_coords_to_space_coords(x, y)\n        d_point = self.renderer.pixel_coords_to_space_coords(dx, dy, relative=True)\n        self.renderer.scene.on_mouse_motion(point, d_point)\n\n    def on_mouse_scroll(self, x: int, y: int, x_offset: float, y_offset: float) -> None:\n        super().on_mouse_scroll(x, y, x_offset, y_offset)\n        point = self.renderer.pixel_coords_to_space_coords(x, y)\n        offset = self.renderer.pixel_coords_to_space_coords(\n            x_offset,\n            y_offset,\n            relative=True,\n        )\n        self.renderer.scene.on_mouse_scroll(point, offset)\n\n    def on_key_press(self, symbol: int, modifiers: int) -> bool:\n        self.renderer.pressed_keys.add(symbol)\n        event_handled: bool = super().on_key_press(symbol, modifiers)\n        self.renderer.scene.on_key_press(symbol, modifiers)\n        return event_handled\n\n    def on_key_release(self, symbol: int, modifiers: int) -> None:\n        if symbol in self.renderer.pressed_keys:\n            self.renderer.pressed_keys.remove(symbol)\n        super().on_key_release(symbol, modifiers)\n        self.renderer.scene.on_key_release(symbol, modifiers)\n\n    def on_mouse_drag(\n        self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int\n    ) -> None:\n        super().on_mouse_drag(x, y, dx, dy, buttons, modifiers)\n        point = self.renderer.pixel_coords_to_space_coords(x, y)\n        d_point = self.renderer.pixel_coords_to_space_coords(dx, dy, relative=True)\n        self.renderer.scene.on_mouse_drag(point, d_point, buttons, modifiers)\n\n    def find_initial_position(\n        self, size: tuple[int, int], monitor: Monitor\n    ) -> tuple[int, int]:\n        custom_position = config.window_position\n        window_width, window_height = size\n        # Position might be specified with a string of the form x,y for integers x and y\n        if len(custom_position) == 1:\n            raise ValueError(\n                \"window_position must specify both Y and X positions (Y/X -> UR). Also accepts LEFT/RIGHT/ORIGIN/UP/DOWN.\",\n            )\n        # in the form Y/X (UR)\n        if custom_position in [\"LEFT\", \"RIGHT\"]:\n            custom_position = \"O\" + custom_position[0]\n        elif custom_position in [\"UP\", \"DOWN\"]:\n            custom_position = custom_position[0] + \"O\"\n        elif custom_position == \"ORIGIN\":\n            custom_position = \"O\" * 2\n        elif \",\" in custom_position:\n            pos_y, pos_x = tuple(map(int, custom_position.split(\",\")))\n            return (pos_x, pos_y)\n\n        # Alternatively, it might be specified with a string like\n        # UR, OO, DL, etc. specifying what corner it should go to\n        char_to_n = {\"L\": 0, \"U\": 0, \"O\": 1, \"R\": 2, \"D\": 2}\n        width_diff: int = monitor.width - window_width\n        height_diff: int = monitor.height - window_height\n\n        return (\n            monitor.x + char_to_n[custom_position[1]] * width_diff // 2,\n            -monitor.y + char_to_n[custom_position[0]] * height_diff // 2,\n        )\n\n    def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> None:\n        super().on_mouse_press(x, y, button, modifiers)\n        point = self.renderer.pixel_coords_to_space_coords(x, y)\n        mouse_button_map = {\n            1: \"LEFT\",\n            2: \"MOUSE\",\n            4: \"RIGHT\",\n        }\n        self.renderer.scene.on_mouse_press(point, mouse_button_map[button], modifiers)\n"
  },
  {
    "path": "manim/renderer/shader.py",
    "content": "from __future__ import annotations\n\nimport contextlib\nimport inspect\nimport re\nimport textwrap\nfrom collections.abc import Callable, Iterator, Sequence\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, Any, Self, TypeAlias\n\nimport moderngl\nimport numpy as np\nimport numpy.typing as npt\n\nif TYPE_CHECKING:\n    from manim.renderer.opengl_renderer import OpenGLRenderer\n\n    MeshTimeBasedUpdater: TypeAlias = Callable[[\"Object3D\", float], None]\n    MeshNonTimeBasedUpdater: TypeAlias = Callable[[\"Object3D\"], None]\n    MeshUpdater: TypeAlias = MeshNonTimeBasedUpdater | MeshTimeBasedUpdater\n\nfrom manim.typing import MatrixMN, Point3D\n\nfrom .. import config\nfrom ..utils import opengl\n\nSHADER_FOLDER = Path(__file__).parent / \"shaders\"\nshader_program_cache: dict[str, moderngl.Program] = {}\nfile_path_to_code_map: dict[Path, str] = {}\n\n__all__ = [\n    \"Object3D\",\n    \"Mesh\",\n    \"Shader\",\n    \"FullScreenQuad\",\n]\n\n\ndef get_shader_code_from_file(file_path: Path) -> str:\n    if file_path in file_path_to_code_map:\n        return file_path_to_code_map[file_path]\n    source = file_path.read_text()\n    include_lines = re.finditer(\n        r\"^#include (?P<include_path>.*\\.glsl)$\",\n        source,\n        flags=re.MULTILINE,\n    )\n    for match in include_lines:\n        include_path = match.group(\"include_path\")\n        included_code = get_shader_code_from_file(\n            file_path.parent / include_path,\n        )\n        source = source.replace(match.group(0), included_code)\n    file_path_to_code_map[file_path] = source\n    return source\n\n\ndef filter_attributes(\n    unfiltered_attributes: npt.NDArray, attributes: Sequence[str]\n) -> npt.NDArray:\n    # Construct attributes for only those needed by the shader.\n    filtered_attributes_dtype = []\n    for i, dtype_name in enumerate(unfiltered_attributes.dtype.names):\n        if dtype_name in attributes:\n            filtered_attributes_dtype.append(\n                (\n                    dtype_name,\n                    unfiltered_attributes.dtype[i].subdtype[0].str,\n                    unfiltered_attributes.dtype[i].shape,\n                ),\n            )\n\n    filtered_attributes = np.zeros(\n        unfiltered_attributes[unfiltered_attributes.dtype.names[0]].shape[0],\n        dtype=filtered_attributes_dtype,\n    )\n\n    for dtype_name in unfiltered_attributes.dtype.names:\n        if dtype_name in attributes:\n            filtered_attributes[dtype_name] = unfiltered_attributes[dtype_name]\n\n    return filtered_attributes\n\n\nclass Object3D:\n    def __init__(self, *children: Object3D):\n        self.model_matrix = np.eye(4)\n        self.normal_matrix = np.eye(4)\n        self.children: list[Object3D] = []\n        self.parent: Object3D | None = None\n        self.add(*children)\n        self.init_updaters()\n\n    # TODO: Use path_func.\n    def interpolate(self, start: Object3D, end: Object3D, alpha: float, _: Any) -> None:\n        self.model_matrix = (1 - alpha) * start.model_matrix + alpha * end.model_matrix\n        self.normal_matrix = (\n            1 - alpha\n        ) * start.normal_matrix + alpha * end.normal_matrix\n\n    def single_copy(self) -> Object3D:\n        copy = Object3D()\n        copy.model_matrix = self.model_matrix.copy()\n        copy.normal_matrix = self.normal_matrix.copy()\n        return copy\n\n    def copy(self) -> Object3D:\n        node_to_copy = {}\n\n        bfs = [self]\n        while bfs:\n            node = bfs.pop(0)\n            bfs.extend(node.children)\n\n            node_copy = node.single_copy()\n            node_to_copy[node] = node_copy\n\n            # Add the copy to the copy of the parent.\n            if node.parent is not None and node is not self:\n                node_to_copy[node.parent].add(node_copy)\n        return node_to_copy[self]\n\n    def add(self, *children: Object3D) -> None:\n        for child in children:\n            if child.parent is not None:\n                raise Exception(\n                    \"Attempt to add child that's already added to another Object3D\",\n                )\n        self.remove(*children, current_children_only=False)\n        self.children.extend(children)\n        for child in children:\n            child.parent = self\n\n    def remove(self, *children: Object3D, current_children_only: bool = True) -> None:\n        if current_children_only:\n            for child in children:\n                if child.parent != self:\n                    raise Exception(\n                        \"Attempt to remove child that isn't added to this Object3D\",\n                    )\n        self.children = list(filter(lambda child: child not in children, self.children))\n        for child in children:\n            child.parent = None\n\n    def get_position(self) -> Point3D:\n        return self.model_matrix[:, 3][:3]\n\n    def set_position(self, position: Point3D) -> Self:\n        self.model_matrix[:, 3][:3] = position\n        return self\n\n    def get_meshes(self) -> Iterator[Mesh]:\n        dfs = [self]\n        while dfs:\n            parent = dfs.pop()\n            if isinstance(parent, Mesh):\n                yield parent\n            dfs.extend(parent.children)\n\n    def get_family(self) -> Iterator[Object3D]:\n        dfs = [self]\n        while dfs:\n            parent = dfs.pop()\n            yield parent\n            dfs.extend(parent.children)\n\n    def align_data_and_family(self, _: Any) -> None:\n        pass\n\n    def hierarchical_model_matrix(self) -> MatrixMN:\n        if self.parent is None:\n            return self.model_matrix\n\n        model_matrices = [self.model_matrix]\n        current_object = self\n        while current_object.parent is not None:\n            model_matrices.append(current_object.parent.model_matrix)\n            current_object = current_object.parent\n        return np.linalg.multi_dot(list(reversed(model_matrices)))\n\n    def hierarchical_normal_matrix(self) -> MatrixMN:\n        if self.parent is None:\n            return self.normal_matrix[:3, :3]\n\n        normal_matrices = [self.normal_matrix]\n        current_object = self\n        while current_object.parent is not None:\n            normal_matrices.append(current_object.parent.model_matrix)\n            current_object = current_object.parent\n        return np.linalg.multi_dot(list(reversed(normal_matrices)))[:3, :3]\n\n    def init_updaters(self) -> None:\n        self.time_based_updaters: list[MeshTimeBasedUpdater] = []\n        self.non_time_updaters: list[MeshNonTimeBasedUpdater] = []\n        self.has_updaters = False\n        self.updating_suspended = False\n\n    def update(self, dt: float = 0) -> Self:\n        if not self.has_updaters or self.updating_suspended:\n            return self\n        for time_based_updater in self.time_based_updaters:\n            time_based_updater(self, dt)\n        for non_time_based_updater in self.non_time_updaters:\n            non_time_based_updater(self)\n        return self\n\n    def get_time_based_updaters(self) -> list[MeshTimeBasedUpdater]:\n        return self.time_based_updaters\n\n    def has_time_based_updater(self) -> bool:\n        return len(self.time_based_updaters) > 0\n\n    def get_updaters(self) -> list[MeshUpdater]:\n        return self.time_based_updaters + self.non_time_updaters\n\n    def add_updater(\n        self,\n        update_function: MeshUpdater,\n        index: int | None = None,\n        call_updater: bool = True,\n    ) -> Self:\n        if \"dt\" in inspect.signature(update_function).parameters:\n            self._add_time_based_updater(update_function, index)  # type: ignore[arg-type]\n        else:\n            self._add_non_time_updater(update_function, index)  # type: ignore[arg-type]\n\n        self.refresh_has_updater_status()\n        if call_updater:\n            self.update()\n        return self\n\n    def _add_time_based_updater(\n        self, update_function: MeshTimeBasedUpdater, index: int | None = None\n    ) -> None:\n        if index is None:\n            self.time_based_updaters.append(update_function)\n        else:\n            self.time_based_updaters.insert(index, update_function)\n\n    def _add_non_time_updater(\n        self, update_function: MeshNonTimeBasedUpdater, index: int | None = None\n    ) -> None:\n        if index is None:\n            self.non_time_updaters.append(update_function)\n        else:\n            self.non_time_updaters.insert(index, update_function)\n\n    def remove_updater(self, update_function: MeshUpdater) -> Self:\n        while update_function in self.time_based_updaters:\n            self.time_based_updaters.remove(update_function)  # type: ignore[arg-type]\n        while update_function in self.non_time_updaters:\n            self.non_time_updaters.remove(update_function)  # type: ignore[arg-type]\n        self.refresh_has_updater_status()\n        return self\n\n    def clear_updaters(self) -> Self:\n        self.time_based_updaters = []\n        self.non_time_updaters = []\n        self.refresh_has_updater_status()\n        return self\n\n    def match_updaters(self, mesh: Object3D) -> Self:\n        self.clear_updaters()\n        for updater in mesh.get_updaters():\n            self.add_updater(updater)\n        return self\n\n    def suspend_updating(self) -> Self:\n        self.updating_suspended = True\n        return self\n\n    def resume_updating(self, call_updater: bool = True) -> Self:\n        self.updating_suspended = False\n        if call_updater:\n            self.update(dt=0)\n        return self\n\n    def refresh_has_updater_status(self) -> Self:\n        self.has_updaters = len(self.get_updaters()) > 0\n        return self\n\n\nclass Mesh(Object3D):\n    def __init__(\n        self,\n        shader: Shader | None = None,\n        attributes: npt.NDArray | None = None,\n        geometry: Mesh | None = None,\n        material: Shader | None = None,\n        indices: npt.NDArray | None = None,\n        use_depth_test: bool = True,\n        primitive: int = moderngl.TRIANGLES,\n    ):\n        super().__init__()\n        if shader is not None and attributes is not None:\n            self.shader: Shader = shader\n            self.attributes = attributes\n            self.indices = indices\n        elif geometry is not None and material is not None:\n            self.shader = material\n            self.attributes = geometry.attributes\n            self.indices = geometry.indices\n        else:\n            raise Exception(\n                \"Mesh requires either attributes and a Shader or a Geometry and a \"\n                \"Material\",\n            )\n        self.use_depth_test = use_depth_test\n        self.primitive = primitive\n        self.skip_render: bool = False\n        self.init_updaters()\n\n    def single_copy(self) -> Mesh:\n        copy = Mesh(\n            attributes=self.attributes.copy(),\n            shader=self.shader,\n            indices=self.indices.copy() if self.indices is not None else None,\n            use_depth_test=self.use_depth_test,\n            primitive=self.primitive,\n        )\n        copy.skip_render = self.skip_render\n        copy.model_matrix = self.model_matrix.copy()\n        copy.normal_matrix = self.normal_matrix.copy()\n        # TODO: Copy updaters?\n        return copy\n\n    def set_uniforms(self, renderer: OpenGLRenderer) -> None:\n        self.shader.set_uniform(\n            \"u_model_matrix\",\n            opengl.matrix_to_shader_input(self.model_matrix),\n        )\n        self.shader.set_uniform(\"u_view_matrix\", renderer.camera.formatted_view_matrix)\n        self.shader.set_uniform(\n            \"u_projection_matrix\",\n            renderer.camera.projection_matrix,\n        )\n\n    def render(self) -> None:\n        if self.skip_render:\n            return\n\n        if self.use_depth_test:\n            self.shader.context.enable(moderngl.DEPTH_TEST)\n        else:\n            self.shader.context.disable(moderngl.DEPTH_TEST)\n\n        shader_attribute_names: list[str] = []\n        for member_name, member in self.shader.shader_program._members.items():\n            if isinstance(member, moderngl.Attribute):\n                shader_attribute_names.append(member_name)\n        filtered_shader_attributes = filter_attributes(\n            self.attributes, shader_attribute_names\n        )\n\n        vertex_buffer_object = self.shader.context.buffer(\n            filtered_shader_attributes.tobytes()\n        )\n        if self.indices is None:\n            index_buffer_object = None\n        else:\n            vert_index_data = self.indices.astype(\"i4\").tobytes()\n            if vert_index_data:\n                index_buffer_object = self.shader.context.buffer(vert_index_data)\n            else:\n                index_buffer_object = None\n        vertex_array_object = self.shader.context.simple_vertex_array(\n            self.shader.shader_program,\n            vertex_buffer_object,\n            *filtered_shader_attributes.dtype.names,\n            index_buffer=index_buffer_object,\n        )\n        vertex_array_object.render(self.primitive)\n        vertex_buffer_object.release()\n        vertex_array_object.release()\n        if index_buffer_object is not None:\n            index_buffer_object.release()\n\n\nclass Shader:\n    def __init__(\n        self,\n        context: moderngl.Context,\n        name: str | None = None,\n        source: dict[str, Any] | None = None,\n    ):\n        global shader_program_cache\n        self.context = context\n        self.name = name\n        self.source = source\n\n        # See if the program is cached.\n        if (\n            self.name in shader_program_cache\n            and shader_program_cache[self.name].ctx == self.context\n        ):\n            self.shader_program = shader_program_cache[self.name]\n        elif self.source is not None:\n            # Generate the shader from inline code if it was passed.\n            self.shader_program = context.program(**self.source)\n        elif self.name is not None:\n            # Search for a file containing the shader.\n            source_dict = {}\n            source_dict_key = {\n                \"vert\": \"vertex_shader\",\n                \"frag\": \"fragment_shader\",\n                \"geom\": \"geometry_shader\",\n            }\n            shader_folder = SHADER_FOLDER / self.name\n            for shader_file in shader_folder.iterdir():\n                shader_file_path = shader_folder / shader_file\n                shader_source = get_shader_code_from_file(shader_file_path)\n                source_dict[source_dict_key[shader_file_path.stem]] = shader_source\n            self.shader_program = context.program(**source_dict)\n        else:\n            raise Exception(\"Must either pass shader name or shader source.\")\n\n        # Cache the shader.\n        if self.name is not None and self.name not in shader_program_cache:\n            shader_program_cache[self.name] = self.shader_program\n\n    def set_uniform(self, name: str, value: Any) -> None:\n        with contextlib.suppress(KeyError):\n            self.shader_program[name] = value\n\n\nclass FullScreenQuad(Mesh):\n    def __init__(\n        self,\n        context: moderngl.Context,\n        fragment_shader_source: str | None = None,\n        fragment_shader_name: str | None = None,\n    ):\n        if fragment_shader_source is None and fragment_shader_name is None:\n            raise Exception(\"Must either pass shader name or shader source.\")\n\n        if fragment_shader_name is not None:\n            # Use the name.\n            shader_file_path = SHADER_FOLDER / f\"{fragment_shader_name}.frag\"\n            fragment_shader_source = get_shader_code_from_file(shader_file_path)\n        elif fragment_shader_source is not None:\n            fragment_shader_source = textwrap.dedent(fragment_shader_source.lstrip())\n\n        shader = Shader(\n            context,\n            source={\n                \"vertex_shader\": \"\"\"\n                #version 330\n                in vec4 in_vert;\n                uniform mat4 u_model_view_matrix;\n                uniform mat4 u_projection_matrix;\n                void main() {{\n                    vec4 camera_space_vertex = u_model_view_matrix * in_vert;\n                    vec4 clip_space_vertex = u_projection_matrix * camera_space_vertex;\n                    gl_Position = clip_space_vertex;\n                }}\n                \"\"\",\n                \"fragment_shader\": fragment_shader_source,\n            },\n        )\n        attributes = np.zeros(6, dtype=[(\"in_vert\", np.float32, (4,))])\n        attributes[\"in_vert\"] = np.array(\n            [\n                [-config[\"frame_x_radius\"], -config[\"frame_y_radius\"], 0, 1],\n                [-config[\"frame_x_radius\"], config[\"frame_y_radius\"], 0, 1],\n                [config[\"frame_x_radius\"], config[\"frame_y_radius\"], 0, 1],\n                [-config[\"frame_x_radius\"], -config[\"frame_y_radius\"], 0, 1],\n                [config[\"frame_x_radius\"], -config[\"frame_y_radius\"], 0, 1],\n                [config[\"frame_x_radius\"], config[\"frame_y_radius\"], 0, 1],\n            ],\n        )\n        shader.set_uniform(\"u_model_view_matrix\", opengl.view_matrix())\n        shader.set_uniform(\n            \"u_projection_matrix\",\n            opengl.orthographic_projection_matrix(),\n        )\n        super().__init__(shader, attributes)\n\n    def render(self) -> None:\n        super().render()\n"
  },
  {
    "path": "manim/renderer/shader_wrapper.py",
    "content": "from __future__ import annotations\n\nimport copy\nimport logging\nimport re\nfrom collections.abc import Mapping, Sequence\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, Self, TypeAlias\n\nimport moderngl\nimport numpy as np\nimport numpy.typing as npt\n\nif TYPE_CHECKING:\n    from manim.typing import FloatRGBLike_Array\n\n# Mobjects that should be rendered with\n# the same shader will be organized and\n# clumped together based on keeping track\n# of a dict holding all the relevant information\n# to that shader\n\n__all__ = [\"ShaderWrapper\"]\n\nlogger = logging.getLogger(\"manim\")\n\n\ndef get_shader_dir():\n    return Path(__file__).parent / \"shaders\"\n\n\ndef find_file(file_name: Path, directories: list[Path]) -> Path:\n    # Check if what was passed in is already a valid path to a file\n    if file_name.exists():\n        return file_name\n    possible_paths = (directory / file_name for directory in directories)\n    for path in possible_paths:\n        if path.exists():\n            return path\n        else:\n            logger.debug(f\"{path} does not exist.\")\n    raise OSError(f\"{file_name} not Found\")\n\n\n_ShaderDType: TypeAlias = np.void\n_ShaderData: TypeAlias = npt.NDArray[_ShaderDType]\n\n\nclass ShaderWrapper:\n    def __init__(\n        self,\n        vert_data: _ShaderData = None,\n        vert_indices: Sequence[int] | None = None,\n        shader_folder: Path | str | None = None,\n        # A dictionary mapping names of uniform variables\n        uniforms: dict[str, float | tuple[float, ...]] | None = None,\n        # A dictionary mapping names to filepaths for textures.\n        texture_paths: Mapping[str, Path | str] | None = None,\n        depth_test: bool = False,\n        render_primitive: int | str = moderngl.TRIANGLE_STRIP,\n    ):\n        self.vert_data: _ShaderData = vert_data\n        self.vert_indices: Sequence[int] | None = vert_indices\n        self.vert_attributes: tuple[str, ...] | None = vert_data.dtype.names\n        self.shader_folder: Path = Path(shader_folder or \"\")\n        self.uniforms: dict[str, float | tuple[float, ...]] = uniforms or {}\n        self.texture_paths: Mapping[str, str | Path] = texture_paths or {}\n        self.depth_test: bool = depth_test\n        self.render_primitive: str = str(render_primitive)\n        self.init_program_code()\n        self.refresh_id()\n\n    def copy(self):\n        result = copy.copy(self)\n        result.vert_data = np.array(self.vert_data)\n        if result.vert_indices is not None:\n            result.vert_indices = np.array(self.vert_indices)\n        if self.uniforms:\n            result.uniforms = dict(self.uniforms)\n        if self.texture_paths:\n            result.texture_paths = dict(self.texture_paths)\n        return result\n\n    def is_valid(self) -> bool:\n        return all(\n            [\n                self.vert_data is not None,\n                self.program_code[\"vertex_shader\"] is not None,\n                self.program_code[\"fragment_shader\"] is not None,\n            ],\n        )\n\n    def get_id(self) -> str:\n        return self.id\n\n    def get_program_id(self) -> int:\n        return self.program_id\n\n    def create_id(self):\n        # A unique id for a shader\n        return \"|\".join(\n            map(\n                str,\n                [\n                    self.program_id,\n                    self.uniforms,\n                    self.texture_paths,\n                    self.depth_test,\n                    self.render_primitive,\n                ],\n            ),\n        )\n\n    def refresh_id(self) -> None:\n        self.program_id: int = self.create_program_id()\n        self.id: str = self.create_id()\n\n    def create_program_id(self):\n        return hash(\n            \"\".join(\n                self.program_code[f\"{name}_shader\"] or \"\"\n                for name in (\"vertex\", \"geometry\", \"fragment\")\n            ),\n        )\n\n    def init_program_code(self):\n        def get_code(name: str) -> str | None:\n            return get_shader_code_from_file(\n                self.shader_folder / f\"{name}.glsl\",\n            )\n\n        self.program_code: dict[str, str | None] = {\n            \"vertex_shader\": get_code(\"vert\"),\n            \"geometry_shader\": get_code(\"geom\"),\n            \"fragment_shader\": get_code(\"frag\"),\n        }\n\n    def get_program_code(self):\n        return self.program_code\n\n    def replace_code(self, old: str, new: str) -> None:\n        code_map = self.program_code\n        for name, code in code_map.items():\n            if code:\n                code_map[name] = re.sub(old, new, code)\n        self.refresh_id()\n\n    def combine_with(self, *shader_wrappers: \"ShaderWrapper\") -> Self:  # noqa: UP037\n        # Assume they are of the same type\n        if len(shader_wrappers) == 0:\n            return self\n        if self.vert_indices is not None:\n            num_verts = len(self.vert_data)\n            indices_list = [self.vert_indices]\n            data_list = [self.vert_data]\n            for sw in shader_wrappers:\n                indices_list.append(sw.vert_indices + num_verts)\n                data_list.append(sw.vert_data)\n                num_verts += len(sw.vert_data)\n            self.vert_indices = np.hstack(indices_list)\n            self.vert_data = np.hstack(data_list)\n        else:\n            self.vert_data = np.hstack(\n                [self.vert_data, *(sw.vert_data for sw in shader_wrappers)],\n            )\n        return self\n\n\n# For caching\nfilename_to_code_map: dict = {}\n\n\ndef get_shader_code_from_file(filename: Path) -> str | None:\n    if filename in filename_to_code_map:\n        return filename_to_code_map[filename]\n\n    try:\n        filepath = find_file(\n            filename,\n            directories=[get_shader_dir(), Path(\"/\")],\n        )\n    except OSError:\n        return None\n\n    result = filepath.read_text()\n\n    # To share functionality between shaders, some functions are read in\n    # from other files an inserted into the relevant strings before\n    # passing to ctx.program for compiling\n    # Replace \"#INSERT \" lines with relevant code\n    insertions = re.findall(\n        r\"^#include ../include/.*\\.glsl$\",\n        result,\n        flags=re.MULTILINE,\n    )\n    for line in insertions:\n        inserted_code = get_shader_code_from_file(\n            Path() / \"include\" / line.replace(\"#include ../include/\", \"\"),\n        )\n        if inserted_code is None:\n            return None\n        result = result.replace(line, inserted_code)\n    filename_to_code_map[filename] = result\n    return result\n\n\ndef get_colormap_code(rgb_list: FloatRGBLike_Array) -> str:\n    data = \",\".join(\"vec3({}, {}, {})\".format(*rgb) for rgb in rgb_list)\n    return f\"vec3[{len(rgb_list)}]({data})\"\n"
  },
  {
    "path": "manim/renderer/shaders/default/frag.glsl",
    "content": "#version 330\n\nuniform vec4 u_color;\nout vec4 frag_color;\n\nvoid main() {\n  frag_color = u_color;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/default/vert.glsl",
    "content": "#version 330\n\nin vec3 in_vert;\nuniform mat4 u_model_matrix;\nuniform mat4 u_view_matrix;\nuniform mat4 u_projection_matrix;\n\nvoid main() {\n    gl_Position = u_projection_matrix * u_view_matrix * u_model_matrix * vec4(in_vert, 1.0);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/design.frag",
    "content": "#version 330\n\nout vec4 frag_color;\n\nvoid main() {\n  vec2 st = gl_FragCoord.xy / vec2(854, 360);\n  vec3 color = vec3(0.0);\n\n  st *= 3.0;\n  st = fract(st);\n\n  color = vec3(st, 0.0);\n\n  frag_color = vec4(color, 1.0);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/design_2.frag",
    "content": "#version 330\n\nuniform vec2 u_resolution;\nout vec4 frag_color;\n\n\n#define PI 3.14159265358979323846\n\nvec2 rotate2D(vec2 _st, float _angle){\n    _st -= 0.5;\n    _st =  mat2(cos(_angle),-sin(_angle),\n                sin(_angle),cos(_angle)) * _st;\n    _st += 0.5;\n    return _st;\n}\n\nvec2 tile(vec2 _st, float _zoom){\n    _st *= _zoom;\n    return fract(_st);\n}\n\nfloat box(vec2 _st, vec2 _size, float _smoothEdges){\n    _size = vec2(0.5)-_size*0.5;\n    vec2 aa = vec2(_smoothEdges*0.5);\n    vec2 uv = smoothstep(_size,_size+aa,_st);\n    uv *= smoothstep(_size,_size+aa,vec2(1.0)-_st);\n    return uv.x*uv.y;\n}\n\nvoid main(void){\n    vec2 st = gl_FragCoord.xy/u_resolution.xy;\n    vec3 color = vec3(0.0);\n\n    // Divide the space in 4\n    st = tile(st,4.);\n\n    // Use a matrix to rotate the space 45 degrees\n    st = rotate2D(st,PI*0.25);\n\n    // Draw a square\n    color = vec3(box(st,vec2(0.7),0.01));\n    // color = vec3(st,0.0);\n\n    frag_color = vec4(color,1.0);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/design_3.frag",
    "content": "#version 330\n\nuniform vec3 u_resolution;\nuniform float u_time;\nout vec4 frag_color;\n\nvec3 palette(float d){\n\treturn mix(vec3(0.2,0.7,0.9),vec3(1.,0.,1.),d);\n}\n\nvec2 rotate(vec2 p,float a){\n\tfloat c = cos(a);\n    float s = sin(a);\n    return p*mat2(c,s,-s,c);\n}\n\nfloat map(vec3 p){\n    for( int i = 0; i<8; ++i){\n        float t = u_time*0.1;\n        p.xz =rotate(p.xz,t);\n        p.xy =rotate(p.xy,t*1.89);\n        p.xz = abs(p.xz);\n        p.xz-=.5;\n\t}\n\treturn dot(sign(p),p)/5.;\n}\n\nvec4 rm (vec3 ro, vec3 rd){\n    float t = 0.;\n    vec3 col = vec3(0.);\n    float d;\n    for(float i =0.; i<64.; i++){\n\t\tvec3 p = ro + rd*t;\n        d = map(p)*.5;\n        if(d<0.02){\n            break;\n        }\n        if(d>100.){\n        \tbreak;\n        }\n        //col+=vec3(0.6,0.8,0.8)/(400.*(d));\n        col+=palette(length(p)*.1)/(400.*(d));\n        t+=d;\n    }\n    return vec4(col,1./(d*100.));\n}\n\nvoid main(void){\n    vec2 uv = (gl_FragCoord.xy-(u_resolution.xy/2.))/u_resolution.x;\n\tvec3 ro = vec3(0.,0.,-50.);\n    ro.xz = rotate(ro.xz,u_time);\n    vec3 cf = normalize(-ro);\n    vec3 cs = normalize(cross(cf,vec3(0.,1.,0.)));\n    vec3 cu = normalize(cross(cf,cs));\n    vec3 uuv = ro+cf*3. + uv.x*cs + uv.y*cu;\n    vec3 rd = normalize(uuv-ro);\n    vec4 col = rm(ro,rd);\n    frag_color = vec4(col.xyz, 1);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/image/frag.glsl",
    "content": "#version 330\n\nuniform sampler2D Texture;\n\nin vec2 v_im_coords;\nin float v_opacity;\n\nout vec4 frag_color;\n\nvoid main() {\n    frag_color = texture(Texture, v_im_coords);\n    frag_color.a = v_opacity;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/image/vert.glsl",
    "content": "#version 330\n\n#include ../include/camera_uniform_declarations.glsl\n\nuniform sampler2D Texture;\n\nin vec3 point;\nin vec2 im_coords;\nin float opacity;\n\nout vec2 v_im_coords;\nout float v_opacity;\n\n// Analog of import for manim only\n#include ../include/get_gl_Position.glsl\n#include ../include/position_point_into_frame.glsl\n\nvoid main(){\n    v_im_coords = im_coords;\n    v_opacity = opacity;\n    gl_Position = get_gl_Position(position_point_into_frame(point));\n}\n"
  },
  {
    "path": "manim/renderer/shaders/include/NOTE.md",
    "content": "There seems to be no analog to #include in C++ for OpenGL shaders.  While there are other options for sharing code between shaders, a lot of them aren't great, especially if the goal is to have all the logic for which specific bits of code to share handled in the shader file itself.  So the way manim currently works is to replace any line which looks like\n\n#INSERT <file_name>\n\nwith the code from one of the files in this folder.\n\nThe functions in this file often include reference to uniforms which are assumed to be part of the surrounding context into which they are inserted.\n"
  },
  {
    "path": "manim/renderer/shaders/include/add_light.glsl",
    "content": "///// INSERT COLOR_MAP FUNCTION HERE /////\n\nvec4 add_light(vec4 color,\n               vec3 point,\n               vec3 unit_normal,\n               vec3 light_coords,\n               float gloss,\n               float shadow){\n    ///// INSERT COLOR FUNCTION HERE /////\n    // The line above may be replaced by arbitrary code snippets, as per\n    // the method Mobject.set_color_by_code\n    if(gloss == 0.0 && shadow == 0.0) return color;\n\n    // TODO, do we actually want this?  It effectively treats surfaces as two-sided\n    if(unit_normal.z < 0){\n            unit_normal *= -1;\n    }\n\n    // TODO, read this in as a uniform?\n    float camera_distance = 6;\n    // Assume everything has already been rotated such that camera is in the z-direction\n    vec3 to_camera = vec3(0, 0, camera_distance) - point;\n    vec3 to_light = light_coords - point;\n    vec3 light_reflection = -to_light + 2 * unit_normal * dot(to_light, unit_normal);\n    float dot_prod = dot(normalize(light_reflection), normalize(to_camera));\n    float shine = gloss * exp(-3 * pow(1 - dot_prod, 2));\n    float dp2 = dot(normalize(to_light), unit_normal);\n    float darkening = mix(1, max(dp2, 0), shadow);\n    return vec4(\n            darkening * mix(color.rgb, vec3(1.0), shine),\n            color.a\n    );\n}\n\nvec4 finalize_color(vec4 color,\n                    vec3 point,\n                    vec3 unit_normal,\n                    vec3 light_coords,\n                    float gloss,\n                    float shadow){\n    // Put insertion here instead\n    return add_light(color, point, unit_normal, light_coords, gloss, shadow);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/include/camera_uniform_declarations.glsl",
    "content": "uniform vec2 frame_shape;\nuniform float anti_alias_width;\nuniform vec3 camera_center;\nuniform mat3 camera_rotation;\nuniform float is_fixed_in_frame;\nuniform float is_fixed_orientation;\nuniform vec3 fixed_orientation_center;\nuniform float focal_distance;\n"
  },
  {
    "path": "manim/renderer/shaders/include/finalize_color.glsl",
    "content": "vec3 float_to_color(float value, float min_val, float max_val, vec3[9] colormap_data){\n    float alpha = clamp((value - min_val) / (max_val - min_val), 0.0, 1.0);\n    int disc_alpha = min(int(alpha * 8), 7);\n    return mix(\n        colormap_data[disc_alpha],\n        colormap_data[disc_alpha + 1],\n        8.0 * alpha - disc_alpha\n    );\n}\n\n\nvec4 add_light(vec4 color,\n               vec3 point,\n               vec3 unit_normal,\n               vec3 light_coords,\n               float gloss,\n               float shadow){\n    if(gloss == 0.0 && shadow == 0.0) return color;\n\n    // TODO, do we actually want this?  It effectively treats surfaces as two-sided\n    if(unit_normal.z < 0){\n            unit_normal *= -1;\n    }\n\n    // TODO, read this in as a uniform?\n    float camera_distance = 6;\n    // Assume everything has already been rotated such that camera is in the z-direction\n    vec3 to_camera = vec3(0, 0, camera_distance) - point;\n    vec3 to_light = light_coords - point;\n    vec3 light_reflection = -to_light + 2 * unit_normal * dot(to_light, unit_normal);\n    float dot_prod = dot(normalize(light_reflection), normalize(to_camera));\n    float shine = gloss * exp(-3 * pow(1 - dot_prod, 2));\n    float dp2 = dot(normalize(to_light), unit_normal);\n    float darkening = mix(1, max(dp2, 0), shadow);\n    return vec4(\n            darkening * mix(color.rgb, vec3(1.0), shine),\n            color.a\n    );\n}\n\nvec4 finalize_color(vec4 color,\n                    vec3 point,\n                    vec3 unit_normal,\n                    vec3 light_coords,\n                    float gloss,\n                    float shadow){\n    ///// INSERT COLOR FUNCTION HERE /////\n    // The line above may be replaced by arbitrary code snippets, as per\n    // the method Mobject.set_color_by_code\n    return add_light(color, point, unit_normal, light_coords, gloss, shadow);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/include/get_gl_Position.glsl",
    "content": "// Assumes the following uniforms exist in the surrounding context:\n// uniform vec2 frame_shape;\n// uniform float focal_distance;\n// uniform float is_fixed_in_frame;\n// uniform float is_fixed_orientation;\n// uniform vec3 fixed_orientation_center;\n\nconst vec2 DEFAULT_FRAME_SHAPE = vec2(8.0 * 16.0 / 9.0, 8.0);\n\nfloat perspective_scale_factor(float z, float focal_distance){\n    return max(0.0, focal_distance / (focal_distance - z));\n}\n\n\nvec4 get_gl_Position(vec3 point){\n    vec4 result = vec4(point, 1.0);\n    if(!bool(is_fixed_in_frame)){\n        result.x *= 2.0 / frame_shape.x;\n        result.y *= 2.0 / frame_shape.y;\n        float psf = perspective_scale_factor(result.z, focal_distance);\n        if (psf > 0){\n            result.xy *= psf;\n            // TODO, what's the better way to do this?\n            // This is to keep vertices too far out of frame from getting cut.\n            result.z *= 0.01;\n        }\n    } else{\n        if (!bool(is_fixed_orientation)){\n            result.x *= 2.0 / DEFAULT_FRAME_SHAPE.x;\n            result.y *= 2.0 / DEFAULT_FRAME_SHAPE.y;\n        } else{\n            result.x *= 2.0 / frame_shape.x;\n            result.y *= 2.0 / frame_shape.y;\n        }\n    }\n    result.z *= -1;\n    return result;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/include/get_rotated_surface_unit_normal_vector.glsl",
    "content": "// Assumes the following uniforms exist in the surrounding context:\n// uniform vec3 camera_center;\n// uniform mat3 camera_rotation;\n\nvec3 get_rotated_surface_unit_normal_vector(vec3 point, vec3 du_point, vec3 dv_point){\n    vec3 cp = cross(\n        (du_point - point),\n        (dv_point - point)\n    );\n    if(length(cp) == 0){\n        // Instead choose a normal to just dv_point - point in the direction of point\n        vec3 v2 = dv_point - point;\n        cp = cross(cross(v2, point), v2);\n    }\n    return normalize(rotate_point_into_frame(cp));\n}\n"
  },
  {
    "path": "manim/renderer/shaders/include/get_unit_normal.glsl",
    "content": "vec3 get_unit_normal(in vec3[3] points){\n    float tol = 1e-6;\n    vec3 v1 = normalize(points[1] - points[0]);\n    vec3 v2 = normalize(points[2] - points[0]);\n    vec3 cp = cross(v1, v2);\n    float cp_norm = length(cp);\n    if(cp_norm < tol){\n        // Three points form a line, so find a normal vector\n        // to that line in the plane shared with the z-axis\n        vec3 k_hat = vec3(0.0, 0.0, 1.0);\n        vec3 new_cp = cross(cross(v2, k_hat), v2);\n        float new_cp_norm = length(new_cp);\n        if(new_cp_norm < tol){\n            // We only come here if all three points line up\n            // on the z-axis.\n            return vec3(0.0, -1.0, 0.0);\n            // return k_hat;\n        }\n        return new_cp / new_cp_norm;\n    }\n    return cp / cp_norm;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/include/position_point_into_frame.glsl",
    "content": "// Assumes the following uniforms exist in the surrounding context:\n// uniform float is_fixed_in_frame;\n// uniform float is_fixed_orientation;\n// uniform vec3 fixed_orientation_center;\n// uniform vec3 camera_center;\n// uniform mat3 camera_rotation;\n\nvec3 rotate_point_into_frame(vec3 point){\n    if(bool(is_fixed_in_frame)){\n        return point;\n    }\n    return camera_rotation * point;\n}\n\n\nvec3 position_point_into_frame(vec3 point){\n    if(bool(is_fixed_in_frame)){\n        return point;\n    }\n    if(bool(is_fixed_orientation)){\n        vec3 new_center = rotate_point_into_frame(fixed_orientation_center);\n        return point + (new_center - fixed_orientation_center);\n    }\n    return rotate_point_into_frame(point - camera_center);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/include/quadratic_bezier_distance.glsl",
    "content": "// Must be inserted in a context with a definition for modify_distance_for_endpoints\n\n// All of this is with respect to a curve that's been rotated/scaled\n// so that b0 = (0, 0) and b1 = (1, 0).  That is, b2 entirely\n// determines the shape of the curve\n\nvec2 bezier(float t, vec2 b2){\n    // Quick returns for the 0 and 1 cases\n    if (t == 0) return vec2(0, 0);\n    else if (t == 1) return b2;\n    // Everything else\n    return vec2(\n        2 * t * (1 - t) + b2.x * t*t,\n        b2.y * t * t\n    );\n}\n\n\nfloat cube_root(float x){\n    return sign(x) * pow(abs(x), 1.0 / 3.0);\n}\n\n\nint cubic_solve(float a, float b, float c, float d, out float roots[3]){\n    // Normalize so a = 1\n    b = b / a;\n    c = c / a;\n    d = d / a;\n\n    float  p = c - b*b / 3.0;\n    float  q = b * (2.0*b*b - 9.0*c) / 27.0 + d;\n    float p3 = p*p*p;\n    float  disc = q*q + 4.0*p3 / 27.0;\n    float offset = -b / 3.0;\n    if(disc >= 0.0){\n        float z = sqrt(disc);\n        float u = (-q + z) / 2.0;\n        float v = (-q - z) / 2.0;\n        u = cube_root(u);\n        v = cube_root(v);\n        roots[0] = offset + u + v;\n        return 1;\n    }\n    float u = sqrt(-p / 3.0);\n    float v = acos(-sqrt( -27.0 / p3) * q / 2.0) / 3.0;\n    float m = cos(v);\n    float n = sin(v) * 1.732050808;\n\n    float all_roots[3] = float[3](\n        offset + u * (n - m),\n        offset - u * (n + m),\n        offset + u * (m + m)\n    );\n\n    // Only accept roots with a positive derivative\n    int n_valid_roots = 0;\n    for(int i = 0; i < 3; i++){\n        float r = all_roots[i];\n        if(3*r*r + 2*b*r + c > 0){\n            roots[n_valid_roots] = r;\n            n_valid_roots++;\n        }\n    }\n    return n_valid_roots;\n}\n\nfloat dist_to_line(vec2 p, vec2 b2){\n    float t = clamp(p.x / b2.x, 0, 1);\n    float dist;\n    if(t == 0)      dist = length(p);\n    else if(t == 1) dist = distance(p, b2);\n    else            dist = abs(p.y);\n\n    return modify_distance_for_endpoints(p, dist, t);\n}\n\n\nfloat dist_to_point_on_curve(vec2 p, float t, vec2 b2){\n    t = clamp(t, 0, 1);\n    return modify_distance_for_endpoints(\n        p, length(p - bezier(t, b2)), t\n    );\n}\n\n\nfloat min_dist_to_curve(vec2 p, vec2 b2, float degree){\n    // Check if curve is really a a line\n    if(degree == 1) return dist_to_line(p, b2);\n\n    // Try finding the exact sdf by solving the equation\n    // (d/dt) dist^2(t) = 0, which amount to the following\n    // cubic.\n    float xm2 = uv_b2.x - 2.0;\n    float y = uv_b2.y;\n    float a = xm2*xm2 + y*y;\n    float b = 3 * xm2;\n    float c = -(p.x*xm2 + p.y*y) + 2;\n    float d = -p.x;\n\n    float roots[3];\n    int n = cubic_solve(a, b, c, d, roots);\n    // At most 2 roots will have been populated.\n    float d0 = dist_to_point_on_curve(p, roots[0], b2);\n    if(n == 1) return d0;\n    float d1 = dist_to_point_on_curve(p, roots[1], b2);\n    return min(d0, d1);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/include/quadratic_bezier_geometry_functions.glsl",
    "content": "float cross2d(vec2 v, vec2 w){\n    return v.x * w.y - w.x * v.y;\n}\n\n\nmat3 get_xy_to_uv(vec2 b0, vec2 b1){\n    mat3 shift = mat3(\n        1.0, 0.0, 0.0,\n        0.0, 1.0, 0.0,\n        -b0.x, -b0.y, 1.0\n    );\n\n    float sf = length(b1 - b0);\n    vec2 I = (b1 - b0) / sf;\n    vec2 J = vec2(-I.y, I.x);\n    mat3 rotate = mat3(\n        I.x, J.x, 0.0,\n        I.y, J.y, 0.0,\n        0.0, 0.0, 1.0\n    );\n    return (1 / sf) * rotate * shift;\n}\n\n\n// Orthogonal matrix to convert to a uv space defined so that\n// b0 goes to [0, 0] and b1 goes to [1, 0]\nmat4 get_xyz_to_uv(vec3 b0, vec3 b1, vec3 unit_normal){\n    mat4 shift = mat4(\n        1, 0, 0, 0,\n        0, 1, 0, 0,\n        0, 0, 1, 0,\n        -b0.x, -b0.y, -b0.z, 1\n    );\n\n    float scale_factor = length(b1 - b0);\n    vec3 I = (b1 - b0) / scale_factor;\n    vec3 K = unit_normal;\n    vec3 J = cross(K, I);\n    // Transpose (hence inverse) of matrix taking\n    // i-hat to I, k-hat to unit_normal, and j-hat to their cross\n    mat4 rotate = mat4(\n        I.x, J.x, K.x, 0.0,\n        I.y, J.y, K.y, 0.0,\n        I.z, J.z, K.z, 0.0,\n        0.0, 0.0, 0.0, 1.0\n    );\n    return (1 / scale_factor) * rotate * shift;\n}\n\n\n// Returns 0 for null curve, 1 for linear, 2 for quadratic.\n// Populates new_points with bezier control points for the curve,\n// which for quadratics will be the same, but for linear and null\n// might change.  The idea is to inform the caller of the degree,\n// while also passing tangency information in the linear case.\n// float get_reduced_control_points(vec3 b0, vec3 b1, vec3 b2, out vec3 new_points[3]){\nfloat get_reduced_control_points(in vec3 points[3], out vec3 new_points[3]){\n    float length_threshold = 1e-6;\n    float angle_threshold = 5e-2;\n\n    vec3 p0 = points[0];\n    vec3 p1 = points[1];\n    vec3 p2 = points[2];\n    vec3 v01 = (p1 - p0);\n    vec3 v12 = (p2 - p1);\n\n    float dot_prod = clamp(dot(normalize(v01), normalize(v12)), -1, 1);\n    bool aligned = acos(dot_prod) < angle_threshold;\n    bool distinct_01 = length(v01) > length_threshold;  // v01 is considered nonzero\n    bool distinct_12 = length(v12) > length_threshold;  // v12 is considered nonzero\n    int n_uniques = int(distinct_01) + int(distinct_12);\n\n    bool quadratic = (n_uniques == 2) && !aligned;\n    bool linear = (n_uniques == 1) || ((n_uniques == 2) && aligned);\n    bool constant = (n_uniques == 0);\n    if(quadratic){\n        new_points[0] = p0;\n        new_points[1] = p1;\n        new_points[2] = p2;\n        return 2.0;\n    }else if(linear){\n        new_points[0] = p0;\n        new_points[1] = (p0 + p2) / 2.0;\n        new_points[2] = p2;\n        return 1.0;\n    }else{\n        new_points[0] = p0;\n        new_points[1] = p0;\n        new_points[2] = p0;\n        return 0.0;\n    }\n}\n"
  },
  {
    "path": "manim/renderer/shaders/manim_coords/frag.glsl",
    "content": "#version 330\n\nuniform vec4 u_color;\nout vec4 frag_color;\n\nvoid main() {\n  frag_color = u_color;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/manim_coords/vert.glsl",
    "content": "#version 330\n\nin vec4 in_vert;\nuniform mat4 u_model_view_matrix;\nuniform mat4 u_projection_matrix;\n\nvoid main() {\n    vec4 camera_space_vertex = u_model_view_matrix * in_vert;\n    vec4 clip_space_vertex = u_projection_matrix * camera_space_vertex;\n    gl_Position = clip_space_vertex;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/quadratic_bezier_fill/frag.glsl",
    "content": "#version 330\n\n#include ../include/camera_uniform_declarations.glsl\n\nin vec4 color;\nin float fill_all;  // Either 0 or 1e\nin float uv_anti_alias_width;\n\nin vec3 xyz_coords;\nin float orientation;\nin vec2 uv_coords;\nin vec2 uv_b2;\nin float bezier_degree;\n\nout vec4 frag_color;\n\n// Needed for quadratic_bezier_distance insertion below\nfloat modify_distance_for_endpoints(vec2 p, float dist, float t){\n    return dist;\n}\n\n#include ../include/quadratic_bezier_distance.glsl\n\n\nfloat sdf(){\n    if(bezier_degree < 2){\n        return abs(uv_coords[1]);\n    }\n    float u2 = uv_b2.x;\n    float v2 = uv_b2.y;\n    // For really flat curves, just take the distance to x-axis\n    if(abs(v2 / u2) < 0.1 * uv_anti_alias_width){\n        return abs(uv_coords[1]);\n    }\n    // For flat-ish curves, take the curve\n    else if(abs(v2 / u2) < 0.5 * uv_anti_alias_width){\n        return min_dist_to_curve(uv_coords, uv_b2, bezier_degree);\n    }\n    // I know, I don't love this amount of arbitrary-seeming branching either,\n    // but a number of strange dimples and bugs pop up otherwise.\n\n    // This converts uv_coords to yet another space where the bezier points sit on\n    // (0, 0), (1/2, 0) and (1, 1), so that the curve can be expressed implicityly\n    // as y = x^2.\n    mat2 to_simple_space = mat2(\n        v2, 0,\n        2 - u2, 4 * v2\n    );\n    vec2 p = to_simple_space * uv_coords;\n    // Sign takes care of whether we should be filling the inside or outside of curve.\n    float sgn = orientation * sign(v2);\n    float Fp = (p.x * p.x - p.y);\n    if(sgn * Fp < 0){\n        return 0.0;\n    }else{\n        return min_dist_to_curve(uv_coords, uv_b2, bezier_degree);\n    }\n}\n\n\nvoid main() {\n    if (color.a == 0) discard;\n    frag_color = color;\n    if (fill_all == 1.0) return;\n    frag_color.a *= smoothstep(1, 0, sdf() / uv_anti_alias_width);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/quadratic_bezier_fill/geom.glsl",
    "content": "#version 330\n\nlayout (triangles) in;\nlayout (triangle_strip, max_vertices = 5) out;\n\nuniform float anti_alias_width;\n\n// Needed for get_gl_Position\nuniform vec2 frame_shape;\nuniform float focal_distance;\nuniform float is_fixed_in_frame;\nuniform float is_fixed_orientation;\nuniform vec3 fixed_orientation_center;\n// Needed for finalize_color\nuniform vec3 light_source_position;\nuniform float gloss;\nuniform float shadow;\n\nin vec3 bp[3];\nin vec3 v_global_unit_normal[3];\nin vec4 v_color[3];\nin float v_vert_index[3];\n\nout vec4 color;\nout float fill_all;\nout float uv_anti_alias_width;\n\nout vec3 xyz_coords;\nout float orientation;\n// uv space is where b0 = (0, 0), b1 = (1, 0), and transform is orthogonal\nout vec2 uv_coords;\nout vec2 uv_b2;\nout float bezier_degree;\n\n\n// Analog of import for manim only\n#include ../include/quadratic_bezier_geometry_functions.glsl\n#include ../include/get_gl_Position.glsl\n#include ../include/get_unit_normal.glsl\n#include ../include/finalize_color.glsl\n\n\nvoid emit_vertex_wrapper(vec3 point, int index){\n    color = finalize_color(\n        v_color[index],\n        point,\n        v_global_unit_normal[index],\n        light_source_position,\n        gloss,\n        shadow\n    );\n    xyz_coords = point;\n    gl_Position = get_gl_Position(xyz_coords);\n    EmitVertex();\n}\n\n\nvoid emit_simple_triangle(){\n    for(int i = 0; i < 3; i++){\n        emit_vertex_wrapper(bp[i], i);\n    }\n    EndPrimitive();\n}\n\n\nvoid emit_pentagon(vec3[3] points, vec3 normal){\n    vec3 p0 = points[0];\n    vec3 p1 = points[1];\n    vec3 p2 = points[2];\n    // Tangent vectors\n    vec3 t01 = normalize(p1 - p0);\n    vec3 t12 = normalize(p2 - p1);\n    // Vectors perpendicular to the curve in the plane of the curve pointing outside the curve\n    vec3 p0_perp = cross(t01, normal);\n    vec3 p2_perp = cross(t12, normal);\n\n    bool fill_inside = orientation > 0;\n    float aaw = anti_alias_width;\n    vec3 corners[5];\n    if(fill_inside){\n        // Note, straight lines will also fall into this case, and since p0_perp and p2_perp\n        // will point to the right of the curve, it's just what we want\n        corners = vec3[5](\n            p0 + aaw * p0_perp,\n            p0,\n            p1 + 0.5 * aaw * (p0_perp + p2_perp),\n            p2,\n            p2 + aaw * p2_perp\n        );\n    }else{\n        corners = vec3[5](\n            p0,\n            p0 - aaw * p0_perp,\n            p1,\n            p2 - aaw * p2_perp,\n            p2\n        );\n    }\n\n    mat4 xyz_to_uv = get_xyz_to_uv(p0, p1, normal);\n    uv_b2 = (xyz_to_uv * vec4(p2, 1)).xy;\n    uv_anti_alias_width = anti_alias_width / length(p1 - p0);\n\n    for(int i = 0; i < 5; i++){\n        vec3 corner = corners[i];\n        uv_coords = (xyz_to_uv * vec4(corner, 1)).xy;\n        int j = int(sign(i - 1) + 1);  // Maps i = [0, 1, 2, 3, 4] onto j = [0, 0, 1, 2, 2]\n        emit_vertex_wrapper(corner, j);\n    }\n    EndPrimitive();\n}\n\n\nvoid main(){\n    // If vert indices are sequential, don't fill all\n    fill_all = float(\n        (v_vert_index[1] - v_vert_index[0]) != 1.0 ||\n        (v_vert_index[2] - v_vert_index[1]) != 1.0\n    );\n\n    if(fill_all == 1.0){\n        emit_simple_triangle();\n        return;\n    }\n\n    vec3 new_bp[3];\n    bezier_degree = get_reduced_control_points(vec3[3](bp[0], bp[1], bp[2]), new_bp);\n    vec3 local_unit_normal = get_unit_normal(new_bp);\n    orientation = sign(dot(v_global_unit_normal[0], local_unit_normal));\n\n    if(bezier_degree >= 1){\n        emit_pentagon(new_bp, local_unit_normal);\n    }\n    // Don't emit any vertices for bezier_degree 0\n}\n"
  },
  {
    "path": "manim/renderer/shaders/quadratic_bezier_fill/vert.glsl",
    "content": "#version 330\n\n#include ../include/camera_uniform_declarations.glsl\n\nin vec3 point;\nin vec3 unit_normal;\nin vec4 color;\nin float vert_index;\n\nout vec3 bp;  // Bezier control point\nout vec3 v_global_unit_normal;\nout vec4 v_color;\nout float v_vert_index;\n\n// Analog of import for manim only\n#include ../include/position_point_into_frame.glsl\n\nvoid main(){\n    bp = position_point_into_frame(point.xyz);\n    v_global_unit_normal = rotate_point_into_frame(unit_normal.xyz);\n    v_color = color;\n    v_vert_index = vert_index;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/quadratic_bezier_stroke/frag.glsl",
    "content": "#version 330\n\n#include ../include/camera_uniform_declarations.glsl\n\nin vec2 uv_coords;\nin vec2 uv_b2;\n\nin float uv_stroke_width;\nin vec4 color;\nin float uv_anti_alias_width;\n\nin float has_prev;\nin float has_next;\nin float bevel_start;\nin float bevel_end;\nin float angle_from_prev;\nin float angle_to_next;\n\nin float bezier_degree;\n\nout vec4 frag_color;\n\n\nfloat cross2d(vec2 v, vec2 w){\n    return v.x * w.y - w.x * v.y;\n}\n\n\nfloat modify_distance_for_endpoints(vec2 p, float dist, float t){\n    float buff = 0.5 * uv_stroke_width - uv_anti_alias_width;\n    // Check the beginning of the curve\n    if(t == 0){\n        // Clip the start\n        if(has_prev == 0) return max(dist, -p.x + buff);\n        // Bevel start\n        if(bevel_start == 1){\n            float a = angle_from_prev;\n            mat2 rot = mat2(\n                cos(a), sin(a),\n                -sin(a), cos(a)\n            );\n            // Dist for intersection of two lines\n            float bevel_d = max(abs(p.y), abs((rot * p).y));\n            // Dist for union of this intersection with the real curve\n            // intersected with radius 2 away from curve to smooth out\n            // really sharp corners\n            return max(min(dist, bevel_d), dist / 2);\n        }\n        // Otherwise, start will be rounded off\n    }else if(t == 1){\n        // Check the end of the curve\n        // TODO, too much code repetition\n        vec2 v21 = (bezier_degree == 2) ? vec2(1, 0) - uv_b2 : vec2(-1, 0);\n        float len_v21 = length(v21);\n        if(len_v21 == 0){\n            v21 = -uv_b2;\n            len_v21 = length(v21);\n        }\n\n        float perp_dist = dot(p - uv_b2, v21) / len_v21;\n        if(has_next == 0) return max(dist, -perp_dist + buff);\n        // Bevel end\n        if(bevel_end == 1){\n            float a = -angle_to_next;\n            mat2 rot = mat2(\n                cos(a), sin(a),\n                -sin(a), cos(a)\n            );\n            vec2 v21_unit = v21 / length(v21);\n            float bevel_d = max(\n                abs(cross2d(p - uv_b2, v21_unit)),\n                abs(cross2d((rot * (p - uv_b2)), v21_unit))\n            );\n            return max(min(dist, bevel_d), dist / 2);\n        }\n        // Otherwise, end will be rounded off\n    }\n    return dist;\n}\n\n\n#include ../include/quadratic_bezier_distance.glsl\n\n\nvoid main() {\n    if (uv_stroke_width == 0) discard;\n    float dist_to_curve = min_dist_to_curve(uv_coords, uv_b2, bezier_degree);\n    // An sdf for the region around the curve we wish to color.\n    float signed_dist = abs(dist_to_curve) - 0.5 * uv_stroke_width;\n\n    frag_color = color;\n    frag_color.a *= smoothstep(0.5, -0.5, signed_dist / uv_anti_alias_width);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/quadratic_bezier_stroke/geom.glsl",
    "content": "#version 330\n\nlayout (triangles) in;\nlayout (triangle_strip, max_vertices = 5) out;\n\n// Needed for get_gl_Position\nuniform vec2 frame_shape;\nuniform float focal_distance;\nuniform float is_fixed_in_frame;\nuniform float is_fixed_orientation;\nuniform vec3 fixed_orientation_center;\n\nuniform float anti_alias_width;\nuniform float flat_stroke;\n\n//Needed for lighting\nuniform vec3 light_source_position;\nuniform float joint_type;\nuniform float gloss;\nuniform float shadow;\n\nin vec3 bp[3];\nin vec3 prev_bp[3];\nin vec3 next_bp[3];\nin vec3 v_global_unit_normal[3];\n\nin vec4 v_color[3];\nin float v_stroke_width[3];\n\nout vec4 color;\nout float uv_stroke_width;\nout float uv_anti_alias_width;\n\nout float has_prev;\nout float has_next;\nout float bevel_start;\nout float bevel_end;\nout float angle_from_prev;\nout float angle_to_next;\n\nout float bezier_degree;\n\nout vec2 uv_coords;\nout vec2 uv_b2;\n\n// Codes for joint types\nconst float AUTO_JOINT = 0;\nconst float ROUND_JOINT = 1;\nconst float BEVEL_JOINT = 2;\nconst float MITER_JOINT = 3;\nconst float PI = 3.141592653;\n\n\n#include ../include/quadratic_bezier_geometry_functions.glsl\n#include ../include/get_gl_Position.glsl\n#include ../include/get_unit_normal.glsl\n#include ../include/finalize_color.glsl\n\n\nvoid flatten_points(in vec3[3] points, out vec2[3] flat_points){\n    for(int i = 0; i < 3; i++){\n        float sf = perspective_scale_factor(points[i].z, focal_distance);\n        flat_points[i] = sf * points[i].xy;\n    }\n}\n\n\nfloat angle_between_vectors(vec2 v1, vec2 v2){\n    float v1_norm = length(v1);\n    float v2_norm = length(v2);\n    if(v1_norm == 0 || v2_norm == 0) return 0.0;\n    float dp = dot(v1, v2) / (v1_norm * v2_norm);\n    float angle = acos(clamp(dp, -1.0, 1.0));\n    float sn = sign(cross2d(v1, v2));\n    return sn * angle;\n}\n\n\nbool find_intersection(vec2 p0, vec2 v0, vec2 p1, vec2 v1, out vec2 intersection){\n    // Find the intersection of a line passing through\n    // p0 in the direction v0 and one passing through p1 in\n    // the direction p1.\n    // That is, find a solutoin to p0 + v0 * t = p1 + v1 * s\n    float det = -v0.x * v1.y + v1.x * v0.y;\n    if(det == 0) return false;\n    float t = cross2d(p0 - p1, v1) / det;\n    intersection = p0 + v0 * t;\n    return true;\n}\n\n\nvoid create_joint(float angle, vec2 unit_tan, float buff,\n                  vec2 static_c0, out vec2 changing_c0,\n                  vec2 static_c1, out vec2 changing_c1){\n    float shift;\n    if(abs(angle) < 1e-3){\n        // No joint\n        shift = 0;\n    }else if(joint_type == MITER_JOINT){\n        shift = buff * (-1.0 - cos(angle)) / sin(angle);\n    }else{\n        // For a Bevel joint\n        shift = buff * (1.0 - cos(angle)) / sin(angle);\n    }\n    changing_c0 = static_c0 - shift * unit_tan;\n    changing_c1 = static_c1 + shift * unit_tan;\n}\n\n\n// This function is responsible for finding the corners of\n// a bounding region around the bezier curve, which can be\n// emitted as a triangle fan\nint get_corners(vec2 controls[3], int degree, float stroke_widths[3], out vec2 corners[5]){\n    vec2 p0 = controls[0];\n    vec2 p1 = controls[1];\n    vec2 p2 = controls[2];\n\n    // Unit vectors for directions between control points\n    vec2 v10 = normalize(p0 - p1);\n    vec2 v12 = normalize(p2 - p1);\n    vec2 v01 = -v10;\n    vec2 v21 = -v12;\n\n    vec2 p0_perp = vec2(-v01.y, v01.x);  // Pointing to the left of the curve from p0\n    vec2 p2_perp = vec2(-v12.y, v12.x);  // Pointing to the left of the curve from p2\n\n    // aaw is the added width given around the polygon for antialiasing.\n    // In case the normal is faced away from (0, 0, 1), the vector to the\n    // camera, this is scaled up.\n    float aaw = anti_alias_width;\n    float buff0 = 0.5 * stroke_widths[0] + aaw;\n    float buff2 = 0.5 * stroke_widths[2] + aaw;\n    float aaw0 = (1 - has_prev) * aaw;\n    float aaw2 = (1 - has_next) * aaw;\n\n    vec2 c0 = p0 - buff0 * p0_perp + aaw0 * v10;\n    vec2 c1 = p0 + buff0 * p0_perp + aaw0 * v10;\n    vec2 c2 = p2 + buff2 * p2_perp + aaw2 * v12;\n    vec2 c3 = p2 - buff2 * p2_perp + aaw2 * v12;\n\n    // Account for previous and next control points\n    if(has_prev > 0) create_joint(angle_from_prev, v01, buff0, c0, c0, c1, c1);\n    if(has_next > 0) create_joint(angle_to_next, v21, buff2, c3, c3, c2, c2);\n\n    // Linear case is the simplest\n    if(degree == 1){\n        // The order of corners should be for a triangle_strip.  Last entry is a dummy\n        corners = vec2[5](c0, c1, c3, c2, vec2(0.0));\n        return 4;\n    }\n    // Otherwise, form a pentagon around the curve\n    float orientation = sign(cross2d(v01, v12));  // Positive for ccw curves\n    if(orientation > 0) corners = vec2[5](c0, c1, p1, c2, c3);\n    else                corners = vec2[5](c1, c0, p1, c3, c2);\n    // Replace corner[2] with convex hull point accounting for stroke width\n    find_intersection(corners[0], v01, corners[4], v21, corners[2]);\n    return 5;\n}\n\n\nvoid set_adjascent_info(vec2 c0, vec2 tangent,\n                        int degree,\n                        vec2 adj[3],\n                        out float bevel,\n                        out float angle\n                        ){\n    bool linear_adj = (angle_between_vectors(adj[1] - adj[0], adj[2] - adj[1]) < 1e-3);\n    angle = angle_between_vectors(c0 - adj[1], tangent);\n    // Decide on joint type\n    bool one_linear = (degree == 1 || linear_adj);\n    bool should_bevel = (\n        (joint_type == AUTO_JOINT && one_linear) ||\n        joint_type == BEVEL_JOINT\n    );\n    bevel = should_bevel ? 1.0 : 0.0;\n}\n\n\nvoid find_joint_info(vec2 controls[3], vec2 prev[3], vec2 next[3], int degree){\n    float tol = 1e-6;\n\n    // Made as floats not bools so they can be passed to the frag shader\n    has_prev = float(distance(prev[2], controls[0]) < tol);\n    has_next = float(distance(next[0], controls[2]) < tol);\n\n    if(bool(has_prev)){\n        vec2 tangent = controls[1] - controls[0];\n        set_adjascent_info(\n            controls[0], tangent, degree, prev,\n            bevel_start, angle_from_prev\n        );\n    }\n    if(bool(has_next)){\n        vec2 tangent = controls[1] - controls[2];\n        set_adjascent_info(\n            controls[2], tangent, degree, next,\n            bevel_end, angle_to_next\n        );\n        angle_to_next *= -1;\n    }\n}\n\n\nvoid main() {\n    // Convert control points to a standard form if they are linear or null\n    vec3 controls[3];\n    vec3 prev[3];\n    vec3 next[3];\n    bezier_degree = get_reduced_control_points(vec3[3](bp[0], bp[1], bp[2]), controls);\n    if(bezier_degree == 0.0) return;  // Null curve\n    int degree = int(bezier_degree);\n    get_reduced_control_points(vec3[3](prev_bp[0], prev_bp[1], prev_bp[2]), prev);\n    get_reduced_control_points(vec3[3](next_bp[0], next_bp[1], next_bp[2]), next);\n\n\n    // Adjust stroke width based on distance from the camera\n    float scaled_strokes[3];\n    for(int i = 0; i < 3; i++){\n        float sf = perspective_scale_factor(controls[i].z, focal_distance);\n        if(bool(flat_stroke)){\n            vec3 to_cam = normalize(vec3(0.0, 0.0, focal_distance) - controls[i]);\n            sf *= abs(dot(v_global_unit_normal[i], to_cam));\n        }\n        scaled_strokes[i] = v_stroke_width[i] * sf;\n    }\n\n    // Control points are projected to the xy plane before drawing, which in turn\n    // gets translated to a uv plane.  The z-coordinate information will be remembered\n    // by what's sent out to gl_Position, and by how it affects the lighting and stroke width\n    vec2 flat_controls[3];\n    vec2 flat_prev[3];\n    vec2 flat_next[3];\n    flatten_points(controls, flat_controls);\n    flatten_points(prev, flat_prev);\n    flatten_points(next, flat_next);\n\n    find_joint_info(flat_controls, flat_prev, flat_next, degree);\n\n    // Corners of a bounding region around curve\n    vec2 corners[5];\n    int n_corners = get_corners(flat_controls, degree, scaled_strokes, corners);\n\n    int index_map[5] = int[5](0, 0, 1, 2, 2);\n    if(n_corners == 4) index_map[2] = 2;\n\n    // Find uv conversion matrix\n    mat3 xy_to_uv = get_xy_to_uv(flat_controls[0], flat_controls[1]);\n    float scale_factor = length(flat_controls[1] - flat_controls[0]);\n    uv_anti_alias_width = anti_alias_width / scale_factor;\n    uv_b2 = (xy_to_uv * vec3(flat_controls[2], 1.0)).xy;\n\n    // Emit each corner\n    for(int i = 0; i < n_corners; i++){\n        uv_coords = (xy_to_uv * vec3(corners[i], 1.0)).xy;\n        uv_stroke_width = scaled_strokes[index_map[i]] / scale_factor;\n        // Apply some lighting to the color before sending out.\n        // vec3 xyz_coords = vec3(corners[i], controls[index_map[i]].z);\n        vec3 xyz_coords = vec3(corners[i], controls[index_map[i]].z);\n        color = finalize_color(\n            v_color[index_map[i]],\n            xyz_coords,\n            v_global_unit_normal[index_map[i]],\n            light_source_position,\n            gloss,\n            shadow\n        );\n        gl_Position = vec4(\n            get_gl_Position(vec3(corners[i], 0.0)).xy,\n            get_gl_Position(controls[index_map[i]]).zw\n        );\n        EmitVertex();\n    }\n    EndPrimitive();\n}\n"
  },
  {
    "path": "manim/renderer/shaders/quadratic_bezier_stroke/vert.glsl",
    "content": "#version 330\n\n#include ../include/camera_uniform_declarations.glsl\n\nin vec3 point;\nin vec3 prev_point;\nin vec3 next_point;\nin vec3 unit_normal;\n\nin float stroke_width;\nin vec4 color;\n\n// Bezier control point\nout vec3 bp;\nout vec3 prev_bp;\nout vec3 next_bp;\nout vec3 v_global_unit_normal;\n\nout float v_stroke_width;\nout vec4 v_color;\n\nconst float STROKE_WIDTH_CONVERSION = 0.01;\n\n#include ../include/position_point_into_frame.glsl\n\nvoid main(){\n    bp = position_point_into_frame(point);\n    prev_bp = position_point_into_frame(prev_point);\n    next_bp = position_point_into_frame(next_point);\n    v_global_unit_normal = rotate_point_into_frame(unit_normal);\n\n    v_stroke_width = STROKE_WIDTH_CONVERSION * stroke_width;\n    v_color = color;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/simple_vert.glsl",
    "content": "#version 330\n\n#include ../include/camera_uniform_declarations.glsl\n\nin vec3 point;\n\n// Analog of import for manim only\n#include ../include/get_gl_Position.glsl\n#include ../include/position_point_into_frame.glsl\n\nvoid main(){\n    gl_Position = get_gl_Position(position_point_into_frame(point));\n}\n"
  },
  {
    "path": "manim/renderer/shaders/surface/frag.glsl",
    "content": "#version 330\n\nuniform vec3 light_source_position;\nuniform float gloss;\nuniform float shadow;\n\nin vec3 xyz_coords;\nin vec3 v_normal;\nin vec4 v_color;\n\nout vec4 frag_color;\n\n#include ../include/finalize_color.glsl\n\nvoid main() {\n    frag_color = finalize_color(\n        v_color,\n        xyz_coords,\n        normalize(v_normal),\n        light_source_position,\n        gloss,\n        shadow\n    );\n}\n"
  },
  {
    "path": "manim/renderer/shaders/surface/vert.glsl",
    "content": "#version 330\n\n#include ../include/camera_uniform_declarations.glsl\n\nin vec3 point;\nin vec3 du_point;\nin vec3 dv_point;\nin vec4 color;\n\nout vec3 xyz_coords;\nout vec3 v_normal;\nout vec4 v_color;\n\n#include ../include/position_point_into_frame.glsl\n#include ../include/get_gl_Position.glsl\n#include ../include/get_rotated_surface_unit_normal_vector.glsl\n\nvoid main(){\n    xyz_coords = position_point_into_frame(point);\n    v_normal = get_rotated_surface_unit_normal_vector(point, du_point, dv_point);\n    v_color = color;\n    gl_Position = get_gl_Position(xyz_coords);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/test/frag.glsl",
    "content": "#version 330\n\nin vec4 v_color;\n\nout vec4 frag_color;\n\nvoid main() {\n    frag_color = v_color;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/test/vert.glsl",
    "content": "#version 330\n\nin vec2 in_vert;\nin vec4 in_color;\n\nout vec4 v_color;\n\nvoid main() {\n    v_color = in_color;\n    gl_Position = vec4(in_vert, 0.0, 1.0);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/textured_surface/frag.glsl",
    "content": "#version 330\n\nuniform sampler2D LightTexture;\nuniform sampler2D DarkTexture;\nuniform float num_textures;\nuniform vec3 light_source_position;\nuniform float gloss;\nuniform float shadow;\n\nin vec3 xyz_coords;\nin vec3 v_normal;\nin vec2 v_im_coords;\nin float v_opacity;\n\nout vec4 frag_color;\n\n#include ../include/finalize_color.glsl\n\nconst float dark_shift = 0.2;\n\nvoid main() {\n    vec4 color = texture(LightTexture, v_im_coords);\n    if(num_textures == 2.0){\n        vec4 dark_color = texture(DarkTexture, v_im_coords);\n        float dp = dot(\n            normalize(light_source_position - xyz_coords),\n            normalize(v_normal)\n        );\n        float alpha = smoothstep(-dark_shift, dark_shift, dp);\n        color = mix(dark_color, color, alpha);\n    }\n\n    frag_color = finalize_color(\n        color,\n        xyz_coords,\n        normalize(v_normal),\n        light_source_position,\n        gloss,\n        shadow\n    );\n    frag_color.a = v_opacity;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/textured_surface/vert.glsl",
    "content": "#version 330\n\n#include ../include/camera_uniform_declarations.glsl\n\nin vec3 point;\nin vec3 du_point;\nin vec3 dv_point;\nin vec2 im_coords;\nin float opacity;\n\nout vec3 xyz_coords;\nout vec3 v_normal;\nout vec2 v_im_coords;\nout float v_opacity;\n\n#include ../include/position_point_into_frame.glsl\n#include ../include/get_gl_Position.glsl\n#include ../include/get_rotated_surface_unit_normal_vector.glsl\n\nvoid main(){\n    xyz_coords = position_point_into_frame(point);\n    v_normal = get_rotated_surface_unit_normal_vector(point, du_point, dv_point);\n    v_im_coords = im_coords;\n    v_opacity = opacity;\n    gl_Position = get_gl_Position(xyz_coords);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/true_dot/frag.glsl",
    "content": "#version 330\n\nuniform vec3 light_source_position;\nuniform float gloss;\nuniform float shadow;\nuniform float anti_alias_width;\n\nin vec4 color;\nin float point_radius;\nin vec2 center;\nin vec2 point;\n\nout vec4 frag_color;\n\n#include ../include/finalize_color.glsl\n\nvoid main() {\n    vec2 diff = point - center;\n    float dist = length(diff);\n    float signed_dist = dist - point_radius;\n    if (signed_dist > 0.5 * anti_alias_width){\n        discard;\n    }\n    vec3 normal = vec3(diff / point_radius, sqrt(1 - (dist * dist) / (point_radius * point_radius)));\n    frag_color = finalize_color(\n        color,\n        vec3(point.xy, 0.0),\n        normal,\n        light_source_position,\n        gloss,\n        shadow\n    );\n    frag_color.a *= smoothstep(0.5, -0.5, signed_dist / anti_alias_width);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/true_dot/geom.glsl",
    "content": "#version 330\n\nlayout (points) in;\nlayout (triangle_strip, max_vertices = 4) out;\n\n// Needed for get_gl_Position\nuniform vec2 frame_shape;\nuniform float focal_distance;\nuniform float is_fixed_in_frame;\nuniform float is_fixed_orientation;\nuniform vec3 fixed_orientation_center;\nuniform float anti_alias_width;\n\nin vec3 v_point[1];\nin float v_point_radius[1];\nin vec4 v_color[1];\n\nout vec4 color;\nout float point_radius;\nout vec2 center;\nout vec2 point;\n\n#include ../include/get_gl_Position.glsl\n\nvoid main() {\n    color = v_color[0];\n    point_radius = v_point_radius[0];\n    center = v_point[0].xy;\n\n    point_radius = v_point_radius[0] / max(1.0 - v_point[0].z / focal_distance / frame_shape.y, 0.0);\n    float rpa = point_radius + anti_alias_width;\n\n    for(int i = 0; i < 4; i++){\n        // To account for perspective\n\n        int x_index = 2 * (i % 2) - 1;\n        int y_index = 2 * (i / 2) - 1;\n        vec3 corner = v_point[0] + vec3(x_index * rpa, y_index * rpa, 0.0);\n\n        gl_Position = get_gl_Position(corner);\n        point = corner.xy;\n        EmitVertex();\n    }\n    EndPrimitive();\n}\n"
  },
  {
    "path": "manim/renderer/shaders/true_dot/vert.glsl",
    "content": "#version 330\n\n#include ../include/camera_uniform_declarations.glsl\n\nin vec3 point;\nin vec4 color;\n\nuniform float point_radius;\n\nout vec3 v_point;\nout float v_point_radius;\nout vec4 v_color;\n\n#include ../include/position_point_into_frame.glsl\n\nvoid main(){\n    v_point = position_point_into_frame(point);\n    v_point_radius = point_radius;\n    v_color = color;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/vectorized_mobject_fill/frag.glsl",
    "content": "#version 330\n\nin vec4 v_color;\nin vec2 v_texture_coords;\nflat in int v_texture_mode;\n\nout vec4 frag_color;\n\nvoid main() {\n    float curve_func = v_texture_coords[0] * v_texture_coords[0] - v_texture_coords[1];\n    if (v_texture_mode * curve_func >= 0.0) {\n        frag_color = v_color;\n    } else {\n        discard;\n    }\n}\n"
  },
  {
    "path": "manim/renderer/shaders/vectorized_mobject_fill/vert.glsl",
    "content": "#version 330\n\nuniform mat4 u_model_view_matrix;\nuniform mat4 u_projection_matrix;\n\nin vec3 in_vert;\nin vec4 in_color;\nin vec2 texture_coords;\nin int texture_mode;\n\nout vec4 v_color;\nout vec2 v_texture_coords;\nflat out int v_texture_mode;\n\nvoid main() {\n    v_color = in_color;\n    v_texture_coords = texture_coords;\n    v_texture_mode = texture_mode;\n    gl_Position = u_projection_matrix * u_model_view_matrix * vec4(in_vert, 1.0);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/vectorized_mobject_stroke/frag.glsl",
    "content": "#version 330\n\nin float v_degree;\nin float v_thickness;\nin vec2 uv_point;\nin vec2[3] uv_curve;\nin vec4 v_color;\n\nout vec4 frag_color;\n\n// https://www.shadertoy.com/view/ltXSDB\n// Test if point p crosses line (a, b), returns sign of result\nfloat testCross(vec2 a, vec2 b, vec2 p) {\n    return sign((b.y-a.y) * (p.x-a.x) - (b.x-a.x) * (p.y-a.y));\n}\n\n// Determine which side we're on (using barycentric parameterization)\nfloat signBezier(vec2 A, vec2 B, vec2 C, vec2 p)\n{\n    vec2 a = C - A, b = B - A, c = p - A;\n    vec2 bary = vec2(c.x*b.y-b.x*c.y,a.x*c.y-c.x*a.y) / (a.x*b.y-b.x*a.y);\n    vec2 d = vec2(bary.y * 0.5, 0.0) + 1.0 - bary.x - bary.y;\n    return mix(sign(d.x * d.x - d.y), mix(-1.0, 1.0,\n        step(testCross(A, B, p) * testCross(B, C, p), 0.0)),\n        step((d.x - d.y), 0.0)) * testCross(A, C, B);\n}\n\n// Solve cubic equation for roots\nvec3 solveCubic(float a, float b, float c)\n{\n    float p = b - a*a / 3.0, p3 = p*p*p;\n    float q = a * (2.0*a*a - 9.0*b) / 27.0 + c;\n    float d = q*q + 4.0*p3 / 27.0;\n    float offset = -a / 3.0;\n    if(d >= 0.0) {\n        float z = sqrt(d);\n        vec2 x = (vec2(z, -z) - q) / 2.0;\n        vec2 uv = sign(x)*pow(abs(x), vec2(1.0/3.0));\n        return vec3(offset + uv.x + uv.y);\n    }\n    float v = acos(-sqrt(-27.0 / p3) * q / 2.0) / 3.0;\n    float m = cos(v), n = sin(v)*1.732050808;\n    return vec3(m + m, -n - m, n - m) * sqrt(-p / 3.0) + offset;\n}\n\n// Find the signed distance from a point to a bezier curve\nfloat sdBezier(vec2 A, vec2 B, vec2 C, vec2 p)\n{\n    B = mix(B + vec2(1e-4), B, abs(sign(B * 2.0 - A - C)));\n    vec2 a = B - A, b = A - B * 2.0 + C, c = a * 2.0, d = A - p;\n    vec3 k = vec3(3.*dot(a,b),2.*dot(a,a)+dot(d,b),dot(d,a)) / dot(b,b);\n    vec3 t = clamp(solveCubic(k.x, k.y, k.z), 0.0, 1.0);\n    vec2 pos = A + (c + b*t.x)*t.x;\n    float dis = length(pos - p);\n    pos = A + (c + b*t.y)*t.y;\n    dis = min(dis, length(pos - p));\n    pos = A + (c + b*t.z)*t.z;\n    dis = min(dis, length(pos - p));\n    return dis * signBezier(A, B, C, p);\n}\n\n// https://www.shadertoy.com/view/llcfR7\nfloat dLine(vec2 p1, vec2 p2, vec2 x) {\n    vec4 colA = vec4(clamp (5.0 - length (x - p1), 0.0, 1.0));\n    vec4 colB = vec4(clamp (5.0 - length (x - p2), 0.0, 1.0));\n\n    vec2 a_p1 = x - p1;\n    vec2 p2_p1 = p2 - p1;\n    float h = clamp (dot (a_p1, p2_p1) / dot (p2_p1, p2_p1), 0.0, 1.0);\n    return length (a_p1 - p2_p1 * h);\n}\n\nvoid main() {\n    float distance;\n    if (v_degree == 2.0) {\n        distance = sdBezier(uv_curve[0], uv_curve[1], uv_curve[2], uv_point);\n    } else {\n        distance = dLine(uv_curve[0], uv_curve[2], uv_point);\n    }\n    if (abs(distance) < v_thickness) {\n        frag_color = v_color;\n    } else {\n        discard;\n    }\n}\n"
  },
  {
    "path": "manim/renderer/shaders/vectorized_mobject_stroke/vert.glsl",
    "content": "#version 330\n\nuniform vec3 manim_unit_normal;\nuniform mat4 u_model_view_matrix;\nuniform mat4 u_projection_matrix;\n\nin vec3[3] current_curve;\nin vec2 tile_coordinate;\nin vec4 in_color;\nin float in_width;\n\nout float v_degree;\nout float v_thickness;\nout vec2 uv_point;\nout vec2[3] uv_curve;\nout vec4 v_color;\n\nint get_degree(in vec3 points[3], out vec3 normal) {\n    float length_threshold = 1e-6;\n    float angle_threshold = 5e-2;\n\n    vec3 v01 = (points[1] - points[0]);\n    vec3 v12 = (points[2] - points[1]);\n\n    float dot_prod = clamp(dot(normalize(v01), normalize(v12)), -1, 1);\n    bool aligned = acos(dot_prod) < angle_threshold;\n    bool distinct_01 = length(v01) > length_threshold;  // v01 is considered nonzero\n    bool distinct_12 = length(v12) > length_threshold;  // v12 is considered nonzero\n    int num_distinct = int(distinct_01) + int(distinct_12);\n\n    bool quadratic = (num_distinct == 2) && !aligned;\n    bool linear = (num_distinct == 1) || ((num_distinct == 2) && aligned);\n    bool constant = (num_distinct == 0);\n\n    if (quadratic) {\n        // If the curve is quadratic pass a normal vector to the caller.\n        normal = normalize(cross(v01, v12));\n        return 2;\n    } else if (linear) {\n        return 1;\n    } else {\n        return 0;\n    }\n}\n\n// https://iquilezles.org/www/articles/bezierbbox/bezierbbox.htm\nvec4 bboxBezier(in vec2 p0, in vec2 p1, in vec2 p2) {\n    vec2 mi = min(p0, p2);\n    vec2 ma = max(p0, p2);\n\n    if (p1.x < mi.x || p1.x > ma.x || p1.y < mi.y || p1.y > ma.y) {\n        vec2 t = clamp((p0 - p1) / (p0 - 2.0 * p1 + p2), 0.0, 1.0);\n        vec2 s = 1.0 - t;\n        vec2 q = s * s * p0 + 2.0 * s * t * p1 + t * t * p2;\n        mi = min(mi, q);\n        ma = max(ma, q);\n    }\n\n    return vec4(mi, ma);\n}\n\nvec2 convert_to_uv(vec3 x_unit, vec3 y_unit, vec3 point) {\n    return vec2(dot(point, x_unit), dot(point, y_unit));\n}\n\nvec3 convert_from_uv(vec3 translation, vec3 x_unit, vec3 y_unit, vec2 point) {\n    vec3 untranslated_point = point[0] * x_unit + point[1] * y_unit;\n    return untranslated_point + translation;\n}\n\nvoid main() {\n    float thickness_multiplier = 0.004;\n    v_color = in_color;\n\n    vec3 computed_normal;\n    v_degree = get_degree(current_curve, computed_normal);\n\n    vec3 tile_x_unit = normalize(current_curve[2] - current_curve[0]);\n    vec3 unit_normal;\n    vec3 tile_y_unit;\n    if (v_degree == 0) {\n        tile_y_unit = vec3(0.0, 0.0, 0.0);\n    } else if (v_degree == 1) {\n        // Since the curve forms a straight line there's no way to compute a normal.\n        unit_normal = manim_unit_normal;\n\n        tile_y_unit = cross(unit_normal, tile_x_unit);\n    } else {\n        // Prefer to use a computed normal vector rather than the one from manim.\n        unit_normal = computed_normal;\n\n        // Ensure tile_y_unit is pointing toward p1 from p0.\n        tile_y_unit = cross(unit_normal, tile_x_unit);\n        if (dot(tile_y_unit, current_curve[1] - current_curve[0]) < 0) {\n            tile_y_unit *= -1;\n        }\n    }\n\n    // Project the curve onto the tile.\n    for(int i = 0; i < 3; i++) {\n        uv_curve[i] = convert_to_uv(tile_x_unit, tile_y_unit, current_curve[i]);\n    }\n\n    // Compute the curve's bounding box.\n    vec4 uv_bounding_box = bboxBezier(uv_curve[0], uv_curve[1], uv_curve[2]);\n    vec3 tile_translation = unit_normal * dot(current_curve[0], unit_normal);\n    vec3 bounding_box_min = convert_from_uv(tile_translation, tile_x_unit, tile_y_unit, uv_bounding_box.xy);\n    vec3 bounding_box_max = convert_from_uv(tile_translation, tile_x_unit, tile_y_unit, uv_bounding_box.zw);\n    vec3 bounding_box_vec = bounding_box_max - bounding_box_min;\n    vec3 tile_origin = bounding_box_min;\n    vec3 tile_x_vec = tile_x_unit * dot(tile_x_unit, bounding_box_vec);\n    vec3 tile_y_vec = tile_y_unit * dot(tile_y_unit, bounding_box_vec);\n\n    // Expand the tile according to the line's thickness.\n    v_thickness = thickness_multiplier * in_width;\n    tile_origin = current_curve[0] - v_thickness * (tile_x_unit + tile_y_unit);\n    tile_x_vec += 2 * v_thickness * tile_x_unit;\n    tile_y_vec += 2 * v_thickness * tile_y_unit;\n\n    vec3 tile_point = tile_origin + \\\n                      tile_coordinate[0] * tile_x_vec + \\\n                      tile_coordinate[1] * tile_y_vec;\n    gl_Position = u_projection_matrix * u_model_view_matrix * vec4(tile_point, 1.0);\n    uv_point = convert_to_uv(tile_x_unit, tile_y_unit, tile_point);\n}\n"
  },
  {
    "path": "manim/renderer/shaders/vertex_colors/frag.glsl",
    "content": "#version 330\n\nin vec4 v_color;\nout vec4 frag_color;\n\nvoid main() {\n  frag_color = v_color;\n}\n"
  },
  {
    "path": "manim/renderer/shaders/vertex_colors/vert.glsl",
    "content": "#version 330\n\nuniform mat4 u_model_matrix;\nuniform mat4 u_view_matrix;\nuniform mat4 u_projection_matrix;\nin vec4 in_vert;\nin vec4 in_color;\nout vec4 v_color;\n\nvoid main() {\n    v_color = in_color;\n    gl_Position = u_projection_matrix * u_view_matrix * u_model_matrix * in_vert;\n}\n"
  },
  {
    "path": "manim/renderer/vectorized_mobject_rendering.py",
    "content": "from __future__ import annotations\n\nfrom collections import defaultdict\nfrom collections.abc import Iterable, Sequence\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\n\nif TYPE_CHECKING:\n    from manim.renderer.opengl_renderer import (\n        OpenGLRenderer,\n        OpenGLVMobject,\n    )\n    from manim.typing import MatrixMN\n\nfrom ..utils import opengl\nfrom ..utils.space_ops import cross2d, earclip_triangulation\nfrom .shader import Shader\n\n__all__ = [\n    \"render_opengl_vectorized_mobject_fill\",\n    \"render_opengl_vectorized_mobject_stroke\",\n]\n\n\ndef build_matrix_lists(\n    mob: OpenGLVMobject,\n) -> defaultdict[tuple[float, ...], list[OpenGLVMobject]]:\n    root_hierarchical_matrix = mob.hierarchical_model_matrix()\n    matrix_to_mobject_list = defaultdict(list)\n    if mob.has_points():\n        matrix_to_mobject_list[tuple(root_hierarchical_matrix.ravel())].append(mob)\n    mobject_to_hierarchical_matrix = {mob: root_hierarchical_matrix}\n    dfs = [mob]\n    while dfs:\n        parent = dfs.pop()\n        for child in parent.submobjects:\n            child_hierarchical_matrix = (\n                mobject_to_hierarchical_matrix[parent] @ child.model_matrix\n            )\n            mobject_to_hierarchical_matrix[child] = child_hierarchical_matrix\n            if child.has_points():\n                matrix_to_mobject_list[tuple(child_hierarchical_matrix.ravel())].append(\n                    child,\n                )\n            dfs.append(child)\n    return matrix_to_mobject_list\n\n\ndef render_opengl_vectorized_mobject_fill(\n    renderer: OpenGLRenderer, mobject: OpenGLVMobject\n) -> None:\n    matrix_to_mobject_list = build_matrix_lists(mobject)\n\n    for matrix_tuple, mobject_list in matrix_to_mobject_list.items():\n        model_matrix = np.array(matrix_tuple).reshape((4, 4))\n        render_mobject_fills_with_matrix(renderer, model_matrix, mobject_list)\n\n\ndef render_mobject_fills_with_matrix(\n    renderer: OpenGLRenderer,\n    model_matrix: MatrixMN,\n    mobjects: Iterable[OpenGLVMobject],\n) -> None:\n    # Precompute the total number of vertices for which to reserve space.\n    # Note that triangulate_mobject() will cache its results.\n    total_size = 0\n    for submob in mobjects:\n        total_size += triangulate_mobject(submob).shape[0]\n\n    attributes = np.empty(\n        total_size,\n        dtype=[\n            (\"in_vert\", np.float32, (3,)),\n            (\"in_color\", np.float32, (4,)),\n            (\"texture_coords\", np.float32, (2,)),\n            (\"texture_mode\", np.int32),\n        ],\n    )\n\n    write_offset = 0\n    for submob in mobjects:\n        if not submob.has_points():\n            continue\n        mobject_triangulation = triangulate_mobject(submob)\n        end_offset = write_offset + mobject_triangulation.shape[0]\n        attributes[write_offset:end_offset] = mobject_triangulation\n        attributes[\"in_color\"][write_offset:end_offset] = np.repeat(\n            submob.fill_rgba,\n            mobject_triangulation.shape[0],\n            axis=0,\n        )\n        write_offset = end_offset\n\n    fill_shader = Shader(renderer.context, name=\"vectorized_mobject_fill\")\n    fill_shader.set_uniform(\n        \"u_model_view_matrix\",\n        opengl.matrix_to_shader_input(\n            renderer.camera.unformatted_view_matrix @ model_matrix,\n        ),\n    )\n    fill_shader.set_uniform(\n        \"u_projection_matrix\",\n        renderer.camera.projection_matrix,\n    )\n\n    vbo = renderer.context.buffer(attributes.tobytes())\n    vao = renderer.context.simple_vertex_array(\n        fill_shader.shader_program,\n        vbo,\n        *attributes.dtype.names,\n    )\n    vao.render()\n    vao.release()\n    vbo.release()\n\n\ndef triangulate_mobject(mob: OpenGLVMobject) -> np.ndarray:\n    if not mob.needs_new_triangulation:\n        return mob.triangulation\n\n    # Figure out how to triangulate the interior to know\n    # how to send the points as to the vertex shader.\n    # First triangles come directly from the points\n    # normal_vector = mob.get_unit_normal()\n    points = mob.points\n\n    b0s = points[0::3]\n    b1s = points[1::3]\n    b2s = points[2::3]\n    v01s = b1s - b0s\n    v12s = b2s - b1s\n\n    crosses = cross2d(v01s, v12s)\n    convexities = np.sign(crosses)\n    if mob.orientation == 1:\n        concave_parts = convexities > 0\n        convex_parts = convexities <= 0\n    else:\n        concave_parts = convexities < 0\n        convex_parts = convexities >= 0\n\n    # These are the vertices to which we'll apply a polygon triangulation\n    atol = mob.tolerance_for_point_equality\n    end_of_loop = np.zeros(len(b0s), dtype=bool)\n    end_of_loop[:-1] = (np.abs(b2s[:-1] - b0s[1:]) > atol).any(1)\n    end_of_loop[-1] = True\n\n    indices = np.arange(len(points), dtype=int)\n    inner_vert_indices = np.hstack(\n        [\n            indices[0::3],\n            indices[1::3][concave_parts],\n            indices[2::3][end_of_loop],\n        ],\n    )\n    inner_vert_indices.sort()\n    rings = np.arange(1, len(inner_vert_indices) + 1)[inner_vert_indices % 3 == 2]\n\n    # Triangulate\n    inner_verts = points[inner_vert_indices]\n    inner_tri_indices = inner_vert_indices[earclip_triangulation(inner_verts, rings)]\n\n    bezier_triangle_indices = np.reshape(indices, (-1, 3))\n    concave_triangle_indices = np.reshape(bezier_triangle_indices[concave_parts], (-1))\n    convex_triangle_indices = np.reshape(bezier_triangle_indices[convex_parts], (-1))\n\n    points = points[\n        np.hstack(\n            [\n                concave_triangle_indices,\n                convex_triangle_indices,\n                inner_tri_indices,\n            ],\n        )\n    ]\n    texture_coords = np.tile(\n        [\n            [0.0, 0.0],\n            [0.5, 0.0],\n            [1.0, 1.0],\n        ],\n        (points.shape[0] // 3, 1),\n    )\n    texture_mode = np.hstack(\n        (\n            np.ones(concave_triangle_indices.shape[0]),\n            -1 * np.ones(convex_triangle_indices.shape[0]),\n            np.zeros(inner_tri_indices.shape[0]),\n        ),\n    )\n\n    attributes = np.zeros(\n        points.shape[0],\n        dtype=[\n            (\"in_vert\", np.float32, (3,)),\n            (\"in_color\", np.float32, (4,)),\n            (\"texture_coords\", np.float32, (2,)),\n            (\"texture_mode\", np.int32),\n        ],\n    )\n    attributes[\"in_vert\"] = points\n    attributes[\"texture_coords\"] = texture_coords\n    attributes[\"texture_mode\"] = texture_mode\n\n    mob.triangulation = attributes\n    mob.needs_new_triangulation = False\n\n    return attributes\n\n\ndef render_opengl_vectorized_mobject_stroke(\n    renderer: OpenGLRenderer, mobject: OpenGLVMobject\n) -> None:\n    matrix_to_mobject_list = build_matrix_lists(mobject)\n    for matrix_tuple, mobject_list in matrix_to_mobject_list.items():\n        model_matrix = np.array(matrix_tuple).reshape((4, 4))\n        render_mobject_strokes_with_matrix(renderer, model_matrix, mobject_list)\n\n\ndef render_mobject_strokes_with_matrix(\n    renderer: OpenGLRenderer,\n    model_matrix: MatrixMN,\n    mobjects: Sequence[OpenGLVMobject],\n) -> None:\n    # Precompute the total number of vertices for which to reserve space.\n    total_size = 0\n    for submob in mobjects:\n        total_size += submob.points.shape[0]\n\n    points = np.empty((total_size, 3))\n    colors = np.empty((total_size, 4))\n    widths = np.empty(total_size)\n\n    write_offset = 0\n    for submob in mobjects:\n        if not submob.has_points():\n            continue\n        end_offset = write_offset + submob.points.shape[0]\n\n        points[write_offset:end_offset] = submob.points\n        if submob.stroke_rgba.shape[0] == points[write_offset:end_offset].shape[0]:\n            colors[write_offset:end_offset] = submob.stroke_rgba\n        else:\n            colors[write_offset:end_offset] = np.repeat(\n                submob.stroke_rgba,\n                submob.points.shape[0],\n                axis=0,\n            )\n        widths[write_offset:end_offset] = np.repeat(\n            submob.stroke_width,\n            submob.points.shape[0],\n        )\n        write_offset = end_offset\n\n    stroke_data = np.zeros(\n        len(points),\n        dtype=[\n            # (\"previous_curve\", np.float32, (3, 3)),\n            (\"current_curve\", np.float32, (3, 3)),\n            # (\"next_curve\", np.float32, (3, 3)),\n            (\"tile_coordinate\", np.float32, (2,)),\n            (\"in_color\", np.float32, (4,)),\n            (\"in_width\", np.float32),\n        ],\n    )\n\n    stroke_data[\"in_color\"] = colors\n    stroke_data[\"in_width\"] = widths\n    curves = np.reshape(points, (-1, 3, 3))\n    # stroke_data[\"previous_curve\"] = np.repeat(np.roll(curves, 1, axis=0), 3, axis=0)\n    stroke_data[\"current_curve\"] = np.repeat(curves, 3, axis=0)\n    # stroke_data[\"next_curve\"] = np.repeat(np.roll(curves, -1, axis=0), 3, axis=0)\n\n    # Repeat each vertex in order to make a tile.\n    stroke_data = np.tile(stroke_data, 2)\n    stroke_data[\"tile_coordinate\"] = np.vstack(\n        (\n            np.tile(\n                [\n                    [0.0, 0.0],\n                    [0.0, 1.0],\n                    [1.0, 1.0],\n                ],\n                (len(points) // 3, 1),\n            ),\n            np.tile(\n                [\n                    [0.0, 0.0],\n                    [1.0, 0.0],\n                    [1.0, 1.0],\n                ],\n                (len(points) // 3, 1),\n            ),\n        ),\n    )\n\n    shader = Shader(renderer.context, \"vectorized_mobject_stroke\")\n    shader.set_uniform(\n        \"u_model_view_matrix\",\n        opengl.matrix_to_shader_input(\n            renderer.camera.unformatted_view_matrix @ model_matrix,\n        ),\n    )\n    shader.set_uniform(\"u_projection_matrix\", renderer.camera.projection_matrix)\n    shader.set_uniform(\"manim_unit_normal\", tuple(-mobjects[0].unit_normal[0]))\n\n    vbo = renderer.context.buffer(stroke_data.tobytes())\n    vao = renderer.context.simple_vertex_array(\n        shader.shader_program, vbo, *stroke_data.dtype.names\n    )\n    renderer.frame_buffer_object.use()\n    vao.render()\n    vao.release()\n    vbo.release()\n"
  },
  {
    "path": "manim/scene/__init__.py",
    "content": ""
  },
  {
    "path": "manim/scene/moving_camera_scene.py",
    "content": "\"\"\"A scene whose camera can be moved around.\n\n.. SEEALSO::\n\n    :mod:`.moving_camera`\n\n\nExamples\n--------\n\n.. manim:: ChangingCameraWidthAndRestore\n\n    class ChangingCameraWidthAndRestore(MovingCameraScene):\n        def construct(self):\n            text = Text(\"Hello World\").set_color(BLUE)\n            self.add(text)\n            self.camera.frame.save_state()\n            self.play(self.camera.frame.animate.set(width=text.width * 1.2))\n            self.wait(0.3)\n            self.play(Restore(self.camera.frame))\n\n\n.. manim:: MovingCameraCenter\n\n    class MovingCameraCenter(MovingCameraScene):\n        def construct(self):\n            s = Square(color=RED, fill_opacity=0.5).move_to(2 * LEFT)\n            t = Triangle(color=GREEN, fill_opacity=0.5).move_to(2 * RIGHT)\n            self.wait(0.3)\n            self.add(s, t)\n            self.play(self.camera.frame.animate.move_to(s))\n            self.wait(0.3)\n            self.play(self.camera.frame.animate.move_to(t))\n\n\n.. manim:: MovingAndZoomingCamera\n\n    class MovingAndZoomingCamera(MovingCameraScene):\n        def construct(self):\n            s = Square(color=BLUE, fill_opacity=0.5).move_to(2 * LEFT)\n            t = Triangle(color=YELLOW, fill_opacity=0.5).move_to(2 * RIGHT)\n            self.add(s, t)\n            self.play(self.camera.frame.animate.move_to(s).set(width=s.width*2))\n            self.wait(0.3)\n            self.play(self.camera.frame.animate.move_to(t).set(width=t.width*2))\n\n            self.play(self.camera.frame.animate.move_to(ORIGIN).set(width=14))\n\n.. manim:: MovingCameraOnGraph\n\n    class MovingCameraOnGraph(MovingCameraScene):\n        def construct(self):\n            self.camera.frame.save_state()\n\n            ax = Axes(x_range=[-1, 10], y_range=[-1, 10])\n            graph = ax.plot(lambda x: np.sin(x), color=WHITE, x_range=[0, 3 * PI])\n\n            dot_1 = Dot(ax.i2gp(graph.t_min, graph))\n            dot_2 = Dot(ax.i2gp(graph.t_max, graph))\n            self.add(ax, graph, dot_1, dot_2)\n\n            self.play(self.camera.frame.animate.scale(0.5).move_to(dot_1))\n            self.play(self.camera.frame.animate.move_to(dot_2))\n            self.play(Restore(self.camera.frame))\n            self.wait()\n\n.. manim:: SlidingMultipleScenes\n\n    class SlidingMultipleScenes(MovingCameraScene):\n        def construct(self):\n            def create_scene(number):\n                frame = Rectangle(width=16,height=9)\n                circ = Circle().shift(LEFT)\n                text = Tex(f\"This is Scene {str(number)}\").next_to(circ, RIGHT)\n                frame.add(circ,text)\n                return frame\n\n            group = VGroup(*(create_scene(i) for i in range(4))).arrange_in_grid(buff=4)\n            self.add(group)\n            self.camera.auto_zoom(group[0], animate=False)\n            for scene in group:\n                self.play(self.camera.auto_zoom(scene))\n                self.wait()\n\n            self.play(self.camera.auto_zoom(group, margin=2))\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"MovingCameraScene\"]\n\nfrom typing import Any\n\nfrom manim.animation.animation import Animation\nfrom manim.mobject.mobject import Mobject\n\nfrom ..camera.camera import Camera\nfrom ..camera.moving_camera import MovingCamera\nfrom ..scene.scene import Scene\nfrom ..utils.family import extract_mobject_family_members\nfrom ..utils.iterables import list_update\n\n\nclass MovingCameraScene(Scene):\n    \"\"\"\n    This is a Scene, with special configurations and properties that\n    make it suitable for cases where the camera must be moved around.\n\n    Note: Examples are included in the moving_camera_scene module\n    documentation, see below in the 'see also' section.\n\n    .. SEEALSO::\n\n        :mod:`.moving_camera_scene`\n        :class:`.MovingCamera`\n    \"\"\"\n\n    def __init__(\n        self, camera_class: type[Camera] = MovingCamera, **kwargs: Any\n    ) -> None:\n        super().__init__(camera_class=camera_class, **kwargs)\n\n    def get_moving_mobjects(self, *animations: Animation) -> list[Mobject]:\n        \"\"\"\n        This method returns a list of all of the Mobjects in the Scene that\n        are moving, that are also in the animations passed.\n\n        Parameters\n        ----------\n        *animations\n            The Animations whose mobjects will be checked.\n        \"\"\"\n        moving_mobjects = super().get_moving_mobjects(*animations)\n        all_moving_mobjects = extract_mobject_family_members(moving_mobjects)\n        movement_indicators = self.renderer.camera.get_mobjects_indicating_movement()  # type: ignore[union-attr]\n        for movement_indicator in movement_indicators:\n            if movement_indicator in all_moving_mobjects:\n                # When one of these is moving, the camera should\n                # consider all mobjects to be moving\n                return list_update(self.mobjects, moving_mobjects)\n        return moving_mobjects\n"
  },
  {
    "path": "manim/scene/scene.py",
    "content": "\"\"\"Basic canvas for animations.\"\"\"\n\nfrom __future__ import annotations\n\nfrom manim.utils.parameter_parsing import flatten_iterable_parameters\n\nfrom ..mobject.mobject import _AnimationBuilder\n\n__all__ = [\"Scene\"]\n\nimport copy\nimport datetime\nimport inspect\nimport platform\nimport random\nimport threading\nimport time\nfrom dataclasses import dataclass\nfrom pathlib import Path\nfrom queue import Queue\n\nimport srt\n\nfrom manim.scene.section import DefaultSectionType\n\ntry:\n    import dearpygui.dearpygui as dpg\n\n    dearpygui_imported = True\n    dpg.create_context()\n    window = dpg.generate_uuid()\nexcept ImportError:\n    dearpygui_imported = False\n\nfrom collections.abc import Callable, Iterable, Sequence\nfrom typing import TYPE_CHECKING, Any\n\nimport numpy as np\nfrom tqdm import tqdm\nfrom watchdog.events import DirModifiedEvent, FileModifiedEvent, FileSystemEventHandler\nfrom watchdog.observers import Observer\n\nfrom manim import __version__\nfrom manim.data_structures import MethodWithArgs\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.opengl.opengl_mobject import OpenGLPoint\n\nfrom .. import config, logger\nfrom ..animation.animation import Animation, Wait, prepare_animation\nfrom ..camera.camera import Camera\nfrom ..constants import *\nfrom ..renderer.cairo_renderer import CairoRenderer\nfrom ..renderer.opengl_renderer import OpenGLCamera, OpenGLMobject, OpenGLRenderer\nfrom ..renderer.shader import Object3D\nfrom ..utils import opengl, space_ops\nfrom ..utils.exceptions import EndSceneEarlyException, RerunSceneException\nfrom ..utils.family import extract_mobject_family_members\nfrom ..utils.family_ops import restructure_list_to_exclude_certain_family_members\nfrom ..utils.file_ops import open_media_file\nfrom ..utils.iterables import list_difference_update, list_update\nfrom ..utils.module_ops import scene_classes_from_file\n\nif TYPE_CHECKING:\n    from types import FrameType\n    from typing import Self, TypeAlias\n\n    from manim.typing import Point3D\n\n    SceneInteractAction: TypeAlias = (\n        MethodWithArgs | \"SceneInteractContinue\" | \"SceneInteractRerun\"\n    )\n    \"\"\"The SceneInteractAction type alias is used for elements in the queue\n    used by :meth:`.Scene.interact()`.\n\n    The elements can be one of the following three:\n\n    - a :class:`~.MethodWithArgs` object, which represents a :class:`Scene`\n      method to be called along with its args and kwargs,\n    - a :class:`~.SceneInteractContinue` object, indicating that the scene\n      interaction is over and the scene will continue rendering after that, or\n    - a :class:`~.SceneInteractRerun` object, indicating that the scene should\n      render again.\n    \"\"\"\n\n\n@dataclass\nclass SceneInteractContinue:\n    \"\"\"Object which, when encountered in :meth:`.Scene.interact`, triggers\n    the end of the scene interaction, continuing with the rest of the\n    animations, if any. This object can be queued in :attr:`.Scene.queue`\n    for later use in :meth:`.Scene.interact`.\n\n    Attributes\n    ----------\n    sender : str\n        The name of the entity which issued the end of the scene interaction,\n        such as ``\"gui\"`` or ``\"keyboard\"``.\n    \"\"\"\n\n    __slots__ = [\"sender\"]\n\n    sender: str\n\n\nclass SceneInteractRerun:\n    \"\"\"Object which, when encountered in :meth:`.Scene.interact`, triggers\n    the rerun of the scene. This object can be queued in :attr:`.Scene.queue`\n    for later use in :meth:`.Scene.interact`.\n\n    Attributes\n    ----------\n    sender : str\n        The name of the entity which issued the rerun of the scene, such as\n        ``\"gui\"``, ``\"keyboard\"``, ``\"play\"`` or ``\"file\"``.\n    kwargs : dict[str, Any]\n        Additional keyword arguments when rerunning the scene. Currently,\n        only ``\"from_animation_number\"`` is being used, which determines the\n        animation from which to start rerunning the scene.\n    \"\"\"\n\n    __slots__ = [\"sender\", \"kwargs\"]\n\n    def __init__(self, sender: str, **kwargs: Any) -> None:\n        self.sender = sender\n        self.kwargs = kwargs\n\n\nclass RerunSceneHandler(FileSystemEventHandler):\n    \"\"\"A class to handle rerunning a Scene after the input file is modified.\"\"\"\n\n    def __init__(self, queue: Queue[SceneInteractAction]) -> None:\n        super().__init__()\n        self.queue = queue\n\n    def on_modified(self, event: DirModifiedEvent | FileModifiedEvent) -> None:\n        self.queue.put(SceneInteractRerun(\"file\"))\n\n\nclass Scene:\n    \"\"\"A Scene is the canvas of your animation.\n\n    The primary role of :class:`Scene` is to provide the user with tools to manage\n    mobjects and animations.  Generally speaking, a manim script consists of a class\n    that derives from :class:`Scene` whose :meth:`Scene.construct` method is overridden\n    by the user's code.\n\n    Mobjects are displayed on screen by calling :meth:`Scene.add` and removed from\n    screen by calling :meth:`Scene.remove`.  All mobjects currently on screen are kept\n    in :attr:`Scene.mobjects`.  Animations are played by calling :meth:`Scene.play`.\n\n    A :class:`Scene` is rendered internally by calling :meth:`Scene.render`.  This in\n    turn calls :meth:`Scene.setup`, :meth:`Scene.construct`, and\n    :meth:`Scene.tear_down`, in that order.\n\n    It is not recommended to override the ``__init__`` method in user Scenes.  For code\n    that should be ran before a Scene is rendered, use :meth:`Scene.setup` instead.\n\n    Examples\n    --------\n    Override the :meth:`Scene.construct` method with your code.\n\n    .. code-block:: python\n\n        class MyScene(Scene):\n            def construct(self):\n                self.play(Write(Text(\"Hello World!\")))\n\n    \"\"\"\n\n    def __init__(\n        self,\n        renderer: CairoRenderer | OpenGLRenderer | None = None,\n        camera_class: type[Camera] = Camera,\n        always_update_mobjects: bool = False,\n        random_seed: int | None = None,\n        skip_animations: bool = False,\n    ) -> None:\n        self.camera_class = camera_class\n        self.always_update_mobjects = always_update_mobjects\n        self.random_seed = random_seed if random_seed is not None else config.seed\n        self.skip_animations = skip_animations\n\n        self.animations: list[Animation] | None = None\n        self.stop_condition: Callable[[], bool] | None = None\n        self.moving_mobjects: list[Mobject] = []\n        self.static_mobjects: list[Mobject] = []\n        self.time_progression: tqdm[float] | None = None\n        self.duration: float = 0.0\n        self.last_t = 0.0\n        self.queue: Queue[SceneInteractAction] = Queue()\n        self.skip_animation_preview = False\n        self.meshes: list[Object3D] = []\n        self.camera_target = ORIGIN\n        self.widgets: list[dict[str, Any]] = []\n        self.dearpygui_imported = dearpygui_imported\n        self.updaters: list[Callable[[float], None]] = []\n        self.key_to_function_map: dict[str, Callable[[], None]] = {}\n        self.mouse_press_callbacks: list[Callable[[], None]] = []\n        self.interactive_mode = False\n\n        if config.renderer == RendererType.OPENGL:\n            # Items associated with interaction\n            self.mouse_point = OpenGLPoint()\n            self.mouse_drag_point = OpenGLPoint()\n            if renderer is None:\n                renderer = OpenGLRenderer()\n\n        if renderer is None:\n            self.renderer: CairoRenderer | OpenGLRenderer = CairoRenderer(\n                # TODO: Is it a suitable approach to make an instance of\n                # the self.camera_class here?\n                camera_class=self.camera_class,\n                skip_animations=self.skip_animations,\n            )\n        else:\n            self.renderer = renderer\n        self.renderer.init_scene(self)\n\n        self.mobjects: list[Mobject] = []\n        # TODO, remove need for foreground mobjects\n        self.foreground_mobjects: list[Mobject] = []\n\n        random.seed(self.random_seed)\n        np.random.seed(self.random_seed)  # noqa: NPY002 (only way to set seed globally)\n\n    @property\n    def camera(self) -> Camera | OpenGLCamera:\n        return self.renderer.camera\n\n    @property\n    def time(self) -> float:\n        \"\"\"The time since the start of the scene.\"\"\"\n        return self.renderer.time\n\n    def __deepcopy__(self, clone_from_id: dict[int, Any]) -> Scene:\n        cls = self.__class__\n        result = cls.__new__(cls)\n        clone_from_id[id(self)] = result\n        for k, v in self.__dict__.items():\n            if k in [\"renderer\", \"time_progression\"]:\n                continue\n            if k == \"camera_class\":\n                setattr(result, k, v)\n            setattr(result, k, copy.deepcopy(v, clone_from_id))\n\n        return result\n\n    def render(self, preview: bool = False) -> bool:\n        \"\"\"\n        Renders this Scene.\n\n        Parameters\n        ---------\n        preview\n            If true, opens scene in a file viewer.\n        \"\"\"\n        self.setup()\n        try:\n            self.construct()\n        except EndSceneEarlyException:\n            pass\n        except RerunSceneException:\n            self.remove(*self.mobjects)\n            # TODO: The CairoRenderer does not have the method clear_screen()\n            self.renderer.clear_screen()  # type: ignore[union-attr]\n            self.renderer.num_plays = 0\n            return True\n        self.tear_down()\n        # We have to reset these settings in case of multiple renders.\n        self.renderer.scene_finished(self)\n\n        # Show info only if animations are rendered or to get image\n        if (\n            self.renderer.num_plays\n            or config[\"format\"] == \"png\"\n            or config[\"save_last_frame\"]\n        ):\n            logger.info(\n                f\"Rendered {str(self)}\\nPlayed {self.renderer.num_plays} animations\",\n            )\n\n        # If preview open up the render after rendering.\n        if preview:\n            config[\"preview\"] = True\n\n        if config[\"preview\"] or config[\"show_in_file_browser\"]:\n            open_media_file(self.renderer.file_writer)\n\n        return False\n\n    def setup(self) -> None:\n        \"\"\"\n        This is meant to be implemented by any scenes which\n        are commonly subclassed, and have some common setup\n        involved before the construct method is called.\n        \"\"\"\n        pass\n\n    def tear_down(self) -> None:\n        \"\"\"\n        This is meant to be implemented by any scenes which\n        are commonly subclassed, and have some common method\n        to be invoked before the scene ends.\n        \"\"\"\n        pass\n\n    def construct(self) -> None:\n        \"\"\"Add content to the Scene.\n\n        From within :meth:`Scene.construct`, display mobjects on screen by calling\n        :meth:`Scene.add` and remove them from screen by calling :meth:`Scene.remove`.\n        All mobjects currently on screen are kept in :attr:`Scene.mobjects`.  Play\n        animations by calling :meth:`Scene.play`.\n\n        Notes\n        -----\n        Initialization code should go in :meth:`Scene.setup`.  Termination code should\n        go in :meth:`Scene.tear_down`.\n\n        Examples\n        --------\n        A typical manim script includes a class derived from :class:`Scene` with an\n        overridden :meth:`Scene.construct` method:\n\n        .. code-block:: python\n\n            class MyScene(Scene):\n                def construct(self):\n                    self.play(Write(Text(\"Hello World!\")))\n\n        See Also\n        --------\n        :meth:`Scene.setup`\n        :meth:`Scene.render`\n        :meth:`Scene.tear_down`\n\n        \"\"\"\n        pass  # To be implemented in subclasses\n\n    def next_section(\n        self,\n        name: str = \"unnamed\",\n        section_type: str = DefaultSectionType.NORMAL,\n        skip_animations: bool = False,\n    ) -> None:\n        \"\"\"Create separation here; the last section gets finished and a new one gets created.\n        ``skip_animations`` skips the rendering of all animations in this section.\n        Refer to :doc:`the documentation</tutorials/output_and_config>` on how to use sections.\n        \"\"\"\n        self.renderer.file_writer.next_section(name, section_type, skip_animations)\n\n    def __str__(self) -> str:\n        return self.__class__.__name__\n\n    def get_attrs(self, *keys: str) -> list[Any]:\n        \"\"\"\n        Gets attributes of a scene given the attribute's identifier/name.\n\n        Parameters\n        ----------\n        *keys\n            Name(s) of the argument(s) to return the attribute of.\n\n        Returns\n        -------\n        list\n            List of attributes of the passed identifiers.\n        \"\"\"\n        return [getattr(self, key) for key in keys]\n\n    def update_mobjects(self, dt: float) -> None:\n        \"\"\"\n        Begins updating all mobjects in the Scene.\n\n        Parameters\n        ----------\n        dt\n            Change in time between updates. Defaults (mostly) to 1/frames_per_second\n        \"\"\"\n        for mobj in self.mobjects:\n            mobj.update(dt)\n\n    def update_meshes(self, dt: float) -> None:\n        for obj in self.meshes:\n            for mesh in obj.get_family():\n                mesh.update(dt)\n\n    def update_self(self, dt: float) -> None:\n        \"\"\"Run all scene updater functions.\n\n        Among all types of update functions (mobject updaters, mesh updaters,\n        scene updaters), scene update functions are called last.\n\n        Parameters\n        ----------\n        dt\n            Scene time since last update.\n\n        See Also\n        --------\n        :meth:`.Scene.add_updater`\n        :meth:`.Scene.remove_updater`\n        \"\"\"\n        for func in self.updaters:\n            func(dt)\n\n    def should_update_mobjects(self) -> bool:\n        \"\"\"\n        Returns True if the mobjects of this scene should be updated.\n\n        In particular, this checks whether\n\n        - the :attr:`always_update_mobjects` attribute of :class:`.Scene`\n          is set to ``True``,\n        - the :class:`.Scene` itself has time-based updaters attached,\n        - any mobject in this :class:`.Scene` has time-based updaters attached.\n\n        This is only called when a single Wait animation is played.\n        \"\"\"\n        assert self.animations is not None\n        wait_animation = self.animations[0]\n        assert isinstance(wait_animation, Wait)\n        if wait_animation.is_static_wait is None:\n            should_update = (\n                self.always_update_mobjects\n                or self.updaters\n                or wait_animation.stop_condition is not None\n                or any(\n                    mob.has_time_based_updater()\n                    for mob in self.get_mobject_family_members()\n                )\n            )\n            wait_animation.is_static_wait = not should_update\n        return not wait_animation.is_static_wait\n\n    def get_top_level_mobjects(self) -> list[Mobject]:\n        \"\"\"\n        Returns all mobjects which are not submobjects.\n\n        Returns\n        -------\n        list\n            List of top level mobjects.\n        \"\"\"\n        # Return only those which are not in the family\n        # of another mobject from the scene\n        families = [m.get_family() for m in self.mobjects]\n\n        def is_top_level(mobject: Mobject) -> bool:\n            num_families = sum((mobject in family) for family in families)\n            return num_families == 1\n\n        return list(filter(is_top_level, self.mobjects))\n\n    def get_mobject_family_members(self) -> list[Mobject]:\n        \"\"\"\n        Returns list of family-members of all mobjects in scene.\n        If a Circle() and a VGroup(Rectangle(),Triangle()) were added,\n        it returns not only the Circle(), Rectangle() and Triangle(), but\n        also the VGroup() object.\n\n        Returns\n        -------\n        list\n            List of mobject family members.\n        \"\"\"\n        if config.renderer == RendererType.OPENGL:\n            family_members = []\n            for mob in self.mobjects:\n                family_members.extend(mob.get_family())\n            return family_members\n        else:\n            assert config.renderer == RendererType.CAIRO\n            return extract_mobject_family_members(\n                self.mobjects,\n                use_z_index=self.renderer.camera.use_z_index,\n            )\n\n    def add(self, *mobjects: Mobject | OpenGLMobject) -> Self:\n        \"\"\"\n        Mobjects will be displayed, from background to\n        foreground in the order with which they are added.\n\n        Parameters\n        ---------\n        *mobjects\n            Mobjects to add.\n\n        Returns\n        -------\n        Scene\n            The same scene after adding the Mobjects in.\n\n        \"\"\"\n        if config.renderer == RendererType.OPENGL:\n            new_mobjects = []\n            new_meshes: list[Object3D] = []\n            for mobject_or_mesh in mobjects:\n                if isinstance(mobject_or_mesh, Object3D):\n                    new_meshes.append(mobject_or_mesh)\n                else:\n                    new_mobjects.append(mobject_or_mesh)\n            self.remove(*new_mobjects)  # type: ignore[arg-type]\n            self.mobjects += new_mobjects  # type: ignore[arg-type]\n            self.remove(*new_meshes)  # type: ignore[arg-type]\n            self.meshes += new_meshes\n        else:\n            assert config.renderer == RendererType.CAIRO\n            new_and_foreground_mobjects: list[Mobject] = [\n                *mobjects,  # type: ignore[list-item]\n                *self.foreground_mobjects,\n            ]\n            self.restructure_mobjects(to_remove=new_and_foreground_mobjects)\n            self.mobjects += new_and_foreground_mobjects\n            if self.moving_mobjects:\n                self.restructure_mobjects(\n                    to_remove=new_and_foreground_mobjects,\n                    mobject_list_name=\"moving_mobjects\",\n                )\n                self.moving_mobjects += new_and_foreground_mobjects\n        return self\n\n    def add_mobjects_from_animations(self, animations: list[Animation]) -> None:\n        curr_mobjects = self.get_mobject_family_members()\n        for animation in animations:\n            if animation.is_introducer():\n                continue\n            # Anything animated that's not already in the\n            # scene gets added to the scene\n            mob = animation.mobject\n            if mob is not None and mob not in curr_mobjects:\n                self.add(mob)\n                curr_mobjects += mob.get_family()  # type: ignore[arg-type]\n\n    def remove(self, *mobjects: Mobject) -> Self:\n        \"\"\"\n        Removes mobjects in the passed list of mobjects\n        from the scene and the foreground, by removing them\n        from \"mobjects\" and \"foreground_mobjects\"\n\n        Parameters\n        ----------\n        *mobjects\n            The mobjects to remove.\n        \"\"\"\n        if config.renderer == RendererType.OPENGL:\n            mobjects_to_remove = []\n            meshes_to_remove: set[Object3D] = set()\n            mobject_or_mesh: Mobject\n            for mobject_or_mesh in mobjects:\n                if isinstance(mobject_or_mesh, Object3D):\n                    meshes_to_remove.add(mobject_or_mesh)\n                else:\n                    mobjects_to_remove.append(mobject_or_mesh)\n            self.mobjects = restructure_list_to_exclude_certain_family_members(\n                self.mobjects,\n                mobjects_to_remove,\n            )\n\n            def lambda_function(mesh: Object3D) -> bool:\n                return mesh not in set(meshes_to_remove)\n\n            self.meshes = list(\n                filter(lambda_function, self.meshes),\n            )\n            return self\n        else:\n            assert config.renderer == RendererType.CAIRO\n            for list_name in \"mobjects\", \"foreground_mobjects\":\n                self.restructure_mobjects(mobjects, list_name, False)\n            return self\n\n    def replace(self, old_mobject: Mobject, new_mobject: Mobject) -> None:\n        \"\"\"Replace one mobject in the scene with another, preserving draw order.\n\n        If ``old_mobject`` is a submobject of some other Mobject (e.g. a\n        :class:`.Group`), the new_mobject will replace it inside the group,\n        without otherwise changing the parent mobject.\n\n        Parameters\n        ----------\n        old_mobject\n            The mobject to be replaced. Must be present in the scene.\n        new_mobject\n            A mobject which must not already be in the scene.\n\n        \"\"\"\n        if old_mobject is None or new_mobject is None:\n            raise ValueError(\"Specified mobjects cannot be None\")\n\n        def replace_in_list(\n            mobj_list: list[Mobject], old_m: Mobject, new_m: Mobject\n        ) -> bool:\n            # Avoid duplicate references to the same object in self.mobjects\n            if new_m in mobj_list:\n                if old_m is new_m:\n                    # In this case, one could say that the old Mobject was already found.\n                    # No replacement is needed, since old_m is new_m, so no action is required.\n                    # This might be unexpected, so raise a warning.\n                    logger.warning(\n                        f\"Attempted to replace {type(old_m).__name__} \"\n                        \"with itself in Scene.mobjects.\"\n                    )\n                    return True\n                mobj_list.remove(new_m)\n\n            # We use breadth-first search because some Mobjects get very deep and\n            # we expect top-level elements to be the most common targets for replace.\n            for i in range(0, len(mobj_list)):\n                # Is this the old mobject?\n                if mobj_list[i] == old_m:\n                    # If so, write the new object to the same spot and stop looking.\n                    mobj_list[i] = new_m\n                    return True\n            # Now check all the children of all these mobs.\n            for mob in mobj_list:  # noqa: SIM110\n                if replace_in_list(mob.submobjects, old_m, new_m):\n                    # If we found it in a submobject, stop looking.\n                    return True\n            # If we did not find the mobject in the mobject list or any submobjects,\n            # (or the list was empty), indicate we did not make the replacement.\n            return False\n\n        # Make use of short-circuiting conditionals to check mobjects and then\n        # foreground_mobjects\n        replaced = replace_in_list(\n            self.mobjects, old_mobject, new_mobject\n        ) or replace_in_list(self.foreground_mobjects, old_mobject, new_mobject)\n\n        if not replaced:\n            raise ValueError(f\"Could not find {old_mobject} in scene\")\n\n    def add_updater(self, func: Callable[[float], None]) -> None:\n        \"\"\"Add an update function to the scene.\n\n        The scene updater functions are run every frame,\n        and they are the last type of updaters to run.\n\n        .. WARNING::\n\n            When using the Cairo renderer, scene updaters that\n            modify mobjects are not detected in the same way\n            that mobject updaters are. To be more concrete,\n            a mobject only modified via a scene updater will\n            not necessarily be added to the list of *moving\n            mobjects* and thus might not be updated every frame.\n\n            TL;DR: Use mobject updaters to update mobjects.\n\n        Parameters\n        ----------\n        func\n            The updater function. It takes a float, which is the\n            time difference since the last update (usually equal\n            to the frame rate).\n\n        See also\n        --------\n        :meth:`.Scene.remove_updater`\n        :meth:`.Scene.update_self`\n        \"\"\"\n        self.updaters.append(func)\n\n    def remove_updater(self, func: Callable[[float], None]) -> None:\n        \"\"\"Remove an update function from the scene.\n\n        Parameters\n        ----------\n        func\n            The updater function to be removed.\n\n        See also\n        --------\n        :meth:`.Scene.add_updater`\n        :meth:`.Scene.update_self`\n        \"\"\"\n        self.updaters = [f for f in self.updaters if f is not func]\n\n    def restructure_mobjects(\n        self,\n        to_remove: Sequence[Mobject],\n        mobject_list_name: str = \"mobjects\",\n        extract_families: bool = True,\n    ) -> Scene:\n        \"\"\"\n        tl:wr\n            If your scene has a Group(), and you removed a mobject from the Group,\n            this dissolves the group and puts the rest of the mobjects directly\n            in self.mobjects or self.foreground_mobjects.\n\n        In cases where the scene contains a group, e.g. Group(m1, m2, m3), but one\n        of its submobjects is removed, e.g. scene.remove(m1), the list of mobjects\n        will be edited to contain other submobjects, but not m1, e.g. it will now\n        insert m2 and m3 to where the group once was.\n\n        Parameters\n        ----------\n        to_remove\n            The Mobject to remove.\n\n        mobject_list_name\n            The list of mobjects (\"mobjects\", \"foreground_mobjects\" etc) to remove from.\n\n        extract_families\n            Whether the mobject's families should be recursively extracted.\n\n        Returns\n        -------\n        Scene\n            The Scene mobject with restructured Mobjects.\n        \"\"\"\n        if extract_families:\n            to_remove = extract_mobject_family_members(\n                to_remove,\n                use_z_index=self.renderer.camera.use_z_index,\n            )\n        _list = getattr(self, mobject_list_name)\n        new_list = self.get_restructured_mobject_list(_list, to_remove)\n        setattr(self, mobject_list_name, new_list)\n        return self\n\n    def get_restructured_mobject_list(\n        self, mobjects: Iterable[Mobject], to_remove: Iterable[Mobject]\n    ) -> list[Mobject]:\n        \"\"\"\n        Given a list of mobjects and a list of mobjects to be removed, this\n        filters out the removable mobjects from the list of mobjects.\n\n        Parameters\n        ----------\n\n        mobjects\n            The Mobjects to check.\n\n        to_remove\n            The list of mobjects to remove.\n\n        Returns\n        -------\n        list\n            The list of mobjects with the mobjects to remove removed.\n        \"\"\"\n        new_mobjects: list[Mobject] = []\n\n        def add_safe_mobjects_from_list(\n            list_to_examine: Iterable[Mobject], set_to_remove: set[Mobject]\n        ) -> None:\n            for mob in list_to_examine:\n                if mob in set_to_remove:\n                    continue\n                intersect = set_to_remove.intersection(mob.get_family())\n                if intersect:\n                    add_safe_mobjects_from_list(mob.submobjects, intersect)\n                else:\n                    new_mobjects.append(mob)\n\n        add_safe_mobjects_from_list(mobjects, set(to_remove))\n        return new_mobjects\n\n    # TODO, remove this, and calls to this\n    def add_foreground_mobjects(self, *mobjects: Mobject) -> Scene:\n        \"\"\"\n        Adds mobjects to the foreground, and internally to the list\n        foreground_mobjects, and mobjects.\n\n        Parameters\n        ----------\n        *mobjects\n            The Mobjects to add to the foreground.\n\n        Returns\n        ------\n        Scene\n            The Scene, with the foreground mobjects added.\n        \"\"\"\n        self.foreground_mobjects = list_update(self.foreground_mobjects, mobjects)\n        self.add(*mobjects)\n        return self\n\n    def add_foreground_mobject(self, mobject: Mobject) -> Scene:\n        \"\"\"\n        Adds a single mobject to the foreground, and internally to the list\n        foreground_mobjects, and mobjects.\n\n        Parameters\n        ----------\n        mobject\n            The Mobject to add to the foreground.\n\n        Returns\n        ------\n        Scene\n            The Scene, with the foreground mobject added.\n        \"\"\"\n        return self.add_foreground_mobjects(mobject)\n\n    def remove_foreground_mobjects(self, *to_remove: Mobject) -> Scene:\n        \"\"\"\n        Removes mobjects from the foreground, and internally from the list\n        foreground_mobjects.\n\n        Parameters\n        ----------\n        *to_remove\n            The mobject(s) to remove from the foreground.\n\n        Returns\n        ------\n        Scene\n            The Scene, with the foreground mobjects removed.\n        \"\"\"\n        self.restructure_mobjects(to_remove, \"foreground_mobjects\")\n        return self\n\n    def remove_foreground_mobject(self, mobject: Mobject) -> Scene:\n        \"\"\"\n        Removes a single mobject from the foreground, and internally from the list\n        foreground_mobjects.\n\n        Parameters\n        ----------\n        mobject\n            The mobject to remove from the foreground.\n\n        Returns\n        ------\n        Scene\n            The Scene, with the foreground mobject removed.\n        \"\"\"\n        return self.remove_foreground_mobjects(mobject)\n\n    def bring_to_front(self, *mobjects: Mobject) -> Scene:\n        \"\"\"\n        Adds the passed mobjects to the scene again,\n        pushing them to he front of the scene.\n\n        Parameters\n        ----------\n        *mobjects\n            The mobject(s) to bring to the front of the scene.\n\n        Returns\n        ------\n        Scene\n            The Scene, with the mobjects brought to the front\n            of the scene.\n        \"\"\"\n        self.add(*mobjects)\n        return self\n\n    def bring_to_back(self, *mobjects: Mobject) -> Scene:\n        \"\"\"\n        Removes the mobject from the scene and\n        adds them to the back of the scene.\n\n        Parameters\n        ----------\n        *mobjects\n            The mobject(s) to push to the back of the scene.\n\n        Returns\n        ------\n        Scene\n            The Scene, with the mobjects pushed to the back\n            of the scene.\n        \"\"\"\n        self.remove(*mobjects)\n        self.mobjects = list(mobjects) + self.mobjects\n        return self\n\n    def clear(self) -> Self:\n        \"\"\"\n        Removes all mobjects present in self.mobjects\n        and self.foreground_mobjects from the scene.\n\n        Returns\n        ------\n        Scene\n            The Scene, with all of its mobjects in\n            self.mobjects and self.foreground_mobjects\n            removed.\n        \"\"\"\n        self.mobjects = []\n        self.foreground_mobjects = []\n        return self\n\n    def get_moving_mobjects(self, *animations: Animation) -> list[Mobject]:\n        \"\"\"\n        Gets all moving mobjects in the passed animation(s).\n\n        Parameters\n        ----------\n        *animations\n            The animations to check for moving mobjects.\n\n        Returns\n        ------\n        list\n            The list of mobjects that could be moving in\n            the Animation(s)\n        \"\"\"\n        # Go through mobjects from start to end, and\n        # as soon as there's one that needs updating of\n        # some kind per frame, return the list from that\n        # point forward.\n        # Imported inside the method to avoid cyclic import.\n        from ..animation.composition import AnimationGroup\n\n        def _collect_animation_mobjects(\n            nested_animations: Iterable[Animation],\n        ) -> list[Mobject | OpenGLMobject]:\n            animation_mobjects: list[Mobject | OpenGLMobject] = []\n            for anim in nested_animations:\n                if isinstance(anim, AnimationGroup):\n                    animation_mobjects.extend(\n                        _collect_animation_mobjects(anim.animations),\n                    )\n                else:\n                    animation_mobjects.extend(anim.mobject.get_family())\n            return animation_mobjects\n\n        animation_mobjects = _collect_animation_mobjects(animations)\n\n        mobjects = self.get_mobject_family_members()\n        for i, mob in enumerate(mobjects):\n            update_possibilities = [\n                mob in animation_mobjects,\n                len(mob.get_family_updaters()) > 0,\n                mob in self.foreground_mobjects,\n            ]\n            if any(update_possibilities):\n                return mobjects[i:]\n        return []\n\n    def get_moving_and_static_mobjects(\n        self, animations: Iterable[Animation]\n    ) -> tuple[list[Mobject], list[Mobject]]:\n        all_mobjects = list_update(self.mobjects, self.foreground_mobjects)\n        all_mobject_families = extract_mobject_family_members(\n            all_mobjects,\n            use_z_index=self.renderer.camera.use_z_index,\n            only_those_with_points=True,\n        )\n        moving_mobjects = self.get_moving_mobjects(*animations)\n        all_moving_mobject_families = extract_mobject_family_members(\n            moving_mobjects,\n            use_z_index=self.renderer.camera.use_z_index,\n        )\n        static_mobjects = list_difference_update(\n            all_mobject_families,\n            all_moving_mobject_families,\n        )\n        return all_moving_mobject_families, static_mobjects\n\n    def compile_animations(\n        self,\n        *args: Animation | Mobject | _AnimationBuilder,\n        **kwargs: Any,\n    ) -> list[Animation]:\n        \"\"\"\n        Creates _MethodAnimations from any _AnimationBuilders and updates animation\n        kwargs with kwargs passed to play().\n\n        Parameters\n        ----------\n        *args\n            Animations to be played.\n        **kwargs\n            Configuration for the call to play().\n\n        Returns\n        -------\n        Tuple[:class:`Animation`]\n            Animations to be played.\n        \"\"\"\n        animations = []\n        arg_anims = flatten_iterable_parameters(args)\n        # Allow passing a generator to self.play instead of comma separated arguments\n        for arg in arg_anims:\n            try:\n                animations.append(prepare_animation(arg))  # type: ignore[arg-type]\n            except TypeError as e:\n                if inspect.ismethod(arg):\n                    raise TypeError(\n                        \"Passing Mobject methods to Scene.play is no longer\"\n                        \" supported. Use Mobject.animate instead.\",\n                    ) from e\n                else:\n                    raise TypeError(\n                        f\"Unexpected argument {arg} passed to Scene.play().\",\n                    ) from e\n\n        for animation in animations:\n            for k, v in kwargs.items():\n                setattr(animation, k, v)\n\n        return animations\n\n    def _get_animation_time_progression(\n        self, animations: list[Animation], duration: float\n    ) -> tqdm[float]:\n        \"\"\"\n        You will hardly use this when making your own animations.\n        This method is for Manim's internal use.\n\n        Uses :func:`~.get_time_progression` to obtain a\n        CommandLine ProgressBar whose ``fill_time`` is\n        dependent on the qualities of the passed Animation,\n\n        Parameters\n        ----------\n        animations\n            The list of animations to get\n            the time progression for.\n\n        duration\n            duration of wait time\n\n        Returns\n        -------\n        time_progression\n            The CommandLine Progress Bar.\n        \"\"\"\n        if len(animations) == 1 and isinstance(animations[0], Wait):\n            stop_condition = animations[0].stop_condition\n            if stop_condition is not None:\n                time_progression = self.get_time_progression(\n                    duration,\n                    f\"Waiting for {stop_condition.__name__}\",\n                    n_iterations=-1,  # So it doesn't show % progress\n                    override_skip_animations=True,\n                )\n            else:\n                time_progression = self.get_time_progression(\n                    duration,\n                    f\"Waiting {self.renderer.num_plays}\",\n                )\n        else:\n            time_progression = self.get_time_progression(\n                duration,\n                \"\".join(\n                    [\n                        f\"Animation {self.renderer.num_plays}: \",\n                        str(animations[0]),\n                        (\", etc.\" if len(animations) > 1 else \"\"),\n                    ],\n                ),\n            )\n        return time_progression\n\n    def get_time_progression(\n        self,\n        run_time: float,\n        description: str,\n        n_iterations: int | None = None,\n        override_skip_animations: bool = False,\n    ) -> tqdm[float]:\n        \"\"\"\n        You will hardly use this when making your own animations.\n        This method is for Manim's internal use.\n\n        Returns a CommandLine ProgressBar whose ``fill_time``\n        is dependent on the ``run_time`` of an animation,\n        the iterations to perform in that animation\n        and a bool saying whether or not to consider\n        the skipped animations.\n\n        Parameters\n        ----------\n        run_time\n            The ``run_time`` of the animation.\n\n        n_iterations\n            The number of iterations in the animation.\n\n        override_skip_animations\n            Whether or not to show skipped animations in the progress bar.\n\n        Returns\n        -------\n        time_progression\n            The CommandLine Progress Bar.\n        \"\"\"\n        if self.renderer.skip_animations and not override_skip_animations:\n            times: Iterable[float] = [run_time]\n        else:\n            step = 1 / config[\"frame_rate\"]\n            times = np.arange(0, run_time, step)\n        time_progression = tqdm(\n            times,\n            desc=description,\n            total=n_iterations,\n            leave=config[\"progress_bar\"] == \"leave\",\n            ascii=True if platform.system() == \"Windows\" else None,\n            disable=config[\"progress_bar\"] == \"none\",\n        )\n        return time_progression\n\n    @classmethod\n    def validate_run_time(\n        cls,\n        run_time: float,\n        method: Callable[[Any], Any],\n        parameter_name: str = \"run_time\",\n    ) -> float:\n        method_name = f\"{cls.__name__}.{method.__name__}()\"\n        if run_time <= 0:\n            raise ValueError(\n                f\"{method_name} has a {parameter_name} of \"\n                f\"{run_time:g} <= 0 seconds which Manim cannot render. \"\n                f\"The {parameter_name} must be a positive number.\"\n            )\n\n        # config.frame_rate holds the number of frames per second\n        fps = config.frame_rate\n        seconds_per_frame = 1 / fps\n        if run_time < seconds_per_frame:\n            logger.warning(\n                f\"The original {parameter_name} of {method_name}, \"\n                f\"{run_time:g} seconds, is too short for the current frame \"\n                f\"rate of {fps:g} FPS. Rendering with the shortest possible \"\n                f\"{parameter_name} of {seconds_per_frame:g} seconds instead.\"\n            )\n            run_time = seconds_per_frame\n\n        return run_time\n\n    def get_run_time(self, animations: list[Animation]) -> float:\n        \"\"\"\n        Gets the total run time for a list of animations.\n\n        Parameters\n        ----------\n        animations\n            A list of the animations whose total\n            ``run_time`` is to be calculated.\n\n        Returns\n        -------\n        float\n            The total ``run_time`` of all of the animations in the list.\n        \"\"\"\n        run_time = max(animation.run_time for animation in animations)\n        run_time = self.validate_run_time(run_time, self.play, \"total run_time\")\n        return run_time\n\n    def play(\n        self,\n        *args: Animation | Mobject | _AnimationBuilder,\n        subcaption: str | None = None,\n        subcaption_duration: float | None = None,\n        subcaption_offset: float = 0,\n        **kwargs: Any,\n    ) -> None:\n        r\"\"\"Plays an animation in this scene.\n\n        Parameters\n        ----------\n\n        args\n            Animations to be played.\n        subcaption\n            The content of the external subcaption that should\n            be added during the animation.\n        subcaption_duration\n            The duration for which the specified subcaption is\n            added. If ``None`` (the default), the run time of the\n            animation is taken.\n        subcaption_offset\n            An offset (in seconds) for the start time of the\n            added subcaption.\n        kwargs\n            All other keywords are passed to the renderer.\n\n        \"\"\"\n        # If we are in interactive embedded mode, make sure this is running on the main thread (required for OpenGL)\n        if (\n            self.interactive_mode\n            and config.renderer == RendererType.OPENGL\n            and threading.current_thread().name != \"MainThread\"\n        ):\n            # TODO: are these actually being used?\n            kwargs.update(\n                {\n                    \"subcaption\": subcaption,\n                    \"subcaption_duration\": subcaption_duration,\n                    \"subcaption_offset\": subcaption_offset,\n                }\n            )\n            self.queue.put(SceneInteractRerun(\"play\", **kwargs))\n            return\n\n        start_time = self.time\n        self.renderer.play(self, *args, **kwargs)\n        run_time = self.time - start_time\n        if subcaption:\n            if subcaption_duration is None:\n                subcaption_duration = run_time\n            # The start of the subcaption needs to be offset by the\n            # run_time of the animation because it is added after\n            # the animation has already been played (and Scene.time\n            # has already been updated).\n            self.add_subcaption(\n                content=subcaption,\n                duration=subcaption_duration,\n                offset=-run_time + subcaption_offset,\n            )\n\n    def wait(\n        self,\n        duration: float = DEFAULT_WAIT_TIME,\n        stop_condition: Callable[[], bool] | None = None,\n        frozen_frame: bool | None = None,\n    ) -> None:\n        \"\"\"Plays a \"no operation\" animation.\n\n        Parameters\n        ----------\n        duration\n            The run time of the animation.\n        stop_condition\n            A function without positional arguments that is evaluated every time\n            a frame is rendered. The animation only stops when the return value\n            of the function is truthy, or when the time specified in ``duration``\n            passes.\n        frozen_frame\n            If True, updater functions are not evaluated, and the animation outputs\n            a frozen frame. If False, updater functions are called and frames\n            are rendered as usual. If None (the default), the scene tries to\n            determine whether or not the frame is frozen on its own.\n\n        See also\n        --------\n        :class:`.Wait`, :meth:`.should_mobjects_update`\n        \"\"\"\n        duration = self.validate_run_time(duration, self.wait, \"duration\")\n        self.play(\n            Wait(\n                run_time=duration,\n                stop_condition=stop_condition,\n                frozen_frame=frozen_frame,\n            )\n        )\n\n    def pause(self, duration: float = DEFAULT_WAIT_TIME) -> None:\n        \"\"\"Pauses the scene (i.e., displays a frozen frame).\n\n        This is an alias for :meth:`.wait` with ``frozen_frame``\n        set to ``True``.\n\n        Parameters\n        ----------\n        duration\n            The duration of the pause.\n\n        See also\n        --------\n        :meth:`.wait`, :class:`.Wait`\n        \"\"\"\n        duration = self.validate_run_time(duration, self.pause, \"duration\")\n        self.wait(duration=duration, frozen_frame=True)\n\n    def wait_until(\n        self, stop_condition: Callable[[], bool], max_time: float = 60\n    ) -> None:\n        \"\"\"Wait until a condition is satisfied, up to a given maximum duration.\n\n        Parameters\n        ----------\n        stop_condition\n            A function with no arguments that determines whether or not the\n            scene should keep waiting.\n        max_time\n            The maximum wait time in seconds.\n        \"\"\"\n        max_time = self.validate_run_time(max_time, self.wait_until, \"max_time\")\n        self.wait(max_time, stop_condition=stop_condition)\n\n    def compile_animation_data(\n        self,\n        *animations: Animation | Mobject | _AnimationBuilder,\n        **play_kwargs: Any,\n    ) -> Self | None:\n        \"\"\"Given a list of animations, compile the corresponding\n        static and moving mobjects, and gather the animation durations.\n\n        This also begins the animations.\n\n        Parameters\n        ----------\n        animations\n            Animation or mobject with mobject method and params\n        play_kwargs\n            Named parameters affecting what was passed in ``animations``,\n            e.g. ``run_time``, ``lag_ratio`` and so on.\n\n        Returns\n        -------\n        self, None\n            None if there is nothing to play, or self otherwise.\n        \"\"\"\n        # NOTE TODO : returns statement of this method are wrong. It should return nothing, as it makes a little sense to get any information from this method.\n        # The return are kept to keep webgl renderer from breaking.\n        if len(animations) == 0:\n            raise ValueError(\"Called Scene.play with no animations\")\n\n        self.animations = self.compile_animations(*animations, **play_kwargs)\n        self.add_mobjects_from_animations(self.animations)\n\n        self.last_t = 0\n        self.stop_condition = None\n        self.moving_mobjects = []\n        self.static_mobjects = []\n\n        self.duration = self.get_run_time(self.animations)\n        if len(self.animations) == 1 and isinstance(self.animations[0], Wait):\n            if self.should_update_mobjects():\n                self.update_mobjects(dt=0)  # Any problems with this?\n                self.stop_condition = self.animations[0].stop_condition\n            else:\n                # Static image logic when the wait is static is done by the renderer, not here.\n                self.animations[0].is_static_wait = True\n                return None\n\n        return self\n\n    def begin_animations(self) -> None:\n        \"\"\"Start the animations of the scene.\"\"\"\n        assert self.animations is not None\n        for animation in self.animations:\n            animation._setup_scene(self)\n            animation.begin()\n\n        if config.renderer == RendererType.CAIRO:\n            # Paint all non-moving objects onto the screen, so they don't\n            # have to be rendered every frame\n            (\n                self.moving_mobjects,\n                self.static_mobjects,\n            ) = self.get_moving_and_static_mobjects(self.animations)\n\n    def is_current_animation_frozen_frame(self) -> bool:\n        \"\"\"Returns whether the current animation produces a static frame (generally a Wait).\"\"\"\n        assert self.animations is not None\n        return (\n            isinstance(self.animations[0], Wait)\n            and len(self.animations) == 1\n            and self.animations[0].is_static_wait\n        )\n\n    def play_internal(self, skip_rendering: bool = False) -> None:\n        \"\"\"\n        This method is used to prep the animations for rendering,\n        apply the arguments and parameters required to them,\n        render them, and write them to the video file.\n\n        Parameters\n        ----------\n        skip_rendering\n            Whether the rendering should be skipped, by default False\n        \"\"\"\n        assert self.animations is not None\n        self.duration = self.get_run_time(self.animations)\n        self.time_progression = self._get_animation_time_progression(\n            self.animations,\n            self.duration,\n        )\n        for t in self.time_progression:\n            self.update_to_time(t)\n            if not skip_rendering and not self.skip_animation_preview:\n                self.renderer.render(self, t, self.moving_mobjects)\n            if self.stop_condition is not None and self.stop_condition():\n                self.time_progression.close()\n                break\n\n        for animation in self.animations:\n            animation.finish()\n            animation.clean_up_from_scene(self)\n        if not self.renderer.skip_animations:\n            self.update_mobjects(0)\n        # TODO: The OpenGLRenderer does not have the property static.image.\n        self.renderer.static_image = None  # type: ignore[union-attr]\n        # Closing the progress bar at the end of the play.\n        self.time_progression.close()\n\n    def check_interactive_embed_is_valid(self) -> bool:\n        assert isinstance(self.renderer, OpenGLRenderer)\n        if config[\"force_window\"]:\n            return True\n        if self.skip_animation_preview:\n            logger.warning(\n                \"Disabling interactive embed as 'skip_animation_preview' is enabled\",\n            )\n            return False\n        elif config[\"write_to_movie\"]:\n            logger.warning(\"Disabling interactive embed as 'write_to_movie' is enabled\")\n            return False\n        elif config[\"format\"]:\n            logger.warning(\n                \"Disabling interactive embed as '--format' is set as \"\n                + config[\"format\"],\n            )\n            return False\n        elif not self.renderer.window:\n            logger.warning(\"Disabling interactive embed as no window was created\")\n            return False\n        elif config.dry_run:\n            logger.warning(\"Disabling interactive embed as dry_run is enabled\")\n            return False\n        return True\n\n    def interactive_embed(self) -> None:\n        \"\"\"Like embed(), but allows for screen interaction.\"\"\"\n        assert isinstance(self.camera, OpenGLCamera)\n        assert isinstance(self.renderer, OpenGLRenderer)\n        if not self.check_interactive_embed_is_valid():\n            return\n        self.interactive_mode = True\n        from IPython.terminal.embed import InteractiveShellEmbed\n\n        def ipython(shell: InteractiveShellEmbed, namespace: dict[str, Any]) -> None:\n            import manim.opengl\n\n            def load_module_into_namespace(\n                module: Any, namespace: dict[str, Any]\n            ) -> None:\n                for name in dir(module):\n                    namespace[name] = getattr(module, name)\n\n            load_module_into_namespace(manim, namespace)\n            load_module_into_namespace(manim.opengl, namespace)\n\n            def embedded_rerun(*args: Any, **kwargs: Any) -> None:\n                self.queue.put(SceneInteractRerun(\"keyboard\"))\n                shell.exiter()\n\n            namespace[\"rerun\"] = embedded_rerun\n\n            shell(local_ns=namespace)\n            self.queue.put(SceneInteractContinue(\"keyboard\"))\n\n        def get_embedded_method(method_name: str) -> Callable[..., None]:\n            method = getattr(self, method_name)\n\n            def embedded_method(*args: Any, **kwargs: Any) -> None:\n                self.queue.put(MethodWithArgs(method, args, kwargs))\n\n            return embedded_method\n\n        currentframe: FrameType = inspect.currentframe()  # type: ignore[assignment]\n        local_namespace = currentframe.f_back.f_locals  # type: ignore[union-attr]\n        for method in (\"play\", \"wait\", \"add\", \"remove\"):\n            embedded_method = get_embedded_method(method)\n            # Allow for calling scene methods without prepending 'self.'.\n            local_namespace[method] = embedded_method\n\n        from sqlite3 import connect\n\n        from IPython.core.getipython import get_ipython\n        from traitlets.config import Config\n\n        cfg = Config()\n        cfg.TerminalInteractiveShell.confirm_exit = False\n        if get_ipython() is None:\n            shell = InteractiveShellEmbed.instance(config=cfg)\n        else:\n            shell = InteractiveShellEmbed(config=cfg)\n        hist = get_ipython().history_manager\n        hist.db = connect(hist.hist_file, check_same_thread=False)\n\n        keyboard_thread = threading.Thread(\n            target=ipython,\n            args=(shell, local_namespace),\n        )\n        # run as daemon to kill thread when main thread exits\n        if not shell.pt_app:\n            keyboard_thread.daemon = True\n        keyboard_thread.start()\n\n        if self.dearpygui_imported and config[\"enable_gui\"]:\n            if not dpg.is_dearpygui_running():\n                gui_thread = threading.Thread(\n                    target=self._configure_pygui,\n                    kwargs={\"update\": False},\n                )\n                gui_thread.start()\n            else:\n                self._configure_pygui(update=True)\n\n        self.camera.model_matrix = self.camera.default_model_matrix\n\n        self.interact(shell, keyboard_thread)\n\n    # from IPython.terminal.embed import InteractiveShellEmbed\n\n    def interact(self, shell: Any, keyboard_thread: threading.Thread) -> None:\n        assert isinstance(self.renderer, OpenGLRenderer)\n        event_handler = RerunSceneHandler(self.queue)\n        file_observer = Observer()\n        file_observer.schedule(event_handler, config[\"input_file\"], recursive=True)\n        file_observer.start()\n\n        self.quit_interaction = False\n        keyboard_thread_needs_join = shell.pt_app is not None\n        assert self.queue.qsize() == 0\n\n        last_time = time.time()\n        while not (\n            (self.renderer.window is not None and self.renderer.window.is_closing)\n            or self.quit_interaction\n        ):\n            if not self.queue.empty():\n                action = self.queue.get_nowait()\n                if isinstance(action, SceneInteractRerun):\n                    # Intentionally skip calling join() on the file thread to save time.\n                    if action.sender != \"keyboard\":\n                        if shell.pt_app:\n                            shell.pt_app.app.exit(exception=EOFError)\n                        file_observer.unschedule_all()\n                        raise RerunSceneException\n                    keyboard_thread.join()\n\n                    if \"from_animation_number\" in action.kwargs:\n                        config[\"from_animation_number\"] = action.kwargs[\n                            \"from_animation_number\"\n                        ]\n                    # # TODO: This option only makes sense if interactive_embed() is run at the\n                    # # end of a scene by default.\n                    # if \"upto_animation_number\" in action.kwargs:\n                    #     config[\"upto_animation_number\"] = action.kwargs[\n                    #         \"upto_animation_number\"\n                    #     ]\n\n                    keyboard_thread.join()\n                    file_observer.unschedule_all()\n                    raise RerunSceneException\n                elif isinstance(action, SceneInteractContinue):\n                    # Intentionally skip calling join() on the file thread to save time.\n                    if action.sender != \"keyboard\" and shell.pt_app:\n                        shell.pt_app.app.exit(exception=EOFError)\n                    keyboard_thread.join()\n                    # Remove exit_keyboard from the queue if necessary.\n                    while self.queue.qsize() > 0:\n                        self.queue.get()\n                    keyboard_thread_needs_join = False\n                    break\n                else:\n                    action.method(*action.args, **action.kwargs)\n            else:\n                self.renderer.animation_start_time = 0\n                dt = time.time() - last_time\n                last_time = time.time()\n                self.renderer.render(self, dt, self.moving_mobjects)\n                self.update_mobjects(dt)\n                self.update_meshes(dt)\n                self.update_self(dt)\n\n        # Join the keyboard thread if necessary.\n        if shell is not None and keyboard_thread_needs_join:\n            shell.pt_app.app.exit(exception=EOFError)\n            keyboard_thread.join()\n            # Remove exit_keyboard from the queue if necessary.\n            while self.queue.qsize() > 0:\n                self.queue.get()\n\n        file_observer.stop()\n        file_observer.join()\n\n        if self.dearpygui_imported and config[\"enable_gui\"]:\n            dpg.stop_dearpygui()\n\n        if self.renderer.window is not None and self.renderer.window.is_closing:\n            self.renderer.window.destroy()\n\n    def embed(self) -> None:\n        assert isinstance(self.renderer, OpenGLRenderer)\n        if not config[\"preview\"]:\n            logger.warning(\"Called embed() while no preview window is available.\")\n            return\n        if config[\"write_to_movie\"]:\n            logger.warning(\"embed() is skipped while writing to a file.\")\n            return\n\n        self.renderer.animation_start_time = 0\n        self.renderer.render(self, -1, self.moving_mobjects)\n\n        # Configure IPython shell.\n        from IPython.terminal.embed import InteractiveShellEmbed\n\n        shell = InteractiveShellEmbed()\n\n        # Have the frame update after each command\n        shell.events.register(\n            \"post_run_cell\",\n            lambda *a, **kw: self.renderer.render(self, -1, self.moving_mobjects),\n        )\n\n        # Use the locals of the caller as the local namespace\n        # once embedded, and add a few custom shortcuts.\n        current_frame = inspect.currentframe()\n        assert isinstance(current_frame, FrameType)\n        local_ns = current_frame.f_back.f_locals  # type: ignore[union-attr]\n        # local_ns[\"touch\"] = self.interact\n        for method in (\n            \"play\",\n            \"wait\",\n            \"add\",\n            \"remove\",\n            \"interact\",\n            # \"clear\",\n            # \"save_state\",\n            # \"restore\",\n        ):\n            local_ns[method] = getattr(self, method)\n        shell(local_ns=local_ns, stack_depth=2)\n\n        # End scene when exiting an embed.\n        raise Exception(\"Exiting scene.\")\n\n    def _configure_pygui(self, update: bool = True) -> None:\n        if not self.dearpygui_imported:\n            raise RuntimeError(\"Attempted to use DearPyGUI when it isn't imported.\")\n        if update:\n            dpg.delete_item(window)\n        else:\n            dpg.create_viewport()\n            dpg.setup_dearpygui()\n            dpg.show_viewport()\n\n        dpg.set_viewport_title(title=f\"Manim Community v{__version__}\")\n        dpg.set_viewport_width(1015)\n        dpg.set_viewport_height(540)\n\n        def rerun_callback(sender: Any, data: Any) -> None:\n            self.queue.put(SceneInteractRerun(\"gui\"))\n\n        def continue_callback(sender: Any, data: Any) -> None:\n            self.queue.put(SceneInteractContinue(\"gui\"))\n\n        def scene_selection_callback(sender: Any, data: Any) -> None:\n            config[\"scene_names\"] = (dpg.get_value(sender),)\n            self.queue.put(SceneInteractRerun(\"gui\"))\n\n        scene_classes = scene_classes_from_file(\n            Path(config[\"input_file\"]), full_list=True\n        )  # type: ignore[call-overload]\n        scene_names = [scene_class.__name__ for scene_class in scene_classes]\n\n        with dpg.window(\n            id=window,\n            label=\"Manim GUI\",\n            pos=[config[\"gui_location\"][0], config[\"gui_location\"][1]],\n            width=1000,\n            height=500,\n        ):\n            dpg.set_global_font_scale(2)\n            dpg.add_button(label=\"Rerun\", callback=rerun_callback)\n            dpg.add_button(label=\"Continue\", callback=continue_callback)\n            dpg.add_combo(\n                label=\"Selected scene\",\n                items=scene_names,\n                callback=scene_selection_callback,\n                default_value=config[\"scene_names\"][0],\n            )\n            dpg.add_separator()\n            if len(self.widgets) != 0:\n                with dpg.collapsing_header(\n                    label=f\"{config['scene_names'][0]} widgets\",\n                    default_open=True,\n                ):\n                    for widget_config in self.widgets:\n                        widget_config_copy = widget_config.copy()\n                        name = widget_config_copy[\"name\"]\n                        widget = widget_config_copy[\"widget\"]\n                        if widget != \"separator\":\n                            del widget_config_copy[\"name\"]\n                            del widget_config_copy[\"widget\"]\n                            getattr(dpg, f\"add_{widget}\")(\n                                label=name, **widget_config_copy\n                            )\n                        else:\n                            dpg.add_separator()\n\n        if not update:\n            dpg.start_dearpygui()\n\n    def update_to_time(self, t: float) -> None:\n        dt = t - self.last_t\n        self.last_t = t\n        assert self.animations is not None\n        for animation in self.animations:\n            animation.update_mobjects(dt)\n            alpha = t / animation.run_time\n            animation.interpolate(alpha)\n        self.update_mobjects(dt)\n        self.update_meshes(dt)\n        self.update_self(dt)\n\n    def add_subcaption(\n        self, content: str, duration: float = 1, offset: float = 0\n    ) -> None:\n        r\"\"\"Adds an entry in the corresponding subcaption file\n        at the current time stamp.\n\n        The current time stamp is obtained from ``Scene.time``.\n\n        Parameters\n        ----------\n\n        content\n            The subcaption content.\n        duration\n            The duration (in seconds) for which the subcaption is shown.\n        offset\n            This offset (in seconds) is added to the starting time stamp\n            of the subcaption.\n\n        Examples\n        --------\n\n        This example illustrates both possibilities for adding\n        subcaptions to Manimations::\n\n            class SubcaptionExample(Scene):\n                def construct(self):\n                    square = Square()\n                    circle = Circle()\n\n                    # first option: via the add_subcaption method\n                    self.add_subcaption(\"Hello square!\", duration=1)\n                    self.play(Create(square))\n\n                    # second option: within the call to Scene.play\n                    self.play(\n                        Transform(square, circle), subcaption=\"The square transforms.\"\n                    )\n\n        \"\"\"\n        subtitle = srt.Subtitle(\n            index=len(self.renderer.file_writer.subcaptions),\n            content=content,\n            start=datetime.timedelta(seconds=float(self.time + offset)),\n            end=datetime.timedelta(seconds=float(self.time + offset + duration)),\n        )\n        self.renderer.file_writer.subcaptions.append(subtitle)\n\n    def add_sound(\n        self,\n        sound_file: str,\n        time_offset: float = 0,\n        gain: float | None = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        This method is used to add a sound to the animation.\n\n        Parameters\n        ----------\n\n        sound_file\n            The path to the sound file.\n        time_offset\n            The offset in the sound file after which\n            the sound can be played.\n        gain\n            Amplification of the sound.\n\n        Examples\n        --------\n        .. manim:: SoundExample\n            :no_autoplay:\n\n            class SoundExample(Scene):\n                # Source of sound under Creative Commons 0 License. https://freesound.org/people/Druminfected/sounds/250551/\n                def construct(self):\n                    dot = Dot().set_color(GREEN)\n                    self.add_sound(\"click.wav\")\n                    self.add(dot)\n                    self.wait()\n                    self.add_sound(\"click.wav\")\n                    dot.set_color(BLUE)\n                    self.wait()\n                    self.add_sound(\"click.wav\")\n                    dot.set_color(RED)\n                    self.wait()\n\n        Download the resource for the previous example `here <https://github.com/ManimCommunity/manim/blob/main/docs/source/_static/click.wav>`_ .\n        \"\"\"\n        if self.renderer.skip_animations:\n            return\n        time = self.time + time_offset\n        self.renderer.file_writer.add_sound(sound_file, time, gain, **kwargs)\n\n    def on_mouse_motion(self, point: Point3D, d_point: Point3D) -> None:\n        assert isinstance(self.camera, OpenGLCamera)\n        assert isinstance(self.renderer, OpenGLRenderer)\n        self.mouse_point.move_to(point)\n        if SHIFT_VALUE in self.renderer.pressed_keys:\n            shift = -d_point\n            shift[0] *= self.camera.get_width() / 2\n            shift[1] *= self.camera.get_height() / 2\n            transform = self.camera.inverse_rotation_matrix\n            shift = np.dot(np.transpose(transform), shift)\n            self.camera.shift(shift)\n\n    def on_mouse_scroll(self, point: Point3D, offset: Point3D) -> None:\n        assert isinstance(self.camera, OpenGLCamera)\n        if not config.use_projection_stroke_shaders:\n            factor = 1 + np.arctan(-2.1 * offset[1])\n            self.camera.scale(factor, about_point=self.camera_target)\n        self.mouse_scroll_orbit_controls(point, offset)\n\n    def on_key_press(self, symbol: int, modifiers: int) -> None:\n        assert isinstance(self.camera, OpenGLCamera)\n        try:\n            char = chr(symbol)\n        except OverflowError:\n            logger.warning(\"The value of the pressed key is too large.\")\n            return\n\n        if char == \"r\":\n            self.camera.to_default_state()\n            self.camera_target = np.array([0, 0, 0], dtype=np.float32)\n        elif char == \"q\":\n            self.quit_interaction = True\n        else:\n            if char in self.key_to_function_map:\n                self.key_to_function_map[char]()\n\n    def on_key_release(self, symbol: int, modifiers: int) -> None:\n        pass\n\n    def on_mouse_drag(\n        self,\n        point: Point3D,\n        d_point: Point3D,\n        buttons: int,\n        modifiers: int,\n    ) -> None:\n        assert isinstance(self.camera, OpenGLCamera)\n        self.mouse_drag_point.move_to(point)\n        if buttons == 1:\n            self.camera.increment_theta(-d_point[0])\n            self.camera.increment_phi(d_point[1])\n        elif buttons == 4:\n            camera_x_axis = self.camera.model_matrix[:3, 0]\n            horizontal_shift_vector = -d_point[0] * camera_x_axis\n            vertical_shift_vector = -d_point[1] * np.cross(OUT, camera_x_axis)\n            total_shift_vector = horizontal_shift_vector + vertical_shift_vector\n            self.camera.shift(1.1 * total_shift_vector)\n\n        self.mouse_drag_orbit_controls(point, d_point, buttons, modifiers)\n\n    def mouse_scroll_orbit_controls(self, point: Point3D, offset: Point3D) -> None:\n        assert isinstance(self.camera, OpenGLCamera)\n        camera_to_target = self.camera_target - self.camera.get_position()\n        camera_to_target *= np.sign(offset[1])\n        shift_vector = 0.01 * camera_to_target\n        self.camera.model_matrix = (\n            opengl.translation_matrix(*shift_vector) @ self.camera.model_matrix\n        )\n\n    def mouse_drag_orbit_controls(\n        self,\n        point: Point3D,\n        d_point: Point3D,\n        buttons: int,\n        modifiers: int,\n    ) -> None:\n        assert isinstance(self.camera, OpenGLCamera)\n        # Left click drag.\n        if buttons == 1:\n            # Translate to target the origin and rotate around the z axis.\n            self.camera.model_matrix = (\n                opengl.rotation_matrix(z=-d_point[0])\n                @ opengl.translation_matrix(*-self.camera_target)\n                @ self.camera.model_matrix\n            )\n\n            # Rotation off of the z axis.\n            camera_position = self.camera.get_position()\n            camera_y_axis = self.camera.model_matrix[:3, 1]\n            axis_of_rotation = space_ops.normalize(\n                np.cross(camera_y_axis, camera_position),\n            )\n            rotation_matrix = space_ops.rotation_matrix(\n                d_point[1],\n                axis_of_rotation,\n                homogeneous=True,\n            )\n\n            maximum_polar_angle = self.camera.maximum_polar_angle\n            minimum_polar_angle = self.camera.minimum_polar_angle\n\n            potential_camera_model_matrix = rotation_matrix @ self.camera.model_matrix\n            potential_camera_location = potential_camera_model_matrix[:3, 3]\n            potential_camera_y_axis = potential_camera_model_matrix[:3, 1]\n            sign = (\n                np.sign(potential_camera_y_axis[2])\n                if potential_camera_y_axis[2] != 0\n                else 1\n            )\n            potential_polar_angle = sign * np.arccos(\n                potential_camera_location[2]\n                / np.linalg.norm(potential_camera_location),\n            )\n            if minimum_polar_angle <= potential_polar_angle <= maximum_polar_angle:\n                self.camera.model_matrix = potential_camera_model_matrix\n            else:\n                sign = np.sign(camera_y_axis[2]) if camera_y_axis[2] != 0 else 1\n                current_polar_angle = sign * np.arccos(\n                    camera_position[2] / np.linalg.norm(camera_position),\n                )\n                if potential_polar_angle > maximum_polar_angle:\n                    polar_angle_delta = maximum_polar_angle - current_polar_angle\n                else:\n                    polar_angle_delta = minimum_polar_angle - current_polar_angle\n                rotation_matrix = space_ops.rotation_matrix(\n                    polar_angle_delta,\n                    axis_of_rotation,\n                    homogeneous=True,\n                )\n                self.camera.model_matrix = rotation_matrix @ self.camera.model_matrix\n\n            # Translate to target the original target.\n            self.camera.model_matrix = (\n                opengl.translation_matrix(*self.camera_target)\n                @ self.camera.model_matrix\n            )\n        # Right click drag.\n        elif buttons == 4:\n            camera_x_axis = self.camera.model_matrix[:3, 0]\n            horizontal_shift_vector = -d_point[0] * camera_x_axis\n            vertical_shift_vector = -d_point[1] * np.cross(OUT, camera_x_axis)\n            total_shift_vector = horizontal_shift_vector + vertical_shift_vector\n\n            self.camera.model_matrix = (\n                opengl.translation_matrix(*total_shift_vector)\n                @ self.camera.model_matrix\n            )\n            self.camera_target += total_shift_vector\n\n    def set_key_function(self, char: str, func: Callable[[], Any]) -> None:\n        self.key_to_function_map[char] = func\n\n    def on_mouse_press(self, point: Point3D, button: str, modifiers: int) -> None:\n        for func in self.mouse_press_callbacks:\n            func()\n"
  },
  {
    "path": "manim/scene/scene_file_writer.py",
    "content": "\"\"\"The interface between scenes and ffmpeg.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"SceneFileWriter\"]\n\nimport json\nimport shutil\nimport warnings\nfrom fractions import Fraction\nfrom pathlib import Path\nfrom queue import Queue\nfrom tempfile import NamedTemporaryFile, _TemporaryFileWrapper\nfrom threading import Thread\nfrom typing import TYPE_CHECKING, Any\n\nimport av\nimport numpy as np\nimport srt\nfrom PIL import Image\n\n# Manim handles audio conversion through PyAV directly. Importing pydub emits a\n# RuntimeWarning if ffmpeg/avconv is not on PATH, even when only WAV code paths\n# are used (which do not need ffmpeg). Silence this specific warning.\nwith warnings.catch_warnings():\n    warnings.filterwarnings(\n        \"ignore\",\n        message=r\".*ffmpeg or avconv.*\",\n        category=RuntimeWarning,\n    )\n    from pydub import AudioSegment\n\nfrom manim import __version__\n\nfrom .. import config, logger\nfrom .._config.logger_utils import set_file_logger\nfrom ..constants import RendererType\nfrom ..utils.file_ops import (\n    add_extension_if_not_present,\n    add_version_before_extension,\n    guarantee_existence,\n    is_gif_format,\n    is_png_format,\n    modify_atime,\n    write_to_movie,\n)\nfrom ..utils.sounds import get_full_sound_file_path\nfrom .section import DefaultSectionType, Section\n\nif TYPE_CHECKING:\n    from av.container.output import OutputContainer\n    from av.stream import Stream\n\n    from manim.renderer.cairo_renderer import CairoRenderer\n    from manim.renderer.opengl_renderer import OpenGLRenderer\n    from manim.typing import PixelArray, StrPath\n\n\ndef to_av_frame_rate(fps: float) -> Fraction:\n    epsilon1 = 1e-4\n    epsilon2 = 0.02\n\n    if isinstance(fps, int):\n        (num, denom) = (fps, 1)\n    elif abs(fps - round(fps)) < epsilon1:\n        (num, denom) = (round(fps), 1)\n    else:\n        denom = 1001\n        num = round(fps * denom / 1000) * 1000\n        if abs(fps - num / denom) >= epsilon2:\n            raise ValueError(\"invalid frame rate\")\n\n    return Fraction(num, denom)\n\n\ndef convert_audio(\n    input_path: Path, output_path: Path | _TemporaryFileWrapper[bytes], codec_name: str\n) -> None:\n    with (\n        av.open(input_path) as input_audio,\n        av.open(output_path, \"w\") as output_audio,\n    ):\n        input_audio_stream = input_audio.streams.audio[0]\n        output_audio_stream = output_audio.add_stream(codec_name)\n        for frame in input_audio.decode(input_audio_stream):\n            for packet in output_audio_stream.encode(frame):\n                output_audio.mux(packet)\n\n        for packet in output_audio_stream.encode():\n            output_audio.mux(packet)\n\n\nclass SceneFileWriter:\n    \"\"\"SceneFileWriter is the object that actually writes the animations\n    played, into video files, using FFMPEG.\n    This is mostly for Manim's internal use. You will rarely, if ever,\n    have to use the methods for this class, unless tinkering with the very\n    fabric of Manim's reality.\n\n    Attributes\n    ----------\n        sections : list of :class:`.Section`\n            used to segment scene\n\n        sections_output_dir : :class:`pathlib.Path`\n            where are section videos stored\n\n        output_name : str\n            name of movie without extension and basis for section video names\n\n    Some useful attributes are:\n        \"write_to_movie\" (bool=False)\n            Whether or not to write the animations into a video file.\n        \"movie_file_extension\" (str=\".mp4\")\n            The file-type extension of the outputted video.\n        \"partial_movie_files\"\n            List of all the partial-movie files.\n\n    \"\"\"\n\n    force_output_as_scene_name = False\n\n    def __init__(\n        self,\n        renderer: CairoRenderer | OpenGLRenderer,\n        scene_name: str,\n        **kwargs: Any,\n    ) -> None:\n        self.renderer = renderer\n        self.init_output_directories(scene_name)\n        self.init_audio()\n        self.frame_count = 0\n        self.partial_movie_files: list[str | None] = []\n        self.subcaptions: list[srt.Subtitle] = []\n        self.sections: list[Section] = []\n        # first section gets automatically created for convenience\n        # if you need the first section to be skipped, add a first section by hand, it will replace this one\n        self.next_section(\n            name=\"autocreated\", type_=DefaultSectionType.NORMAL, skip_animations=False\n        )\n\n    def init_output_directories(self, scene_name: str) -> None:\n        \"\"\"Initialise output directories.\n\n        Notes\n        -----\n        The directories are read from ``config``, for example\n        ``config['media_dir']``.  If the target directories don't already\n        exist, they will be created.\n\n        \"\"\"\n        if config[\"dry_run\"]:  # in dry-run mode there is no output\n            return\n\n        module_name = config.get_dir(\"input_file\").stem if config[\"input_file\"] else \"\"\n\n        if SceneFileWriter.force_output_as_scene_name:\n            self.output_name = Path(scene_name)\n        elif config[\"output_file\"] and not config[\"write_all\"]:\n            self.output_name = config.get_dir(\"output_file\")\n        else:\n            self.output_name = Path(scene_name)\n\n        if config[\"media_dir\"]:\n            image_dir = guarantee_existence(\n                config.get_dir(\n                    \"images_dir\", module_name=module_name, scene_name=scene_name\n                ),\n            )\n            self.image_file_path = image_dir / add_extension_if_not_present(\n                self.output_name, \".png\"\n            )\n\n        if write_to_movie():\n            movie_dir = guarantee_existence(\n                config.get_dir(\n                    \"video_dir\", module_name=module_name, scene_name=scene_name\n                ),\n            )\n            self.movie_file_path = movie_dir / add_extension_if_not_present(\n                self.output_name, config[\"movie_file_extension\"]\n            )\n\n            # TODO: /dev/null would be good in case sections_output_dir is used without being set (doesn't work on Windows), everyone likes defensive programming, right?\n            self.sections_output_dir = Path(\"\")\n            if config.save_sections:\n                self.sections_output_dir = guarantee_existence(\n                    config.get_dir(\n                        \"sections_dir\", module_name=module_name, scene_name=scene_name\n                    )\n                )\n\n            if is_gif_format():\n                self.gif_file_path = add_extension_if_not_present(\n                    self.output_name, \".gif\"\n                )\n\n                if not config[\"output_file\"]:\n                    self.gif_file_path = add_version_before_extension(\n                        self.gif_file_path\n                    )\n\n                self.gif_file_path = movie_dir / self.gif_file_path\n\n            self.partial_movie_directory = guarantee_existence(\n                config.get_dir(\n                    \"partial_movie_dir\",\n                    scene_name=scene_name,\n                    module_name=module_name,\n                ),\n            )\n\n            if config[\"log_to_file\"]:\n                log_dir = guarantee_existence(config.get_dir(\"log_dir\"))\n                set_file_logger(\n                    scene_name=scene_name, module_name=module_name, log_dir=log_dir\n                )\n\n    def finish_last_section(self) -> None:\n        \"\"\"Delete current section if it is empty.\"\"\"\n        if len(self.sections) and self.sections[-1].is_empty():\n            self.sections.pop()\n\n    def next_section(self, name: str, type_: str, skip_animations: bool) -> None:\n        \"\"\"Create segmentation cut here.\"\"\"\n        self.finish_last_section()\n\n        # images don't support sections\n        section_video: str | None = None\n        # don't save when None\n        if (\n            not config.dry_run\n            and write_to_movie()\n            and config.save_sections\n            and not skip_animations\n        ):\n            # relative to index file\n            section_video = f\"{self.output_name}_{len(self.sections):04}_{name}{config.movie_file_extension}\"\n\n        self.sections.append(\n            Section(\n                type_,\n                section_video,\n                name,\n                skip_animations,\n            ),\n        )\n\n    def add_partial_movie_file(self, hash_animation: str | None) -> None:\n        \"\"\"Adds a new partial movie file path to ``scene.partial_movie_files``\n        and current section from a hash.\n\n        This method will compute the path from the hash. In addition to that it\n        adds the new animation to the current section.\n\n        Parameters\n        ----------\n        hash_animation\n            Hash of the animation.\n        \"\"\"\n        if not hasattr(self, \"partial_movie_directory\") or not write_to_movie():\n            return\n\n        # None has to be added to partial_movie_files to keep the right index with scene.num_plays.\n        # i.e if an animation is skipped, scene.num_plays is still incremented and we add an element to partial_movie_file be even with num_plays.\n        if hash_animation is None:\n            self.partial_movie_files.append(None)\n            self.sections[-1].partial_movie_files.append(None)\n        else:\n            new_partial_movie_file = str(\n                self.partial_movie_directory\n                / f\"{hash_animation}{config['movie_file_extension']}\"\n            )\n            self.partial_movie_files.append(new_partial_movie_file)\n            self.sections[-1].partial_movie_files.append(new_partial_movie_file)\n\n    def get_resolution_directory(self) -> str:\n        \"\"\"Get the name of the resolution directory directly containing\n        the video file.\n\n        This method gets the name of the directory that immediately contains the\n        video file. This name is ``<height_in_pixels_of_video>p<frame_rate>``.\n        For example, if you are rendering an 854x480 px animation at 15fps,\n        the name of the directory that immediately contains the video,  file\n        will be ``480p15``.\n\n        The file structure should look something like::\n\n            MEDIA_DIR\n                |--Tex\n                |--texts\n                |--videos\n                    |--<name_of_file_containing_scene>\n                        |--<height_in_pixels_of_video>p<frame_rate>\n                            |--partial_movie_files\n                            |--<scene_name>.mp4\n                            |--<scene_name>.srt\n\n        Returns\n        -------\n        :class:`str`\n            The name of the directory.\n        \"\"\"\n        pixel_height = config[\"pixel_height\"]\n        frame_rate = config[\"frame_rate\"]\n        return f\"{pixel_height}p{frame_rate}\"\n\n    # Sound\n    def init_audio(self) -> None:\n        \"\"\"Preps the writer for adding audio to the movie.\"\"\"\n        self.includes_sound = False\n\n    def create_audio_segment(self) -> None:\n        \"\"\"Creates an empty, silent, Audio Segment.\"\"\"\n        self.audio_segment = AudioSegment.silent()\n\n    def add_audio_segment(\n        self,\n        new_segment: AudioSegment,\n        time: float | None = None,\n        gain_to_background: float | None = None,\n    ) -> None:\n        \"\"\"This method adds an audio segment from an AudioSegment type object\n        and suitable parameters.\n\n        Parameters\n        ----------\n        new_segment\n            The audio segment to add\n\n        time\n            the timestamp at which the sound should be added.\n\n        gain_to_background\n            The gain of the segment from the background.\n        \"\"\"\n        if not self.includes_sound:\n            self.includes_sound = True\n            self.create_audio_segment()\n        segment = self.audio_segment\n        curr_end = segment.duration_seconds\n        if time is None:\n            time = curr_end\n        if time < 0:\n            raise ValueError(\"Adding sound at timestamp < 0\")\n\n        new_end = time + new_segment.duration_seconds\n        diff = new_end - curr_end\n        if diff > 0:\n            segment = segment.append(\n                AudioSegment.silent(int(np.ceil(diff * 1000))),\n                crossfade=0,\n            )\n        self.audio_segment = segment.overlay(\n            new_segment,\n            position=int(1000 * time),\n            gain_during_overlay=gain_to_background,\n        )\n\n    def add_sound(\n        self,\n        sound_file: StrPath,\n        time: float | None = None,\n        gain: float | None = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"This method adds an audio segment from a sound file.\n\n        Parameters\n        ----------\n        sound_file\n            The path to the sound file.\n\n        time\n            The timestamp at which the audio should be added.\n\n        gain\n            The gain of the given audio segment.\n\n        **kwargs\n            This method uses add_audio_segment, so any keyword arguments\n            used there can be referenced here.\n\n        \"\"\"\n        file_path = get_full_sound_file_path(sound_file)\n        # we assume files with .wav / .raw suffix are actually\n        # .wav and .raw files, respectively.\n        if file_path.suffix not in (\".wav\", \".raw\"):\n            # we need to pass delete=False to work on Windows\n            # TODO: figure out a way to cache the wav file generated (benchmark needed)\n            with NamedTemporaryFile(suffix=\".wav\", delete=False) as wav_file_path:\n                convert_audio(file_path, wav_file_path, \"pcm_s16le\")\n                new_segment = AudioSegment.from_file(wav_file_path.name)\n                logger.info(f\"Automatically converted {file_path} to .wav\")\n            Path(wav_file_path.name).unlink()\n        else:\n            new_segment = AudioSegment.from_file(file_path)\n\n        if gain:\n            new_segment = new_segment.apply_gain(gain)\n        self.add_audio_segment(new_segment, time, **kwargs)\n\n    # Writers\n    def begin_animation(\n        self, allow_write: bool = False, file_path: StrPath | None = None\n    ) -> None:\n        \"\"\"Used internally by manim to stream the animation to FFMPEG for\n        displaying or writing to a file.\n\n        Parameters\n        ----------\n        allow_write\n            Whether or not to write to a video file.\n        \"\"\"\n        if write_to_movie() and allow_write:\n            self.open_partial_movie_stream(file_path=file_path)\n\n    def end_animation(self, allow_write: bool = False) -> None:\n        \"\"\"Internally used by Manim to stop streaming to FFMPEG gracefully.\n\n        Parameters\n        ----------\n        allow_write\n            Whether or not to write to a video file.\n        \"\"\"\n        if write_to_movie() and allow_write:\n            self.close_partial_movie_stream()\n\n    def listen_and_write(self) -> None:\n        \"\"\"For internal use only: blocks until new frame is available on the queue.\"\"\"\n        while True:\n            num_frames, frame_data = self.queue.get()\n            if frame_data is None:\n                break\n\n            self.encode_and_write_frame(frame_data, num_frames)\n\n    def encode_and_write_frame(self, frame: PixelArray, num_frames: int) -> None:\n        \"\"\"For internal use only: takes a given frame in ``np.ndarray`` format and\n        writes it to the stream\n        \"\"\"\n        for _ in range(num_frames):\n            # Notes: precomputing reusing packets does not work!\n            # I.e., you cannot do `packets = encode(...)`\n            # and reuse it, as it seems that `mux(...)`\n            # consumes the packet.\n            # The same issue applies for `av_frame`,\n            # reusing it renders weird-looking frames.\n            av_frame = av.VideoFrame.from_ndarray(frame, format=\"rgba\")\n            for packet in self.video_stream.encode(av_frame):\n                self.video_container.mux(packet)\n\n    def write_frame(\n        self, frame_or_renderer: PixelArray | OpenGLRenderer, num_frames: int = 1\n    ) -> None:\n        \"\"\"Used internally by Manim to write a frame to the FFMPEG input buffer.\n\n        Parameters\n        ----------\n        frame_or_renderer\n            Pixel array of the frame.\n        num_frames\n            The number of times to write frame.\n        \"\"\"\n        if write_to_movie():\n            if isinstance(frame_or_renderer, np.ndarray):\n                frame = frame_or_renderer\n            else:\n                frame = (\n                    frame_or_renderer.get_frame()\n                    if config.renderer == RendererType.OPENGL\n                    else frame_or_renderer\n                )\n\n            msg = (num_frames, frame)\n            self.queue.put(msg)\n\n        if is_png_format() and not config[\"dry_run\"]:\n            if isinstance(frame_or_renderer, np.ndarray):\n                image = Image.fromarray(frame_or_renderer)\n            else:\n                image = (\n                    frame_or_renderer.get_image()\n                    if config.renderer == RendererType.OPENGL\n                    else Image.fromarray(frame_or_renderer)\n                )\n            target_dir = self.image_file_path.parent / self.image_file_path.stem\n            extension = self.image_file_path.suffix\n            self.output_image(\n                image,\n                target_dir,\n                extension,\n                config[\"zero_pad\"],\n            )\n\n    def output_image(\n        self, image: Image.Image, target_dir: StrPath, ext: str, zero_pad: int\n    ) -> None:\n        if zero_pad:\n            image.save(f\"{target_dir}{str(self.frame_count).zfill(zero_pad)}{ext}\")\n        else:\n            image.save(f\"{target_dir}{self.frame_count}{ext}\")\n        self.frame_count += 1\n\n    def save_image(self, image: Image.Image) -> None:\n        \"\"\"This method saves the image passed to it in the default image directory.\n\n        Parameters\n        ----------\n        image\n            The pixel array of the image to save.\n        \"\"\"\n        if config[\"dry_run\"]:\n            return\n        if not config[\"output_file\"]:\n            self.image_file_path = add_version_before_extension(self.image_file_path)\n\n        image.save(self.image_file_path)\n        self.print_file_ready_message(self.image_file_path)\n\n    def finish(self) -> None:\n        \"\"\"Finishes writing to the FFMPEG buffer or writing images to output directory.\n        Combines the partial movie files into the whole scene.\n        If save_last_frame is True, saves the last frame in the default image directory.\n        \"\"\"\n        if write_to_movie():\n            self.combine_to_movie()\n            if config.save_sections:\n                self.combine_to_section_videos()\n            if config[\"flush_cache\"]:\n                self.flush_cache_directory()\n            else:\n                self.clean_cache()\n        elif is_png_format() and not config[\"dry_run\"]:\n            target_dir = self.image_file_path.parent / self.image_file_path.stem\n            logger.info(\"\\n%i images ready at %s\\n\", self.frame_count, str(target_dir))\n        if self.subcaptions:\n            self.write_subcaption_file()\n\n    def open_partial_movie_stream(self, file_path: StrPath | None = None) -> None:\n        \"\"\"Open a container holding a video stream.\n\n        This is used internally by Manim initialize the container holding\n        the video stream of a partial movie file.\n        \"\"\"\n        if file_path is None:\n            file_path = self.partial_movie_files[self.renderer.num_plays]\n        self.partial_movie_file_path = file_path\n\n        fps = to_av_frame_rate(config.frame_rate)\n\n        partial_movie_file_codec = \"libx264\"\n        partial_movie_file_pix_fmt = \"yuv420p\"\n        av_options = {\n            \"an\": \"1\",  # ffmpeg: -an, no audio\n            \"crf\": \"23\",  # ffmpeg: -crf, constant rate factor (improved bitrate)\n        }\n\n        if config.movie_file_extension == \".webm\":\n            partial_movie_file_codec = \"libvpx-vp9\"\n            av_options[\"-auto-alt-ref\"] = \"1\"\n            if config.transparent:\n                partial_movie_file_pix_fmt = \"yuva420p\"\n\n        elif config.transparent:\n            partial_movie_file_codec = \"qtrle\"\n            partial_movie_file_pix_fmt = \"argb\"\n\n        video_container = av.open(file_path, mode=\"w\")\n        stream = video_container.add_stream(\n            partial_movie_file_codec,\n            rate=fps,\n            options=av_options,\n        )\n        stream.pix_fmt = partial_movie_file_pix_fmt\n        stream.width = config.pixel_width\n        stream.height = config.pixel_height\n\n        self.video_container: OutputContainer = video_container\n        self.video_stream: Stream = stream\n\n        self.queue: Queue[tuple[int, PixelArray | None]] = Queue()\n        self.writer_thread = Thread(target=self.listen_and_write, args=())\n        self.writer_thread.start()\n\n    def close_partial_movie_stream(self) -> None:\n        \"\"\"Close the currently opened video container.\n\n        Used internally by Manim to first flush the remaining packages\n        in the video stream holding a partial file, and then close\n        the corresponding container.\n        \"\"\"\n        self.queue.put((-1, None))\n        self.writer_thread.join()\n\n        for packet in self.video_stream.encode():\n            self.video_container.mux(packet)\n\n        self.video_container.close()\n\n        logger.info(\n            f\"Animation {self.renderer.num_plays} : Partial movie file written in %(path)s\",\n            {\"path\": f\"'{self.partial_movie_file_path}'\"},\n        )\n\n    def is_already_cached(self, hash_invocation: str) -> bool:\n        \"\"\"Will check if a file named with `hash_invocation` exists.\n\n        Parameters\n        ----------\n        hash_invocation\n            The hash corresponding to an invocation to either `scene.play` or `scene.wait`.\n\n        Returns\n        -------\n        :class:`bool`\n            Whether the file exists.\n        \"\"\"\n        if not hasattr(self, \"partial_movie_directory\") or not write_to_movie():\n            return False\n        path = (\n            self.partial_movie_directory\n            / f\"{hash_invocation}{config['movie_file_extension']}\"\n        )\n        return path.exists()\n\n    def combine_files(\n        self,\n        input_files: list[str],\n        output_file: Path,\n        create_gif: bool = False,\n        includes_sound: bool = False,\n    ) -> None:\n        file_list = self.partial_movie_directory / \"partial_movie_file_list.txt\"\n        logger.debug(\n            f\"Partial movie files to combine ({len(input_files)} files): %(p)s\",\n            {\"p\": input_files[:5]},\n        )\n        with file_list.open(\"w\", encoding=\"utf-8\") as fp:\n            fp.write(\"# This file is used internally by FFMPEG.\\n\")\n            for pf_path in input_files:\n                pf_path = Path(pf_path).as_posix()\n                fp.write(f\"file 'file:{pf_path}'\\n\")\n\n        av_options = {\n            \"safe\": \"0\",  # needed to read files\n        }\n\n        if not includes_sound:\n            av_options[\"an\"] = \"1\"\n\n        partial_movies_input = av.open(\n            str(file_list), options=av_options, format=\"concat\"\n        )\n        partial_movies_stream = partial_movies_input.streams.video[0]\n        output_container = av.open(str(output_file), mode=\"w\")\n        output_container.metadata[\"comment\"] = (\n            f\"Rendered with Manim Community v{__version__}\"\n        )\n        if create_gif:\n            \"\"\"The following solution was largely inspired from this comment\n            https://github.com/imageio/imageio/issues/995#issuecomment-1580533018,\n            and the following code\n            https://github.com/imageio/imageio/blob/65d79140018bb7c64c0692ea72cb4093e8d632a0/imageio/plugins/pyav.py#L927-L996.\n            \"\"\"\n            output_stream = output_container.add_stream(\n                codec_name=\"gif\",\n            )\n            output_stream.pix_fmt = \"rgb8\"\n            if config.transparent:\n                output_stream.pix_fmt = \"pal8\"\n            output_stream.width = config.pixel_width\n            output_stream.height = config.pixel_height\n            output_stream.rate = to_av_frame_rate(config.frame_rate)\n            graph = av.filter.Graph()\n            input_buffer = graph.add_buffer(template=partial_movies_stream)\n            split = graph.add(\"split\")\n            palettegen = graph.add(\"palettegen\", \"stats_mode=diff\")\n            paletteuse = graph.add(\n                \"paletteuse\", \"dither=bayer:bayer_scale=5:diff_mode=rectangle\"\n            )\n            output_sink = graph.add(\"buffersink\")\n\n            input_buffer.link_to(split)\n            split.link_to(palettegen, 0, 0)  # 1st input of split -> input of palettegen\n            split.link_to(paletteuse, 1, 0)  # 2nd output of split -> 1st input\n            palettegen.link_to(paletteuse, 0, 1)  # output of palettegen -> 2nd input\n            paletteuse.link_to(output_sink)\n\n            graph.configure()\n\n            for frame in partial_movies_input.decode(video=0):\n                graph.push(frame)\n\n            graph.push(None)  # EOF: https://github.com/PyAV-Org/PyAV/issues/886.\n\n            frames_written = 0\n            while True:\n                try:\n                    frame = graph.pull()\n                    if output_stream.codec_context.time_base is not None:\n                        frame.time_base = output_stream.codec_context.time_base\n                    frame.pts = frames_written\n                    frames_written += 1\n                    output_container.mux(output_stream.encode(frame))\n                except av.error.EOFError:\n                    break\n\n            for packet in output_stream.encode():\n                output_container.mux(packet)\n\n        else:\n            output_stream = output_container.add_stream_from_template(\n                template=partial_movies_stream,\n            )\n            if config.transparent and config.movie_file_extension == \".webm\":\n                output_stream.pix_fmt = \"yuva420p\"\n            for packet in partial_movies_input.demux(partial_movies_stream):\n                # We need to skip the \"flushing\" packets that `demux` generates.\n                if packet.dts is None:\n                    continue\n\n                packet.dts = None  # This seems to be needed, as dts from consecutive\n                # files may not be monotically increasing, so we let libav compute it.\n\n                # We need to assign the packet to the new stream.\n                packet.stream = output_stream\n                output_container.mux(packet)\n\n        partial_movies_input.close()\n        output_container.close()\n\n    def combine_to_movie(self) -> None:\n        \"\"\"Used internally by Manim to combine the separate\n        partial movie files that make up a Scene into a single\n        video file for that Scene.\n        \"\"\"\n        partial_movie_files = [el for el in self.partial_movie_files if el is not None]\n        # NOTE: Here we should do a check and raise an exception if partial\n        # movie file is empty.  We can't, as a lot of stuff (in particular, in\n        # tests) use scene initialization, and this error would be raised as\n        # it's just an empty scene initialized.\n\n        # determine output path\n        movie_file_path = self.movie_file_path\n        if is_gif_format():\n            movie_file_path = self.gif_file_path\n\n        if len(partial_movie_files) == 0:  # Prevent calling concat on empty list\n            logger.info(\"No animations are contained in this scene.\")\n            return\n\n        logger.info(\"Combining to Movie file.\")\n        self.combine_files(\n            partial_movie_files,\n            movie_file_path,\n            is_gif_format(),\n            self.includes_sound,\n        )\n\n        # handle sound\n        if self.includes_sound and config.format != \"gif\":\n            sound_file_path = movie_file_path.with_suffix(\".wav\")\n            # Makes sure sound file length will match video file\n            self.add_audio_segment(AudioSegment.silent(0))\n            self.audio_segment.export(\n                sound_file_path,\n                format=\"wav\",\n                bitrate=\"312k\",\n            )\n            # Audio added to a VP9 encoded (webm) video file needs\n            # to be encoded as vorbis or opus. Directly exporting\n            # self.audio_segment with such a codec works in principle,\n            # but tries to call ffmpeg via its CLI -- which we want\n            # to avoid. This is why we need to do the conversion\n            # manually.\n            if config.movie_file_extension == \".webm\":\n                ogg_sound_file_path = sound_file_path.with_suffix(\".ogg\")\n                convert_audio(sound_file_path, ogg_sound_file_path, \"libvorbis\")\n                sound_file_path = ogg_sound_file_path\n            elif config.movie_file_extension == \".mp4\":\n                # Similarly, pyav may reject wav audio in an .mp4 file;\n                # convert to AAC.\n                aac_sound_file_path = sound_file_path.with_suffix(\".aac\")\n                convert_audio(sound_file_path, aac_sound_file_path, \"aac\")\n                sound_file_path = aac_sound_file_path\n\n            temp_file_path = movie_file_path.with_name(\n                f\"{movie_file_path.stem}_temp{movie_file_path.suffix}\"\n            )\n            av_options = {\n                \"shortest\": \"1\",\n                \"metadata\": f\"comment=Rendered with Manim Community v{__version__}\",\n            }\n\n            with (\n                av.open(movie_file_path) as video_input,\n                av.open(sound_file_path) as audio_input,\n            ):\n                video_stream = video_input.streams.video[0]\n                audio_stream = audio_input.streams.audio[0]\n                output_container = av.open(\n                    str(temp_file_path), mode=\"w\", options=av_options\n                )\n                output_video_stream = output_container.add_stream_from_template(\n                    template=video_stream\n                )\n                output_audio_stream = output_container.add_stream_from_template(\n                    template=audio_stream\n                )\n\n                for packet in video_input.demux(video_stream):\n                    # We need to skip the \"flushing\" packets that `demux` generates.\n                    if packet.dts is None:\n                        continue\n\n                    # We need to assign the packet to the new stream.\n                    packet.stream = output_video_stream\n                    output_container.mux(packet)\n\n                for packet in audio_input.demux(audio_stream):\n                    # We need to skip the \"flushing\" packets that `demux` generates.\n                    if packet.dts is None:\n                        continue\n\n                    # We need to assign the packet to the new stream.\n                    packet.stream = output_audio_stream\n                    output_container.mux(packet)\n\n                output_container.close()\n\n            shutil.move(str(temp_file_path), str(movie_file_path))\n            sound_file_path.unlink()\n\n        self.print_file_ready_message(str(movie_file_path))\n        if write_to_movie():\n            for file_path in partial_movie_files:\n                # We have to modify the accessed time so if we have to clean the cache we remove the one used the longest.\n                modify_atime(file_path)\n\n    def combine_to_section_videos(self) -> None:\n        \"\"\"Concatenate partial movie files for each section.\"\"\"\n        self.finish_last_section()\n        sections_index: list[dict[str, Any]] = []\n        for section in self.sections:\n            # only if section does want to be saved\n            if section.video is not None:\n                logger.info(f\"Combining partial files for section '{section.name}'\")\n                self.combine_files(\n                    section.get_clean_partial_movie_files(),\n                    self.sections_output_dir / section.video,\n                )\n                sections_index.append(section.get_dict(self.sections_output_dir))\n        with (self.sections_output_dir / f\"{self.output_name}.json\").open(\"w\") as file:\n            json.dump(sections_index, file, indent=4)\n\n    def clean_cache(self) -> None:\n        \"\"\"Will clean the cache by removing the oldest partial_movie_files.\"\"\"\n        cached_partial_movies = [\n            (self.partial_movie_directory / file_name)\n            for file_name in self.partial_movie_directory.iterdir()\n            if file_name != \"partial_movie_file_list.txt\"\n        ]\n        if len(cached_partial_movies) > config[\"max_files_cached\"]:\n            number_files_to_delete = (\n                len(cached_partial_movies) - config[\"max_files_cached\"]\n            )\n            oldest_files_to_delete = sorted(\n                cached_partial_movies,\n                key=lambda path: path.stat().st_atime,\n            )[:number_files_to_delete]\n            for file_to_delete in oldest_files_to_delete:\n                file_to_delete.unlink()\n            logger.info(\n                f\"The partial movie directory is full (> {config['max_files_cached']} files). Therefore, manim has removed the {number_files_to_delete} oldest file(s).\"\n                \" You can change this behaviour by changing max_files_cached in config.\",\n            )\n\n    def flush_cache_directory(self) -> None:\n        \"\"\"Delete all the cached partial movie files\"\"\"\n        cached_partial_movies = [\n            self.partial_movie_directory / file_name\n            for file_name in self.partial_movie_directory.iterdir()\n            if file_name != \"partial_movie_file_list.txt\"\n        ]\n        for f in cached_partial_movies:\n            f.unlink()\n        logger.info(\n            f\"Cache flushed. {len(cached_partial_movies)} file(s) deleted in %(par_dir)s.\",\n            {\"par_dir\": self.partial_movie_directory},\n        )\n\n    def write_subcaption_file(self) -> None:\n        \"\"\"Writes the subcaption file.\"\"\"\n        if config.output_file is None:\n            return\n        subcaption_file = Path(config.output_file).with_suffix(\".srt\")\n        subcaption_file.write_text(srt.compose(self.subcaptions), encoding=\"utf-8\")\n        logger.info(f\"Subcaption file has been written as {subcaption_file}\")\n\n    def print_file_ready_message(self, file_path: StrPath) -> None:\n        \"\"\"Prints the \"File Ready\" message to STDOUT.\"\"\"\n        config[\"output_file\"] = file_path\n        logger.info(\"\\nFile ready at %(file_path)s\\n\", {\"file_path\": f\"'{file_path}'\"})\n"
  },
  {
    "path": "manim/scene/section.py",
    "content": "\"\"\"building blocks of segmented video API\"\"\"\n\nfrom __future__ import annotations\n\nfrom enum import Enum\nfrom pathlib import Path\nfrom typing import Any\n\nfrom manim import get_video_metadata\n\n__all__ = [\"Section\", \"DefaultSectionType\"]\n\n\nclass DefaultSectionType(str, Enum):\n    \"\"\"The type of a section can be used for third party applications.\n    A presentation system could for example use the types to created loops.\n\n    Examples\n    --------\n    This class can be reimplemented for more types::\n\n        class PresentationSectionType(str, Enum):\n            # start, end, wait for continuation by user\n            NORMAL = \"presentation.normal\"\n            # start, end, immediately continue to next section\n            SKIP = \"presentation.skip\"\n            # start, end, restart, immediately continue to next section when continued by user\n            LOOP = \"presentation.loop\"\n            # start, end, restart, finish animation first when user continues\n            COMPLETE_LOOP = \"presentation.complete_loop\"\n    \"\"\"\n\n    NORMAL = \"default.normal\"\n\n\nclass Section:\n    r\"\"\"A :class:`.Scene` can be segmented into multiple Sections.\n    Refer to :doc:`the documentation</tutorials/output_and_config>` for more info.\n    It consists of multiple animations.\n\n    Attributes\n    ----------\n        type\\_\n            Can be used by a third party applications to classify different types of sections.\n        video\n            Path to video file with animations belonging to section relative to sections directory.\n            If ``None``, then the section will not be saved.\n        name\n            Human readable, non-unique name for this section.\n        skip_animations\n            Skip rendering the animations in this section when ``True``.\n        partial_movie_files\n            Animations belonging to this section.\n\n    See Also\n    --------\n    :class:`.DefaultSectionType`\n    :meth:`.CairoRenderer.update_skipping_status`\n    :meth:`.OpenGLRenderer.update_skipping_status`\n    \"\"\"\n\n    def __init__(\n        self, type_: str, video: str | None, name: str, skip_animations: bool\n    ) -> None:\n        self.type_ = type_\n        # None when not to be saved -> still keeps section alive\n        self.video: str | None = video\n        self.name = name\n        self.skip_animations = skip_animations\n        self.partial_movie_files: list[str | None] = []\n\n    def is_empty(self) -> bool:\n        \"\"\"Check whether this section is empty.\n\n        Note that animations represented by ``None`` are also counted.\n        \"\"\"\n        return len(self.partial_movie_files) == 0\n\n    def get_clean_partial_movie_files(self) -> list[str]:\n        \"\"\"Return all partial movie files that are not ``None``.\"\"\"\n        return [el for el in self.partial_movie_files if el is not None]\n\n    def get_dict(self, sections_dir: Path) -> dict[str, Any]:\n        \"\"\"Get dictionary representation with metadata of output video.\n\n        The output from this function is used from every section to build the sections index file.\n        The output video must have been created in the ``sections_dir`` before executing this method.\n        This is the main part of the Segmented Video API.\n        \"\"\"\n        if self.video is None:\n            raise ValueError(\n                f\"Section '{self.name}' cannot be exported as dict, it does not have a video path assigned to it\"\n            )\n\n        video_metadata = get_video_metadata(sections_dir / self.video)\n        return dict(\n            {\n                \"name\": self.name,\n                \"type\": self.type_,\n                \"video\": self.video,\n            },\n            **video_metadata,\n        )\n\n    def __repr__(self) -> str:\n        return f\"<Section '{self.name}' stored in '{self.video}'>\"\n"
  },
  {
    "path": "manim/scene/three_d_scene.py",
    "content": "\"\"\"A scene suitable for rendering three-dimensional objects and animations.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"ThreeDScene\", \"SpecialThreeDScene\"]\n\n\nimport warnings\nfrom collections.abc import Iterable, Sequence\n\nimport numpy as np\n\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.graphing.coordinate_systems import ThreeDAxes\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.mobject.three_d.three_dimensions import Sphere\nfrom manim.mobject.value_tracker import ValueTracker\n\nfrom .. import config\nfrom ..animation.animation import Animation\nfrom ..animation.transform import Transform\nfrom ..camera.three_d_camera import ThreeDCamera\nfrom ..constants import DEGREES, RendererType\nfrom ..mobject.mobject import Mobject\nfrom ..mobject.types.vectorized_mobject import VectorizedPoint, VGroup\nfrom ..renderer.opengl_renderer import OpenGLCamera\nfrom ..scene.scene import Scene\nfrom ..utils.config_ops import merge_dicts_recursively\n\n\nclass ThreeDScene(Scene):\n    \"\"\"\n    This is a Scene, with special configurations and properties that\n    make it suitable for Three Dimensional Scenes.\n    \"\"\"\n\n    def __init__(\n        self,\n        camera_class=ThreeDCamera,\n        ambient_camera_rotation=None,\n        default_angled_camera_orientation_kwargs=None,\n        **kwargs,\n    ):\n        self.ambient_camera_rotation = ambient_camera_rotation\n        if default_angled_camera_orientation_kwargs is None:\n            default_angled_camera_orientation_kwargs = {\n                \"phi\": 70 * DEGREES,\n                \"theta\": -135 * DEGREES,\n            }\n        self.default_angled_camera_orientation_kwargs = (\n            default_angled_camera_orientation_kwargs\n        )\n        super().__init__(camera_class=camera_class, **kwargs)\n\n    def set_camera_orientation(\n        self,\n        phi: float | None = None,\n        theta: float | None = None,\n        gamma: float | None = None,\n        zoom: float | None = None,\n        focal_distance: float | None = None,\n        frame_center: Mobject | Sequence[float] | None = None,\n        **kwargs,\n    ):\n        \"\"\"\n        This method sets the orientation of the camera in the scene.\n\n        Parameters\n        ----------\n        phi\n            The polar angle i.e the angle between Z_AXIS and Camera through ORIGIN in radians.\n\n        theta\n            The azimuthal angle i.e the angle that spins the camera around the Z_AXIS.\n\n        focal_distance\n            The focal_distance of the Camera.\n\n        gamma\n            The rotation of the camera about the vector from the ORIGIN to the Camera.\n\n        zoom\n            The zoom factor of the scene.\n\n        frame_center\n            The new center of the camera frame in cartesian coordinates.\n\n        \"\"\"\n        if phi is not None:\n            self.renderer.camera.set_phi(phi)\n        if theta is not None:\n            self.renderer.camera.set_theta(theta)\n        if focal_distance is not None:\n            self.renderer.camera.set_focal_distance(focal_distance)\n        if gamma is not None:\n            self.renderer.camera.set_gamma(gamma)\n        if zoom is not None:\n            self.renderer.camera.set_zoom(zoom)\n        if frame_center is not None:\n            self.renderer.camera._frame_center.move_to(frame_center)\n\n    def begin_ambient_camera_rotation(self, rate: float = 0.02, about: str = \"theta\"):\n        \"\"\"\n        This method begins an ambient rotation of the camera about the Z_AXIS,\n        in the anticlockwise direction\n\n        Parameters\n        ----------\n        rate\n            The rate at which the camera should rotate about the Z_AXIS.\n            Negative rate means clockwise rotation.\n        about\n            one of 3 options: [\"theta\", \"phi\", \"gamma\"]. defaults to theta.\n        \"\"\"\n        # TODO, use a ValueTracker for rate, so that it\n        # can begin and end smoothly\n        about: str = about.lower()\n        try:\n            if config.renderer == RendererType.CAIRO:\n                trackers = {\n                    \"theta\": self.camera.theta_tracker,\n                    \"phi\": self.camera.phi_tracker,\n                    \"gamma\": self.camera.gamma_tracker,\n                }\n                x: ValueTracker = trackers[about]\n                x.add_updater(lambda m, dt: x.increment_value(rate * dt))\n                self.add(x)\n            elif config.renderer == RendererType.OPENGL:\n                cam: OpenGLCamera = self.camera\n                methods = {\n                    \"theta\": cam.increment_theta,\n                    \"phi\": cam.increment_phi,\n                    \"gamma\": cam.increment_gamma,\n                }\n                cam.add_updater(lambda m, dt: methods[about](rate * dt))\n                self.add(self.camera)\n        except Exception as e:\n            raise ValueError(\"Invalid ambient rotation angle.\") from e\n\n    def stop_ambient_camera_rotation(self, about=\"theta\"):\n        \"\"\"This method stops all ambient camera rotation.\"\"\"\n        about: str = about.lower()\n        try:\n            if config.renderer == RendererType.CAIRO:\n                trackers = {\n                    \"theta\": self.camera.theta_tracker,\n                    \"phi\": self.camera.phi_tracker,\n                    \"gamma\": self.camera.gamma_tracker,\n                }\n                x: ValueTracker = trackers[about]\n                x.clear_updaters()\n                self.remove(x)\n            elif config.renderer == RendererType.OPENGL:\n                self.camera.clear_updaters()\n        except Exception as e:\n            raise ValueError(\"Invalid ambient rotation angle.\") from e\n\n    def begin_3dillusion_camera_rotation(\n        self,\n        rate: float = 1,\n        origin_phi: float | None = None,\n        origin_theta: float | None = None,\n    ):\n        \"\"\"\n        This method creates a 3D camera rotation illusion around\n        the current camera orientation.\n\n        Parameters\n        ----------\n        rate\n            The rate at which the camera rotation illusion should operate.\n        origin_phi\n            The polar angle the camera should move around. Defaults\n            to the current phi angle.\n        origin_theta\n            The azimutal angle the camera should move around. Defaults\n            to the current theta angle.\n        \"\"\"\n        if origin_theta is None:\n            origin_theta = self.renderer.camera.theta_tracker.get_value()\n        if origin_phi is None:\n            origin_phi = self.renderer.camera.phi_tracker.get_value()\n\n        val_tracker_theta = ValueTracker(0)\n\n        def update_theta(m, dt):\n            val_tracker_theta.increment_value(dt * rate)\n            val_for_left_right = 0.2 * np.sin(val_tracker_theta.get_value())\n            return m.set_value(origin_theta + val_for_left_right)\n\n        self.renderer.camera.theta_tracker.add_updater(update_theta)\n        self.add(self.renderer.camera.theta_tracker)\n\n        val_tracker_phi = ValueTracker(0)\n\n        def update_phi(m, dt):\n            val_tracker_phi.increment_value(dt * rate)\n            val_for_up_down = 0.1 * np.cos(val_tracker_phi.get_value()) - 0.1\n            return m.set_value(origin_phi + val_for_up_down)\n\n        self.renderer.camera.phi_tracker.add_updater(update_phi)\n        self.add(self.renderer.camera.phi_tracker)\n\n    def stop_3dillusion_camera_rotation(self):\n        \"\"\"This method stops all illusion camera rotations.\"\"\"\n        self.renderer.camera.theta_tracker.clear_updaters()\n        self.remove(self.renderer.camera.theta_tracker)\n        self.renderer.camera.phi_tracker.clear_updaters()\n        self.remove(self.renderer.camera.phi_tracker)\n\n    def move_camera(\n        self,\n        phi: float | None = None,\n        theta: float | None = None,\n        gamma: float | None = None,\n        zoom: float | None = None,\n        focal_distance: float | None = None,\n        frame_center: Mobject | Sequence[float] | None = None,\n        added_anims: Iterable[Animation] = [],\n        **kwargs,\n    ):\n        \"\"\"\n        This method animates the movement of the camera\n        to the given spherical coordinates.\n\n        Parameters\n        ----------\n        phi\n            The polar angle i.e the angle between Z_AXIS and Camera through ORIGIN in radians.\n\n        theta\n            The azimuthal angle i.e the angle that spins the camera around the Z_AXIS.\n\n        focal_distance\n            The radial focal_distance between ORIGIN and Camera.\n\n        gamma\n            The rotation of the camera about the vector from the ORIGIN to the Camera.\n\n        zoom\n            The zoom factor of the camera.\n\n        frame_center\n            The new center of the camera frame in cartesian coordinates.\n\n        added_anims\n            Any other animations to be played at the same time.\n\n        \"\"\"\n        anims = []\n\n        if config.renderer == RendererType.CAIRO:\n            self.camera: ThreeDCamera\n            value_tracker_pairs = [\n                (phi, self.camera.phi_tracker),\n                (theta, self.camera.theta_tracker),\n                (focal_distance, self.camera.focal_distance_tracker),\n                (gamma, self.camera.gamma_tracker),\n                (zoom, self.camera.zoom_tracker),\n            ]\n            for value, tracker in value_tracker_pairs:\n                if value is not None:\n                    anims.append(tracker.animate.set_value(value))\n            if frame_center is not None:\n                anims.append(self.camera._frame_center.animate.move_to(frame_center))\n        elif config.renderer == RendererType.OPENGL:\n            cam: OpenGLCamera = self.camera\n            cam2 = cam.copy()\n            methods = {\n                \"theta\": cam2.set_theta,\n                \"phi\": cam2.set_phi,\n                \"gamma\": cam2.set_gamma,\n                \"zoom\": cam2.scale,\n                \"frame_center\": cam2.move_to,\n            }\n            if frame_center is not None:\n                if isinstance(frame_center, OpenGLMobject):\n                    frame_center = frame_center.get_center()\n                frame_center = list(frame_center)\n\n            zoom_value = None\n            if zoom is not None:\n                zoom_value = config.frame_height / (zoom * cam.height)\n\n            for value, method in [\n                [theta, \"theta\"],\n                [phi, \"phi\"],\n                [gamma, \"gamma\"],\n                [zoom_value, \"zoom\"],\n                [frame_center, \"frame_center\"],\n            ]:\n                if value is not None:\n                    methods[method](value)\n\n            if focal_distance is not None:\n                warnings.warn(\n                    \"focal distance of OpenGLCamera can not be adjusted.\",\n                    stacklevel=2,\n                )\n\n            anims += [Transform(cam, cam2)]\n\n        self.play(*anims + added_anims, **kwargs)\n\n        # These lines are added to improve performance. If manim thinks that frame_center is moving,\n        # it is required to redraw every object. These lines remove frame_center from the Scene once\n        # its animation is done, ensuring that manim does not think that it is moving. Since the\n        # frame_center is never actually drawn, this shouldn't break anything.\n        if frame_center is not None and config.renderer == RendererType.CAIRO:\n            self.remove(self.camera._frame_center)\n\n    def get_moving_mobjects(self, *animations: Animation):\n        \"\"\"\n        This method returns a list of all of the Mobjects in the Scene that\n        are moving, that are also in the animations passed.\n\n        Parameters\n        ----------\n        *animations\n            The animations whose mobjects will be checked.\n        \"\"\"\n        moving_mobjects = super().get_moving_mobjects(*animations)\n        camera_mobjects = self.renderer.camera.get_value_trackers() + [\n            self.renderer.camera._frame_center,\n        ]\n        if any(cm in moving_mobjects for cm in camera_mobjects):\n            return self.mobjects\n        return moving_mobjects\n\n    def add_fixed_orientation_mobjects(self, *mobjects: Mobject, **kwargs):\n        \"\"\"\n        This method is used to prevent the rotation and tilting\n        of mobjects as the camera moves around. The mobject can\n        still move in the x,y,z directions, but will always be\n        at the angle (relative to the camera) that it was at\n        when it was passed through this method.)\n\n        Parameters\n        ----------\n        *mobjects\n            The Mobject(s) whose orientation must be fixed.\n\n        **kwargs\n            Some valid kwargs are\n                use_static_center_func : bool\n                center_func : function\n        \"\"\"\n        if config.renderer == RendererType.CAIRO:\n            self.add(*mobjects)\n            self.renderer.camera.add_fixed_orientation_mobjects(*mobjects, **kwargs)\n        elif config.renderer == RendererType.OPENGL:\n            for mob in mobjects:\n                mob: OpenGLMobject\n                mob.fix_orientation()\n                self.add(mob)\n\n    def add_fixed_in_frame_mobjects(self, *mobjects: Mobject):\n        \"\"\"\n        This method is used to prevent the rotation and movement\n        of mobjects as the camera moves around. The mobject is\n        essentially overlaid, and is not impacted by the camera's\n        movement in any way.\n\n        Parameters\n        ----------\n        *mobjects\n            The Mobjects whose orientation must be fixed.\n        \"\"\"\n        if config.renderer == RendererType.CAIRO:\n            self.add(*mobjects)\n            self.camera: ThreeDCamera\n            self.camera.add_fixed_in_frame_mobjects(*mobjects)\n        elif config.renderer == RendererType.OPENGL:\n            for mob in mobjects:\n                mob: OpenGLMobject\n                mob.fix_in_frame()\n                self.add(mob)\n\n    def remove_fixed_orientation_mobjects(self, *mobjects: Mobject):\n        \"\"\"\n        This method \"unfixes\" the orientation of the mobjects\n        passed, meaning they will no longer be at the same angle\n        relative to the camera. This only makes sense if the\n        mobject was passed through add_fixed_orientation_mobjects first.\n\n        Parameters\n        ----------\n        *mobjects\n            The Mobjects whose orientation must be unfixed.\n        \"\"\"\n        if config.renderer == RendererType.CAIRO:\n            self.renderer.camera.remove_fixed_orientation_mobjects(*mobjects)\n        elif config.renderer == RendererType.OPENGL:\n            for mob in mobjects:\n                mob: OpenGLMobject\n                mob.unfix_orientation()\n                self.remove(mob)\n\n    def remove_fixed_in_frame_mobjects(self, *mobjects: Mobject):\n        \"\"\"\n         This method undoes what add_fixed_in_frame_mobjects does.\n         It allows the mobject to be affected by the movement of\n         the camera.\n\n        Parameters\n        ----------\n        *mobjects\n            The Mobjects whose position and orientation must be unfixed.\n        \"\"\"\n        if config.renderer == RendererType.CAIRO:\n            self.renderer.camera.remove_fixed_in_frame_mobjects(*mobjects)\n        elif config.renderer == RendererType.OPENGL:\n            for mob in mobjects:\n                mob: OpenGLMobject\n                mob.unfix_from_frame()\n                self.remove(mob)\n\n    ##\n    def set_to_default_angled_camera_orientation(self, **kwargs):\n        \"\"\"\n        This method sets the default_angled_camera_orientation to the\n        keyword arguments passed, and sets the camera to that orientation.\n\n        Parameters\n        ----------\n        **kwargs\n            Some recognised kwargs are phi, theta, focal_distance, gamma,\n            which have the same meaning as the parameters in set_camera_orientation.\n        \"\"\"\n        config = dict(\n            self.default_camera_orientation_kwargs,\n        )  # Where doe this come from?\n        config.update(kwargs)\n        self.set_camera_orientation(**config)\n\n\nclass SpecialThreeDScene(ThreeDScene):\n    \"\"\"An extension of :class:`ThreeDScene` with more settings.\n\n    It has some extra configuration for axes, spheres,\n    and an override for low quality rendering. Further key differences\n    are:\n\n    * The camera shades applicable 3DMobjects by default,\n      except if rendering in low quality.\n    * Some default params for Spheres and Axes have been added.\n\n    \"\"\"\n\n    def __init__(\n        self,\n        cut_axes_at_radius=True,\n        camera_config={\"should_apply_shading\": True, \"exponential_projection\": True},\n        three_d_axes_config={\n            \"num_axis_pieces\": 1,\n            \"axis_config\": {\n                \"unit_size\": 2,\n                \"tick_frequency\": 1,\n                \"numbers_with_elongated_ticks\": [0, 1, 2],\n                \"stroke_width\": 2,\n            },\n        },\n        sphere_config={\"radius\": 2, \"resolution\": (24, 48)},\n        default_angled_camera_position={\n            \"phi\": 70 * DEGREES,\n            \"theta\": -110 * DEGREES,\n        },\n        # When scene is extracted with -l flag, this\n        # configuration will override the above configuration.\n        low_quality_config={\n            \"camera_config\": {\"should_apply_shading\": False},\n            \"three_d_axes_config\": {\"num_axis_pieces\": 1},\n            \"sphere_config\": {\"resolution\": (12, 24)},\n        },\n        **kwargs,\n    ):\n        self.cut_axes_at_radius = cut_axes_at_radius\n        self.camera_config = camera_config\n        self.three_d_axes_config = three_d_axes_config\n        self.sphere_config = sphere_config\n        self.default_angled_camera_position = default_angled_camera_position\n        self.low_quality_config = low_quality_config\n        if self.renderer.camera_config[\"pixel_width\"] == config[\"pixel_width\"]:\n            _config = {}\n        else:\n            _config = self.low_quality_config\n        _config = merge_dicts_recursively(_config, kwargs)\n        super().__init__(**_config)\n\n    def get_axes(self):\n        \"\"\"Return a set of 3D axes.\n\n        Returns\n        -------\n        :class:`.ThreeDAxes`\n            A set of 3D axes.\n        \"\"\"\n        axes = ThreeDAxes(**self.three_d_axes_config)\n        for axis in axes:\n            if self.cut_axes_at_radius:\n                p0 = axis.get_start()\n                p1 = axis.number_to_point(-1)\n                p2 = axis.number_to_point(1)\n                p3 = axis.get_end()\n                new_pieces = VGroup(Line(p0, p1), Line(p1, p2), Line(p2, p3))\n                for piece in new_pieces:\n                    piece.shade_in_3d = True\n                new_pieces.match_style(axis.pieces)\n                axis.pieces.submobjects = new_pieces.submobjects\n            for tick in axis.tick_marks:\n                tick.add(VectorizedPoint(1.5 * tick.get_center()))\n        return axes\n\n    def get_sphere(self, **kwargs):\n        \"\"\"\n        Returns a sphere with the passed keyword arguments as properties.\n\n        Parameters\n        ----------\n        **kwargs\n            Any valid parameter of :class:`~.Sphere` or :class:`~.Surface`.\n\n        Returns\n        -------\n        :class:`~.Sphere`\n            The sphere object.\n        \"\"\"\n        config = merge_dicts_recursively(self.sphere_config, kwargs)\n        return Sphere(**config)\n\n    def get_default_camera_position(self):\n        \"\"\"\n        Returns the default_angled_camera position.\n\n        Returns\n        -------\n        dict\n            Dictionary of phi, theta, focal_distance, and gamma.\n        \"\"\"\n        return self.default_angled_camera_position\n\n    def set_camera_to_default_position(self):\n        \"\"\"Sets the camera to its default position.\"\"\"\n        self.set_camera_orientation(**self.default_angled_camera_position)\n"
  },
  {
    "path": "manim/scene/vector_space_scene.py",
    "content": "\"\"\"A scene suitable for vector spaces.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"VectorScene\", \"LinearTransformationScene\"]\n\nfrom collections.abc import Callable, Iterable\nfrom typing import TYPE_CHECKING, Any, cast\n\nimport numpy as np\n\nfrom manim.animation.creation import DrawBorderThenFill, Group\nfrom manim.camera.camera import Camera\nfrom manim.mobject.geometry.arc import Dot\nfrom manim.mobject.geometry.line import Arrow, Line, Vector\nfrom manim.mobject.geometry.polygram import Rectangle\nfrom manim.mobject.graphing.coordinate_systems import Axes, NumberPlane\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.mobject.text.tex_mobject import MathTex, Tex\nfrom manim.utils.config_ops import update_dict_recursively\n\nfrom .. import config\nfrom ..animation.animation import Animation\nfrom ..animation.creation import Create, Write\nfrom ..animation.fading import FadeOut\nfrom ..animation.growing import GrowArrow\nfrom ..animation.transform import ApplyFunction, ApplyPointwiseFunction, Transform\nfrom ..constants import *\nfrom ..mobject.matrix import Matrix\nfrom ..mobject.mobject import Mobject\nfrom ..mobject.types.vectorized_mobject import VGroup, VMobject\nfrom ..scene.scene import Scene\nfrom ..utils.color import (\n    BLACK,\n    BLUE_D,\n    GREEN_C,\n    GREY,\n    PURE_YELLOW,\n    RED_C,\n    WHITE,\n    ManimColor,\n    ParsableManimColor,\n)\nfrom ..utils.rate_functions import rush_from, rush_into\nfrom ..utils.space_ops import angle_of_vector\n\nif TYPE_CHECKING:\n    from typing import Self\n\n    from manim.typing import (\n        MappingFunction,\n        Point3D,\n        Point3DLike,\n        Vector2DLike,\n        Vector3D,\n        Vector3DLike,\n    )\n\n\nX_COLOR = GREEN_C\nY_COLOR = RED_C\nZ_COLOR = BLUE_D\n\n\n# TODO: Much of this scene type seems dependent on the coordinate system chosen.\n# That is, being centered at the origin with grid units corresponding to the\n# arbitrary space units.  Change it!\n#\n# Also, methods I would have thought of as getters, like coords_to_vector, are\n# actually doing a lot of animating.\nclass VectorScene(Scene):\n    def __init__(self, basis_vector_stroke_width: float = 6.0, **kwargs: Any) -> None:\n        super().__init__(**kwargs)\n        self.basis_vector_stroke_width = basis_vector_stroke_width\n\n    def add_plane(self, animate: bool = False, **kwargs: Any) -> NumberPlane:\n        \"\"\"\n        Adds a NumberPlane object to the background.\n\n        Parameters\n        ----------\n        animate\n            Whether or not to animate the addition of the plane via Create.\n        **kwargs\n            Any valid keyword arguments accepted by NumberPlane.\n\n        Returns\n        -------\n        NumberPlane\n            The NumberPlane object.\n        \"\"\"\n        plane = NumberPlane(**kwargs)\n        if animate:\n            self.play(Create(plane, lag_ratio=0.5))\n        self.add(plane)\n        return plane\n\n    def add_axes(\n        self,\n        animate: bool = False,\n        color: ParsableManimColor | Iterable[ParsableManimColor] = WHITE,\n    ) -> Axes:\n        \"\"\"\n        Adds a pair of Axes to the Scene.\n\n        Parameters\n        ----------\n        animate\n            Whether or not to animate the addition of the axes through Create.\n        color\n            The color of the axes. Defaults to WHITE.\n        \"\"\"\n        axes = Axes(color=color, axis_config={\"unit_size\": 1})\n        if animate:\n            self.play(Create(axes))\n        self.add(axes)\n        return axes\n\n    def lock_in_faded_grid(\n        self, dimness: float = 0.7, axes_dimness: float = 0.5\n    ) -> None:\n        \"\"\"\n        This method freezes the NumberPlane and Axes that were already\n        in the background, and adds new, manipulatable ones to the foreground.\n\n        Parameters\n        ----------\n        dimness\n            The required dimness of the NumberPlane\n\n        axes_dimness\n            The required dimness of the Axes.\n        \"\"\"\n        plane = self.add_plane()\n        axes = plane.get_axes()\n        plane.fade(dimness)\n        axes.set_color(WHITE)\n        axes.fade(axes_dimness)\n        self.add(axes)\n\n        # TODO\n        # error: Missing positional argument \"scene\" in call to \"update_frame\" of \"CairoRenderer\"  [call-arg]\n        self.renderer.update_frame()  # type: ignore[call-arg]\n        self.renderer.camera = Camera(self.renderer.get_frame())\n        self.clear()\n\n    def get_vector(self, numerical_vector: Vector3DLike, **kwargs: Any) -> Arrow:\n        \"\"\"\n        Returns an arrow on the Plane given an input numerical vector.\n\n        Parameters\n        ----------\n        numerical_vector\n            The Vector to plot.\n        **kwargs\n            Any valid keyword argument of Arrow.\n\n        Returns\n        -------\n        Arrow\n            The Arrow representing the Vector.\n        \"\"\"\n        return Arrow(\n            # TODO\n            # error: \"VectorScene\" has no attribute \"plane\"  [attr-defined]\n            self.plane.coords_to_point(0, 0),  # type: ignore[attr-defined]\n            self.plane.coords_to_point(*numerical_vector[:2]),  # type: ignore[attr-defined]\n            buff=0,\n            **kwargs,\n        )\n\n    def add_vector(\n        self,\n        vector: Arrow | Vector3DLike,\n        color: ParsableManimColor | Iterable[ParsableManimColor] = PURE_YELLOW,\n        animate: bool = True,\n        **kwargs: Any,\n    ) -> Arrow:\n        \"\"\"\n        Returns the Vector after adding it to the Plane.\n\n        Parameters\n        ----------\n        vector\n            It can be a pre-made graphical vector, or the\n            coordinates of one.\n\n        color\n            The string of the hex color of the vector.\n            This is only taken into consideration if\n            'vector' is not an Arrow. Defaults to YELLOW.\n\n        animate\n            Whether or not to animate the addition of the vector\n            by using GrowArrow\n\n        **kwargs\n            Any valid keyword argument of Arrow.\n            These are only considered if vector is not\n            an Arrow.\n\n        Returns\n        -------\n        Arrow\n            The arrow representing the vector.\n        \"\"\"\n        if not isinstance(vector, Arrow):\n            vector = Vector(np.asarray(vector), color=color, **kwargs)\n        if animate:\n            self.play(GrowArrow(vector))\n        self.add(vector)\n        return vector\n\n    def write_vector_coordinates(self, vector: Vector, **kwargs: Any) -> Matrix:\n        \"\"\"\n        Returns a column matrix indicating the vector coordinates,\n        after writing them to the screen.\n\n        Parameters\n        ----------\n        vector\n            The arrow representing the vector.\n\n        **kwargs\n            Any valid keyword arguments of :meth:`~.Vector.coordinate_label`:\n\n        Returns\n        -------\n        :class:`.Matrix`\n            The column matrix representing the vector.\n        \"\"\"\n        coords: Matrix = vector.coordinate_label(**kwargs)\n        self.play(Write(coords))\n        return coords\n\n    def get_basis_vectors(\n        self,\n        i_hat_color: ParsableManimColor | Iterable[ParsableManimColor] = X_COLOR,\n        j_hat_color: ParsableManimColor | Iterable[ParsableManimColor] = Y_COLOR,\n    ) -> VGroup:\n        \"\"\"\n        Returns a VGroup of the Basis Vectors (1,0) and (0,1)\n\n        Parameters\n        ----------\n        i_hat_color\n            The hex colour to use for the basis vector in the x direction\n\n        j_hat_color\n            The hex colour to use for the basis vector in the y direction\n\n        Returns\n        -------\n        VGroup\n            VGroup of the Vector Mobjects representing the basis vectors.\n        \"\"\"\n        return VGroup(\n            *(\n                Vector(\n                    np.asarray(vect),\n                    color=color,\n                    stroke_width=self.basis_vector_stroke_width,\n                )\n                for vect, color in [([1, 0], i_hat_color), ([0, 1], j_hat_color)]\n            )\n        )\n\n    def get_basis_vector_labels(self, **kwargs: Any) -> VGroup:\n        \"\"\"\n        Returns naming labels for the basis vectors.\n\n        Parameters\n        ----------\n        **kwargs\n            Any valid keyword arguments of get_vector_label:\n                vector,\n                label (str,MathTex)\n                at_tip (bool=False),\n                direction (str=\"left\"),\n                rotate (bool),\n                color (str),\n                label_scale_factor=VECTOR_LABEL_SCALE_FACTOR (int, float),\n        \"\"\"\n        i_hat = self.get_basis_vectors().submobjects[0]\n        j_hat = self.get_basis_vectors().submobjects[1]\n        return VGroup(\n            *(\n                self.get_vector_label(\n                    vect, label, color=color, label_scale_factor=1, **kwargs\n                )\n                for vect, label, color in [\n                    # Casting i_hat and j_hat to Vector, as the VGroup from\n                    # self.get_basis_vectors() contains two vectors, but the\n                    # type checker is currently not aware of that.\n                    (cast(Vector, i_hat), \"\\\\hat{\\\\imath}\", X_COLOR),\n                    (cast(Vector, j_hat), \"\\\\hat{\\\\jmath}\", Y_COLOR),\n                ]\n            )\n        )\n\n    def get_vector_label(\n        self,\n        vector: Vector,\n        label: MathTex | str,\n        at_tip: bool = False,\n        direction: str = \"left\",\n        rotate: bool = False,\n        color: ParsableManimColor | None = None,\n        label_scale_factor: float = LARGE_BUFF - 0.2,\n    ) -> MathTex:\n        \"\"\"\n        Returns naming labels for the passed vector.\n\n        Parameters\n        ----------\n        vector\n            Vector Object for which to get the label.\n\n        at_tip\n            Whether or not to place the label at the tip of the vector.\n\n        direction\n            If the label should be on the \"left\" or right of the vector.\n        rotate\n            Whether or not to rotate it to align it with the vector.\n        color\n            The color to give the label.\n        label_scale_factor\n            How much to scale the label by.\n\n        Returns\n        -------\n        MathTex\n            The MathTex of the label.\n        \"\"\"\n        if not isinstance(label, MathTex):\n            if len(label) == 1:\n                label = \"\\\\vec{\\\\textbf{%s}}\" % label  # noqa: UP031\n            label = MathTex(label)\n            if color is None:\n                prepared_color: ParsableManimColor = vector.get_color()\n            else:\n                prepared_color = color\n            label.set_color(prepared_color)\n        assert isinstance(label, MathTex)\n        label.scale(label_scale_factor)\n        label.add_background_rectangle()\n\n        if at_tip:\n            vect = vector.get_vector()\n            vect /= np.linalg.norm(vect)\n            label.next_to(vector.get_end(), vect, buff=SMALL_BUFF)\n        else:\n            angle = vector.get_angle()\n            if not rotate:\n                label.rotate(-angle, about_point=ORIGIN)\n            if direction == \"left\":\n                temp_shift_1: Vector3D = np.asarray(label.get_bottom())\n                label.shift(-temp_shift_1 + 0.1 * UP)\n            else:\n                temp_shift_2: Vector3D = np.asarray(label.get_top())\n                label.shift(-temp_shift_2 + 0.1 * DOWN)\n            label.rotate(angle, about_point=ORIGIN)\n            label.shift((vector.get_end() - vector.get_start()) / 2)\n        return label\n\n    def label_vector(\n        self, vector: Vector, label: MathTex | str, animate: bool = True, **kwargs: Any\n    ) -> MathTex:\n        \"\"\"\n        Shortcut method for creating, and animating the addition of\n        a label for the vector.\n\n        Parameters\n        ----------\n        vector\n            The vector for which the label must be added.\n\n        label\n            The MathTex/string of the label.\n\n        animate\n            Whether or not to animate the labelling w/ Write\n\n        **kwargs\n            Any valid keyword argument of get_vector_label\n\n        Returns\n        -------\n        :class:`~.MathTex`\n            The MathTex of the label.\n        \"\"\"\n        mathtex_label = self.get_vector_label(vector, label, **kwargs)\n        if animate:\n            self.play(Write(mathtex_label, run_time=1))\n        self.add(mathtex_label)\n        return mathtex_label\n\n    def position_x_coordinate(\n        self,\n        x_coord: MathTex,\n        x_line: Line,\n        vector: Vector3DLike,\n    ) -> MathTex:  # TODO Write DocStrings for this.\n        x_coord.next_to(x_line, -np.sign(vector[1]) * UP)\n        x_coord.set_color(X_COLOR)\n        return x_coord\n\n    def position_y_coordinate(\n        self,\n        y_coord: MathTex,\n        y_line: Line,\n        vector: Vector3DLike,\n    ) -> MathTex:  # TODO Write DocStrings for this.\n        y_coord.next_to(y_line, np.sign(vector[0]) * RIGHT)\n        y_coord.set_color(Y_COLOR)\n        return y_coord\n\n    def coords_to_vector(\n        self,\n        vector: Vector2DLike,\n        coords_start: Point3DLike = 2 * RIGHT + 2 * UP,\n        clean_up: bool = True,\n    ) -> None:\n        \"\"\"\n        This method writes the vector as a column matrix (henceforth called the label),\n        takes the values in it one by one, and form the corresponding\n        lines that make up the x and y components of the vector. Then, an\n        Vector() based vector is created between the lines on the Screen.\n\n        Parameters\n        ----------\n        vector\n            The vector to show.\n\n        coords_start\n            The starting point of the location of\n            the label of the vector that shows it\n            numerically.\n            Defaults to 2 * RIGHT + 2 * UP or (2,2)\n\n        clean_up\n            Whether or not to remove whatever\n            this method did after it's done.\n\n        \"\"\"\n        starting_mobjects = list(self.mobjects)\n        array = Matrix(vector)\n        array.shift(coords_start)\n        arrow = Vector(vector)\n        x_line = Line(ORIGIN, vector[0] * RIGHT)\n        y_line = Line(x_line.get_end(), arrow.get_end())\n        x_line.set_color(X_COLOR)\n        y_line.set_color(Y_COLOR)\n        mob_matrix = array.get_mob_matrix()\n        x_coord = mob_matrix[0][0]\n        y_coord = mob_matrix[1][0]\n\n        self.play(Write(array, run_time=1))\n        self.wait()\n        self.play(\n            ApplyFunction(\n                lambda x: self.position_x_coordinate(x, x_line, vector),  # type: ignore[arg-type]\n                x_coord,\n            ),\n        )\n        self.play(Create(x_line))\n        animations = [\n            ApplyFunction(\n                lambda y: self.position_y_coordinate(y, y_line, vector),  # type: ignore[arg-type]\n                y_coord,\n            ),\n            FadeOut(array.get_brackets()),\n        ]\n        self.play(*animations)\n        # TODO: Can we delete the line below? I don't think it have any purpose.\n        # y_coord, _ = (anim.mobject for anim in animations)\n        self.play(Create(y_line))\n        self.play(Create(arrow))\n        self.wait()\n        if clean_up:\n            self.clear()\n            self.add(*starting_mobjects)\n\n    def vector_to_coords(\n        self,\n        vector: Vector3DLike,\n        integer_labels: bool = True,\n        clean_up: bool = True,\n    ) -> tuple[Matrix, Line, Line]:\n        \"\"\"\n        This method displays vector as a Vector() based vector, and then shows\n        the corresponding lines that make up the x and y components of the vector.\n        Then, a column matrix (henceforth called the label) is created near the\n        head of the Vector.\n\n        Parameters\n        ----------\n        vector\n            The vector to show.\n\n        integer_labels\n            Whether or not to round the value displayed.\n            in the vector's label to the nearest integer\n\n        clean_up\n            Whether or not to remove whatever\n            this method did after it's done.\n\n        \"\"\"\n        starting_mobjects = list(self.mobjects)\n        show_creation = False\n        if isinstance(vector, Arrow):\n            arrow = vector\n            vector = arrow.get_end()[:2]\n        else:\n            arrow = Vector(vector)\n            show_creation = True\n        array = arrow.coordinate_label(integer_labels=integer_labels)\n        x_line = Line(ORIGIN, vector[0] * RIGHT)\n        y_line = Line(x_line.get_end(), arrow.get_end())\n        x_line.set_color(X_COLOR)\n        y_line.set_color(Y_COLOR)\n        temp = array.get_entries()\n        x_coord = temp.submobjects[0]\n        y_coord = temp.submobjects[1]\n        x_coord_start = self.position_x_coordinate(x_coord.copy(), x_line, vector)\n        y_coord_start = self.position_y_coordinate(y_coord.copy(), y_line, vector)\n        brackets = array.get_brackets()\n\n        if show_creation:\n            self.play(Create(arrow))\n        self.play(Create(x_line), Write(x_coord_start), run_time=1)\n        self.play(Create(y_line), Write(y_coord_start), run_time=1)\n        self.wait()\n        self.play(\n            Transform(x_coord_start, x_coord, lag_ratio=0),\n            Transform(y_coord_start, y_coord, lag_ratio=0),\n            Write(brackets, run_time=1),\n        )\n        self.wait()\n\n        self.remove(x_coord_start, y_coord_start, brackets)\n        self.add(array)\n        if clean_up:\n            self.clear()\n            self.add(*starting_mobjects)\n        return array, x_line, y_line\n\n    def show_ghost_movement(self, vector: Arrow | Vector2DLike | Vector3DLike) -> None:\n        \"\"\"\n        This method plays an animation that partially shows the entire plane moving\n        in the direction of a particular vector. This is useful when you wish to\n        convey the idea of mentally moving the entire plane in a direction, without\n        actually moving the plane.\n\n        Parameters\n        ----------\n        vector\n            The vector which indicates the direction of movement.\n        \"\"\"\n        if isinstance(vector, Arrow):\n            vector = vector.get_end() - vector.get_start()\n        else:\n            vector = np.asarray(vector)\n            if len(vector) == 2:\n                vector = np.append(np.array(vector), 0.0)\n        vector_cleaned: Vector3D = vector\n\n        x_max = int(config[\"frame_x_radius\"] + abs(vector_cleaned[0]))\n        y_max = int(config[\"frame_y_radius\"] + abs(vector_cleaned[1]))\n        # TODO:\n        # I think that this should be a VGroup instead of a VMobject.\n        dots = VMobject(\n            *(  # type: ignore[arg-type]\n                Dot(x * RIGHT + y * UP)\n                for x in range(-x_max, x_max)\n                for y in range(-y_max, y_max)\n            )\n        )\n        dots.set_fill(BLACK, opacity=0)\n        dots_halfway = dots.copy().shift(vector_cleaned / 2).set_fill(WHITE, 1)\n        dots_end = dots.copy().shift(vector_cleaned)\n\n        self.play(Transform(dots, dots_halfway, rate_func=rush_into))\n        self.play(Transform(dots, dots_end, rate_func=rush_from))\n        self.remove(dots)\n\n\nclass LinearTransformationScene(VectorScene):\n    \"\"\"\n    This scene contains special methods that make it\n    especially suitable for showing linear transformations.\n\n    Parameters\n    ----------\n    include_background_plane\n        Whether or not to include the background plane in the scene.\n    include_foreground_plane\n        Whether or not to include the foreground plane in the scene.\n    background_plane_kwargs\n        Parameters to be passed to :class:`NumberPlane` to adjust the background plane.\n    foreground_plane_kwargs\n        Parameters to be passed to :class:`NumberPlane` to adjust the foreground plane.\n    show_coordinates\n        Whether or not to include the coordinates for the background plane.\n    show_basis_vectors\n        Whether to show the basis x_axis -> ``i_hat`` and y_axis -> ``j_hat`` vectors.\n    basis_vector_stroke_width\n        The ``stroke_width`` of the basis vectors.\n    i_hat_color\n        The color of the ``i_hat`` vector.\n    j_hat_color\n        The color of the ``j_hat`` vector.\n    leave_ghost_vectors\n        Indicates the previous position of the basis vectors following a transformation.\n\n    Examples\n    -------\n\n    .. manim:: LinearTransformationSceneExample\n\n        class LinearTransformationSceneExample(LinearTransformationScene):\n            def __init__(self, **kwargs):\n                LinearTransformationScene.__init__(\n                    self,\n                    show_coordinates=True,\n                    leave_ghost_vectors=True,\n                    **kwargs\n                )\n\n            def construct(self):\n                matrix = [[1, 1], [0, 1]]\n                self.apply_matrix(matrix)\n                self.wait()\n    \"\"\"\n\n    def __init__(\n        self,\n        include_background_plane: bool = True,\n        include_foreground_plane: bool = True,\n        background_plane_kwargs: dict[str, Any] | None = None,\n        foreground_plane_kwargs: dict[str, Any] | None = None,\n        show_coordinates: bool = False,\n        show_basis_vectors: bool = True,\n        basis_vector_stroke_width: float = 6,\n        i_hat_color: ParsableManimColor = X_COLOR,\n        j_hat_color: ParsableManimColor = Y_COLOR,\n        leave_ghost_vectors: bool = False,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(**kwargs)\n\n        self.include_background_plane = include_background_plane\n        self.include_foreground_plane = include_foreground_plane\n        self.show_coordinates = show_coordinates\n        self.show_basis_vectors = show_basis_vectors\n        self.basis_vector_stroke_width = basis_vector_stroke_width\n        self.i_hat_color = ManimColor(i_hat_color)\n        self.j_hat_color = ManimColor(j_hat_color)\n        self.leave_ghost_vectors = leave_ghost_vectors\n        self.background_plane_kwargs: dict[str, Any] = {\n            \"color\": GREY,\n            \"axis_config\": {\n                \"color\": GREY,\n            },\n            \"background_line_style\": {\n                \"stroke_color\": GREY,\n                \"stroke_width\": 1,\n            },\n        }\n\n        self.ghost_vectors = VGroup()\n\n        self.foreground_plane_kwargs: dict[str, Any] = {\n            \"x_range\": np.array([-config[\"frame_width\"], config[\"frame_width\"], 1.0]),\n            \"y_range\": np.array([-config[\"frame_width\"], config[\"frame_width\"], 1.0]),\n            \"faded_line_ratio\": 1,\n        }\n\n        self.update_default_configs(\n            (self.foreground_plane_kwargs, self.background_plane_kwargs),\n            (foreground_plane_kwargs, background_plane_kwargs),\n        )\n\n    @staticmethod\n    def update_default_configs(\n        default_configs: Iterable[dict[str, Any]],\n        passed_configs: Iterable[dict[str, Any] | None],\n    ) -> None:\n        for default_config, passed_config in zip(\n            default_configs, passed_configs, strict=False\n        ):\n            if passed_config is not None:\n                update_dict_recursively(default_config, passed_config)\n\n    def setup(self) -> None:\n        # The has_already_setup attr is to not break all the old Scenes\n        if hasattr(self, \"has_already_setup\"):\n            return\n        self.has_already_setup = True\n        self.background_mobjects: list[Mobject] = []\n        self.foreground_mobjects: list[Mobject] = []\n        self.transformable_mobjects: list[Mobject] = []\n        self.moving_vectors: list[Mobject] = []\n        self.transformable_labels: list[MathTex] = []\n        self.moving_mobjects: list[Mobject] = []\n\n        self.background_plane = NumberPlane(**self.background_plane_kwargs)\n\n        if self.show_coordinates:\n            self.background_plane.add_coordinates()\n        if self.include_background_plane:\n            self.add_background_mobject(self.background_plane)\n        if self.include_foreground_plane:\n            self.plane = NumberPlane(**self.foreground_plane_kwargs)\n            self.add_transformable_mobject(self.plane)\n        if self.show_basis_vectors:\n            self.basis_vectors = self.get_basis_vectors(\n                i_hat_color=self.i_hat_color,\n                j_hat_color=self.j_hat_color,\n            )\n            self.moving_vectors += list(self.basis_vectors)\n            self.i_hat, self.j_hat = self.basis_vectors\n            self.add(self.basis_vectors)\n\n    def add_special_mobjects(\n        self, mob_list: list[Mobject], *mobs_to_add: Mobject\n    ) -> None:\n        \"\"\"\n        Adds mobjects to a separate list that can be tracked,\n        if these mobjects have some extra importance.\n\n        Parameters\n        ----------\n        mob_list\n            The special list to which you want to add\n            these mobjects.\n\n        *mobs_to_add\n            The mobjects to add.\n\n        \"\"\"\n        for mobject in mobs_to_add:\n            if mobject not in mob_list:\n                mob_list.append(mobject)\n                self.add(mobject)\n\n    def add_background_mobject(self, *mobjects: Mobject) -> None:\n        \"\"\"\n        Adds the mobjects to the special list\n        self.background_mobjects.\n\n        Parameters\n        ----------\n        *mobjects\n            The mobjects to add to the list.\n        \"\"\"\n        self.add_special_mobjects(self.background_mobjects, *mobjects)\n\n    # TODO, this conflicts with Scene.add_foreground_mobject\n    # Please be aware that there is also the method Scene.add_foreground_mobjects.\n    def add_foreground_mobject(self, *mobjects: Mobject) -> None:  # type: ignore[override]\n        \"\"\"\n        Adds the mobjects to the special list\n        self.foreground_mobjects.\n\n        Parameters\n        ----------\n        *mobjects\n            The mobjects to add to the list\n        \"\"\"\n        self.add_special_mobjects(self.foreground_mobjects, *mobjects)\n\n    def add_transformable_mobject(self, *mobjects: Mobject) -> None:\n        \"\"\"\n        Adds the mobjects to the special list\n        self.transformable_mobjects.\n\n        Parameters\n        ----------\n        *mobjects\n            The mobjects to add to the list.\n        \"\"\"\n        self.add_special_mobjects(self.transformable_mobjects, *mobjects)\n\n    def add_moving_mobject(\n        self, mobject: Mobject, target_mobject: Mobject | None = None\n    ) -> None:\n        \"\"\"\n        Adds the mobject to the special list\n        self.moving_mobject, and adds a property\n        to the mobject called mobject.target, which\n        keeps track of what the mobject will move to\n        or become etc.\n\n        Parameters\n        ----------\n        mobject\n            The mobjects to add to the list\n\n        target_mobject\n            What the moving_mobject goes to, etc.\n        \"\"\"\n        mobject.target = target_mobject\n        self.add_special_mobjects(self.moving_mobjects, mobject)\n\n    def get_ghost_vectors(self) -> VGroup:\n        \"\"\"\n        Returns all ghost vectors ever added to ``self``. Each element is a ``VGroup`` of\n        two ghost vectors.\n        \"\"\"\n        return self.ghost_vectors\n\n    def get_unit_square(\n        self,\n        color: ParsableManimColor | Iterable[ParsableManimColor] = PURE_YELLOW,\n        opacity: float = 0.3,\n        stroke_width: float = 3,\n    ) -> Rectangle:\n        \"\"\"\n        Returns a unit square for the current NumberPlane.\n\n        Parameters\n        ----------\n        color\n            The string of the hex color code of the color wanted.\n\n        opacity\n            The opacity of the square\n\n        stroke_width\n            The stroke_width in pixels of the border of the square\n\n        Returns\n        -------\n        Square\n        \"\"\"\n        square = self.square = Rectangle(\n            color=color,\n            width=self.plane.get_x_unit_size(),\n            height=self.plane.get_y_unit_size(),\n            stroke_color=color,\n            stroke_width=stroke_width,\n            fill_color=color,\n            fill_opacity=opacity,\n        )\n        square.move_to(self.plane.coords_to_point(0, 0), DL)\n        return square\n\n    def add_unit_square(self, animate: bool = False, **kwargs: Any) -> Self:\n        \"\"\"\n        Adds a unit square to the scene via\n        self.get_unit_square.\n\n        Parameters\n        ----------\n        animate\n            Whether or not to animate the addition\n            with DrawBorderThenFill.\n        **kwargs\n            Any valid keyword arguments of\n            self.get_unit_square()\n\n        Returns\n        -------\n        Square\n            The unit square.\n        \"\"\"\n        square = self.get_unit_square(**kwargs)\n        if animate:\n            self.play(\n                DrawBorderThenFill(square),\n                Animation(Group(*self.moving_vectors)),\n            )\n        self.add_transformable_mobject(square)\n        self.bring_to_front(*self.moving_vectors)\n        self.square = square\n        return self\n\n    def add_vector(\n        self,\n        vector: Arrow | list | tuple | np.ndarray,\n        color: ParsableManimColor = PURE_YELLOW,\n        animate: bool = False,\n        **kwargs: Any,\n    ) -> Arrow:\n        \"\"\"\n        Adds a vector to the scene, and puts it in the special\n        list self.moving_vectors.\n\n        Parameters\n        ----------\n        vector\n            It can be a pre-made graphical vector, or the\n            coordinates of one.\n\n        color\n            The string of the hex color of the vector.\n            This is only taken into consideration if\n            'vector' is not an Arrow. Defaults to YELLOW.\n\n        **kwargs\n            Any valid keyword argument of VectorScene.add_vector.\n\n        Returns\n        -------\n        Arrow\n            The arrow representing the vector.\n        \"\"\"\n        vector = super().add_vector(vector, color=color, animate=animate, **kwargs)\n        self.moving_vectors.append(vector)\n        return vector\n\n    def write_vector_coordinates(self, vector: Vector, **kwargs: Any) -> Matrix:\n        \"\"\"\n        Returns a column matrix indicating the vector coordinates,\n        after writing them to the screen, and adding them to the\n        special list self.foreground_mobjects\n\n        Parameters\n        ----------\n        vector\n            The arrow representing the vector.\n\n        **kwargs\n            Any valid keyword arguments of VectorScene.write_vector_coordinates\n\n        Returns\n        -------\n        Matrix\n            The column matrix representing the vector.\n        \"\"\"\n        coords = super().write_vector_coordinates(vector, **kwargs)\n        self.add_foreground_mobject(coords)\n        return coords\n\n    def add_transformable_label(\n        self,\n        vector: Vector,\n        label: MathTex | str,\n        transformation_name: str | MathTex = \"L\",\n        new_label: str | MathTex | None = None,\n        **kwargs: Any,\n    ) -> MathTex:\n        \"\"\"\n        Method for creating, and animating the addition of\n        a transformable label for the vector.\n\n        Parameters\n        ----------\n        vector\n            The vector for which the label must be added.\n\n        label\n            The MathTex/string of the label.\n\n        transformation_name\n            The name to give the transformation as a label.\n\n        new_label\n            What the label should display after a Linear Transformation\n\n        **kwargs\n            Any valid keyword argument of get_vector_label\n\n        Returns\n        -------\n        :class:`~.MathTex`\n            The MathTex of the label.\n        \"\"\"\n        # TODO: Clear up types in this function. This is currently a mess.\n        label_mob = self.label_vector(vector, label, **kwargs)\n        if new_label:\n            label_mob.target_text = new_label  # type: ignore[attr-defined]\n        else:\n            label_mob.target_text = (  # type: ignore[attr-defined]\n                f\"{transformation_name}({label_mob.get_tex_string()})\"\n            )\n        label_mob.vector = vector  # type: ignore[attr-defined]\n        label_mob.kwargs = kwargs  # type: ignore[attr-defined]\n        if \"animate\" in label_mob.kwargs:\n            label_mob.kwargs.pop(\"animate\")\n        self.transformable_labels.append(label_mob)\n        return cast(MathTex, label_mob)\n\n    def add_title(\n        self,\n        title: str | MathTex | Tex,\n        scale_factor: float = 1.5,\n        animate: bool = False,\n    ) -> Self:\n        \"\"\"\n        Adds a title, after scaling it, adding a background rectangle,\n        moving it to the top and adding it to foreground_mobjects adding\n        it as a local variable of self. Returns the Scene.\n\n        Parameters\n        ----------\n        title\n            What the title should be.\n\n        scale_factor\n            How much the title should be scaled by.\n\n        animate\n            Whether or not to animate the addition.\n\n        Returns\n        -------\n        LinearTransformationScene\n            The scene with the title added to it.\n        \"\"\"\n        if not isinstance(title, (Mobject, OpenGLMobject)):\n            title = Tex(title).scale(scale_factor)\n        title.to_edge(UP)\n        title.add_background_rectangle()\n        if animate:\n            self.play(Write(title))\n        self.add_foreground_mobject(title)\n        self.title = title\n        return self\n\n    def get_matrix_transformation(\n        self, matrix: np.ndarray | list | tuple\n    ) -> Callable[[Point3D], Point3D]:\n        \"\"\"\n        Returns a function corresponding to the linear\n        transformation represented by the matrix passed.\n\n        Parameters\n        ----------\n        matrix\n            The matrix.\n        \"\"\"\n        return self.get_transposed_matrix_transformation(np.array(matrix).T)\n\n    def get_transposed_matrix_transformation(\n        self, transposed_matrix: np.ndarray | list | tuple\n    ) -> Callable[[Point3D], Point3D]:\n        \"\"\"\n        Returns a function corresponding to the linear\n        transformation represented by the transposed\n        matrix passed.\n\n        Parameters\n        ----------\n        transposed_matrix\n            The matrix.\n        \"\"\"\n        transposed_matrix = np.array(transposed_matrix)\n        if transposed_matrix.shape == (2, 2):\n            new_matrix = np.identity(3)\n            new_matrix[:2, :2] = transposed_matrix\n            transposed_matrix = new_matrix\n        elif transposed_matrix.shape != (3, 3):\n            raise ValueError(\"Matrix has bad dimensions\")\n        return lambda point: np.dot(point, transposed_matrix)\n\n    def get_piece_movement(self, pieces: Iterable[Mobject]) -> Transform:\n        \"\"\"\n        This method returns an animation that moves an arbitrary\n        mobject in \"pieces\" to its corresponding .target value.\n        If self.leave_ghost_vectors is True, ghosts of the original\n        positions/mobjects are left on screen\n\n        Parameters\n        ----------\n        pieces\n            The pieces for which the movement must be shown.\n\n        Returns\n        -------\n        Animation\n            The animation of the movement.\n        \"\"\"\n        v_pieces = [piece for piece in pieces if isinstance(piece, VMobject)]\n        start = VGroup(*v_pieces)\n        target = VGroup(*(mob.target for mob in v_pieces))\n\n        # don't add empty VGroups\n        if self.leave_ghost_vectors and start.submobjects:\n            # start.copy() gives a VGroup of Vectors\n            self.ghost_vectors.add(start.copy().fade(0.7))\n            self.add(self.ghost_vectors[-1])\n        return Transform(start, target, lag_ratio=0)\n\n    def get_moving_mobject_movement(self, func: MappingFunction) -> Transform:\n        \"\"\"\n        This method returns an animation that moves a mobject\n        in \"self.moving_mobjects\"  to its corresponding .target value.\n        func is a function that determines where the .target goes.\n\n        Parameters\n        ----------\n\n        func\n            The function that determines where the .target of\n            the moving mobject goes.\n\n        Returns\n        -------\n        Animation\n            The animation of the movement.\n        \"\"\"\n        for m in self.moving_mobjects:\n            if m.target is None:\n                m.target = m.copy()\n            temp: Point3D = m.get_center()\n            target_point = func(temp)\n            m.target.move_to(target_point)\n        return self.get_piece_movement(self.moving_mobjects)\n\n    def get_vector_movement(self, func: MappingFunction) -> Transform:\n        \"\"\"\n        This method returns an animation that moves a mobject\n        in \"self.moving_vectors\"  to its corresponding .target value.\n        func is a function that determines where the .target goes.\n\n        Parameters\n        ----------\n\n        func\n            The function that determines where the .target of\n            the moving mobject goes.\n\n        Returns\n        -------\n        Animation\n            The animation of the movement.\n        \"\"\"\n        for v in self.moving_vectors:\n            v.target = Vector(func(v.get_end()), color=v.get_color())\n            norm = float(np.linalg.norm(v.target.get_end()))\n            if norm < 0.1:\n                v.target.get_tip().scale(norm)\n        return self.get_piece_movement(self.moving_vectors)\n\n    def get_transformable_label_movement(self) -> Transform:\n        \"\"\"\n        This method returns an animation that moves all labels\n        in \"self.transformable_labels\" to its corresponding .target .\n\n        Returns\n        -------\n        Animation\n            The animation of the movement.\n        \"\"\"\n        for label in self.transformable_labels:\n            # TODO: This location and lines 933 and 335 are the only locations in\n            # the code where the target_text property is referenced.\n            target_text: MathTex | str = label.target_text  # type: ignore[assignment]\n            label.target = self.get_vector_label(\n                label.vector.target,  # type: ignore[attr-defined]\n                target_text,\n                **label.kwargs,  # type: ignore[arg-type]\n            )\n        return self.get_piece_movement(self.transformable_labels)\n\n    def apply_matrix(self, matrix: np.ndarray | list | tuple, **kwargs: Any) -> None:\n        \"\"\"\n        Applies the transformation represented by the\n        given matrix to the number plane, and each vector/similar\n        mobject on it.\n\n        Parameters\n        ----------\n        matrix\n            The matrix.\n        **kwargs\n            Any valid keyword argument of self.apply_transposed_matrix()\n        \"\"\"\n        self.apply_transposed_matrix(np.array(matrix).T, **kwargs)\n\n    def apply_inverse(self, matrix: np.ndarray | list | tuple, **kwargs: Any) -> None:\n        \"\"\"\n        This method applies the linear transformation\n        represented by the inverse of the passed matrix\n        to the number plane, and each vector/similar mobject on it.\n\n        Parameters\n        ----------\n        matrix\n            The matrix whose inverse is to be applied.\n        **kwargs\n            Any valid keyword argument of self.apply_matrix()\n        \"\"\"\n        self.apply_matrix(np.linalg.inv(matrix), **kwargs)\n\n    def apply_transposed_matrix(\n        self, transposed_matrix: np.ndarray | list | tuple, **kwargs: Any\n    ) -> None:\n        \"\"\"\n        Applies the transformation represented by the\n        given transposed matrix to the number plane,\n        and each vector/similar mobject on it.\n\n        Parameters\n        ----------\n        transposed_matrix\n            The matrix.\n        **kwargs\n            Any valid keyword argument of self.apply_function()\n        \"\"\"\n        func = self.get_transposed_matrix_transformation(transposed_matrix)\n        if \"path_arc\" not in kwargs:\n            net_rotation = np.mean(\n                [angle_of_vector(func(RIGHT)), angle_of_vector(func(UP)) - np.pi / 2],\n            )\n            kwargs[\"path_arc\"] = net_rotation\n        self.apply_function(func, **kwargs)\n\n    def apply_inverse_transpose(\n        self, t_matrix: np.ndarray | list | tuple, **kwargs: Any\n    ) -> None:\n        \"\"\"\n        Applies the inverse of the transformation represented\n        by the given transposed matrix to the number plane and each\n        vector/similar mobject on it.\n\n        Parameters\n        ----------\n        t_matrix\n            The matrix.\n        **kwargs\n            Any valid keyword argument of self.apply_transposed_matrix()\n        \"\"\"\n        t_inv = np.linalg.inv(np.array(t_matrix).T).T\n        self.apply_transposed_matrix(t_inv, **kwargs)\n\n    def apply_nonlinear_transformation(\n        self, function: Callable[[np.ndarray], np.ndarray], **kwargs: Any\n    ) -> None:\n        \"\"\"\n        Applies the non-linear transformation represented\n        by the given function to the number plane and each\n        vector/similar mobject on it.\n\n        Parameters\n        ----------\n        function\n            The function.\n        **kwargs\n            Any valid keyword argument of self.apply_function()\n        \"\"\"\n        self.plane.prepare_for_nonlinear_transform()\n        self.apply_function(function, **kwargs)\n\n    def apply_function(\n        self,\n        function: MappingFunction,\n        added_anims: list[Animation] = [],\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Applies the given function to each of the mobjects in\n        self.transformable_mobjects, and plays the animation showing\n        this.\n\n        Parameters\n        ----------\n        function\n            The function that affects each point\n            of each mobject in self.transformable_mobjects.\n\n        added_anims\n            Any other animations that need to be played\n            simultaneously with this.\n\n        **kwargs\n            Any valid keyword argument of a self.play() call.\n        \"\"\"\n        if \"run_time\" not in kwargs:\n            kwargs[\"run_time\"] = 3\n        anims = (\n            [\n                ApplyPointwiseFunction(function, t_mob)  # type: ignore[arg-type]\n                for t_mob in self.transformable_mobjects\n            ]\n            + [\n                self.get_vector_movement(function),\n                self.get_transformable_label_movement(),\n                self.get_moving_mobject_movement(function),\n            ]\n            + [Animation(f_mob) for f_mob in self.foreground_mobjects]\n            + added_anims\n        )\n        self.play(*anims, **kwargs)\n"
  },
  {
    "path": "manim/scene/zoomed_scene.py",
    "content": "\"\"\"A scene supporting zooming in on a specified section.\n\n\nExamples\n--------\n\n.. manim:: UseZoomedScene\n\n    class UseZoomedScene(ZoomedScene):\n        def construct(self):\n            dot = Dot().set_color(GREEN)\n            self.add(dot)\n            self.wait(1)\n            self.activate_zooming(animate=False)\n            self.wait(1)\n            self.play(dot.animate.shift(LEFT))\n\n.. manim:: ChangingZoomScale\n\n    class ChangingZoomScale(ZoomedScene):\n        def __init__(self, **kwargs):\n            ZoomedScene.__init__(\n                self,\n                zoom_factor=0.3,\n                zoomed_display_height=1,\n                zoomed_display_width=3,\n                image_frame_stroke_width=20,\n                zoomed_camera_config={\n                    \"default_frame_stroke_width\": 3,\n                },\n                **kwargs\n            )\n\n        def construct(self):\n            dot = Dot().set_color(GREEN)\n            sq = Circle(fill_opacity=1, radius=0.2).next_to(dot, RIGHT)\n            self.add(dot, sq)\n            self.wait(1)\n            self.activate_zooming(animate=False)\n            self.wait(1)\n            self.play(dot.animate.shift(LEFT * 0.3))\n\n            self.play(self.zoomed_camera.frame.animate.scale(4))\n            self.play(self.zoomed_camera.frame.animate.shift(0.5 * DOWN))\n\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"ZoomedScene\"]\n\nfrom typing import TYPE_CHECKING, Any\n\nfrom ..animation.transform import ApplyMethod\nfrom ..camera.camera import Camera\nfrom ..camera.moving_camera import MovingCamera\nfrom ..camera.multi_camera import MultiCamera\nfrom ..constants import *\nfrom ..mobject.types.image_mobject import ImageMobjectFromCamera\nfrom ..renderer.opengl_renderer import OpenGLCamera\nfrom ..scene.moving_camera_scene import MovingCameraScene\n\nif TYPE_CHECKING:\n    from manim.typing import Point3DLike, Vector3D\n\n# Note, any scenes from old videos using ZoomedScene will almost certainly\n# break, as it was restructured.\n\n\nclass ZoomedScene(MovingCameraScene):\n    \"\"\"This is a Scene with special configurations made for when\n    a particular part of the scene must be zoomed in on and displayed\n    separately.\n    \"\"\"\n\n    def __init__(\n        self,\n        camera_class: type[Camera] = MultiCamera,\n        zoomed_display_height: float = 3,\n        zoomed_display_width: float = 3,\n        zoomed_display_center: Point3DLike | None = None,\n        zoomed_display_corner: Vector3D = UP + RIGHT,\n        zoomed_display_corner_buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER,\n        zoomed_camera_config: dict[str, Any] = {\n            \"default_frame_stroke_width\": 2,\n            \"background_opacity\": 1,\n        },\n        zoomed_camera_image_mobject_config: dict[str, Any] = {},\n        zoomed_camera_frame_starting_position: Point3DLike = ORIGIN,\n        zoom_factor: float = 0.15,\n        image_frame_stroke_width: float = 3,\n        zoom_activated: bool = False,\n        **kwargs: Any,\n    ) -> None:\n        self.zoomed_display_height = zoomed_display_height\n        self.zoomed_display_width = zoomed_display_width\n        self.zoomed_display_center = zoomed_display_center\n        self.zoomed_display_corner = zoomed_display_corner\n        self.zoomed_display_corner_buff = zoomed_display_corner_buff\n        self.zoomed_camera_config = zoomed_camera_config\n        self.zoomed_camera_image_mobject_config = zoomed_camera_image_mobject_config\n        self.zoomed_camera_frame_starting_position = (\n            zoomed_camera_frame_starting_position\n        )\n        self.zoom_factor = zoom_factor\n        self.image_frame_stroke_width = image_frame_stroke_width\n        self.zoom_activated = zoom_activated\n        super().__init__(camera_class=camera_class, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"This method is used internally by Manim to\n        setup the scene for proper use.\n        \"\"\"\n        super().setup()\n        # Initialize camera and display\n        zoomed_camera = MovingCamera(**self.zoomed_camera_config)\n        zoomed_display = ImageMobjectFromCamera(\n            zoomed_camera, **self.zoomed_camera_image_mobject_config\n        )\n        zoomed_display.add_display_frame()\n        for mob in zoomed_camera.frame, zoomed_display:\n            mob.stretch_to_fit_height(self.zoomed_display_height)\n            mob.stretch_to_fit_width(self.zoomed_display_width)\n        zoomed_camera.frame.scale(self.zoom_factor)\n\n        # Position camera and display\n        zoomed_camera.frame.move_to(self.zoomed_camera_frame_starting_position)\n        if self.zoomed_display_center is not None:\n            zoomed_display.move_to(self.zoomed_display_center)\n        else:\n            zoomed_display.to_corner(\n                self.zoomed_display_corner,\n                buff=self.zoomed_display_corner_buff,\n            )\n\n        self.zoomed_camera = zoomed_camera\n        self.zoomed_display = zoomed_display\n\n    def activate_zooming(self, animate: bool = False) -> None:\n        \"\"\"This method is used to activate the zooming for the zoomed_camera.\n\n        Parameters\n        ----------\n        animate\n            Whether or not to animate the activation\n            of the zoomed camera.\n        \"\"\"\n        self.zoom_activated = True\n        self.renderer.camera.add_image_mobject_from_camera(self.zoomed_display)  # type: ignore[union-attr]\n        if animate:\n            self.play(self.get_zoom_in_animation())\n            self.play(self.get_zoomed_display_pop_out_animation())\n        self.add_foreground_mobjects(\n            self.zoomed_camera.frame,\n            self.zoomed_display,\n        )\n\n    def get_zoom_in_animation(self, run_time: float = 2, **kwargs: Any) -> ApplyMethod:\n        \"\"\"Returns the animation of camera zooming in.\n\n        Parameters\n        ----------\n        run_time\n            The run_time of the animation of the camera zooming in.\n        **kwargs\n            Any valid keyword arguments of ApplyMethod()\n\n        Returns\n        -------\n        ApplyMethod\n            The animation of the camera zooming in.\n        \"\"\"\n        frame = self.zoomed_camera.frame\n        if isinstance(self.camera, OpenGLCamera):\n            full_frame_width, full_frame_height = self.camera.frame_shape\n        else:\n            full_frame_height = self.camera.frame_height\n            full_frame_width = self.camera.frame_width\n        frame.save_state()\n        frame.stretch_to_fit_width(full_frame_width)\n        frame.stretch_to_fit_height(full_frame_height)\n        frame.center()\n        frame.set_stroke(width=0)\n        return ApplyMethod(frame.restore, run_time=run_time, **kwargs)\n\n    def get_zoomed_display_pop_out_animation(self, **kwargs: Any) -> ApplyMethod:\n        \"\"\"This is the animation of the popping out of the mini-display that\n        shows the content of the zoomed camera.\n\n        Returns\n        -------\n        ApplyMethod\n            The Animation of the Zoomed Display popping out.\n        \"\"\"\n        display = self.zoomed_display\n        display.save_state()\n        display.replace(self.zoomed_camera.frame, stretch=True)\n        return ApplyMethod(display.restore)\n\n    def get_zoom_factor(self) -> float:\n        \"\"\"Returns the Zoom factor of the Zoomed camera.\n\n        Defined as the ratio between the height of the zoomed camera and\n        the height of the zoomed mini display.\n\n        Returns\n        -------\n        float\n            The zoom factor.\n        \"\"\"\n        zoom_factor: float = (\n            self.zoomed_camera.frame.height / self.zoomed_display.height\n        )\n        return zoom_factor\n"
  },
  {
    "path": "manim/templates/Axes.mtp",
    "content": "class AxesTemplate(Scene):\n    def construct(self):\n        graph = Axes(\n            x_range=[-1,10,1],\n            y_range=[-1,10,1],\n            x_length=9,\n            y_length=6,\n            axis_config={\"include_tip\":False}\n        )\n        labels = graph.get_axis_labels()\n        self.add(graph, labels)\n"
  },
  {
    "path": "manim/templates/Default.mtp",
    "content": "class DefaultTemplate(Scene):\n    def construct(self):\n        circle = Circle()  # create a circle\n        circle.set_fill(PINK, opacity=0.5)  # set color and transparency\n\n        square = Square()  # create a square\n        square.flip(RIGHT)  # flip horizontally\n        square.rotate(-3 * TAU / 8)  # rotate a certain amount\n\n        self.play(Create(square))  # animate the creation of the square\n        self.play(Transform(square, circle))  # interpolate the square into the circle\n        self.play(FadeOut(square))  # fade out animation\n"
  },
  {
    "path": "manim/templates/MovingCamera.mtp",
    "content": "class MovingCameraTemplate(MovingCameraScene):\n    def construct(self):\n        text = Text(\"Hello World\").set_color(BLUE)\n        self.add(text)\n        self.camera.frame.save_state()\n        self.play(self.camera.frame.animate.set(width=text.width * 1.2))\n        self.wait(0.3)\n        self.play(Restore(self.camera.frame))\n"
  },
  {
    "path": "manim/templates/template.cfg",
    "content": "[CLI]\nframe_rate = 30\npixel_height = 480\npixel_width = 854\nbackground_color = BLACK\nbackground_opacity = 1\nscene_names = DefaultScene\n"
  },
  {
    "path": "manim/typing.py",
    "content": "\"\"\"Custom type definitions used in Manim.\n\n.. admonition:: Note for developers\n    :class: important\n\n    Around the source code there are multiple strings which look like this:\n\n    .. code-block::\n\n        '''\n        [CATEGORY]\n        <category_name>\n        '''\n\n    All type aliases defined under those strings will be automatically\n    classified under that category.\n\n    If you need to define a new category, respect the format described above.\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import Callable, Sequence\nfrom os import PathLike\nfrom typing import TypeAlias\n\nimport numpy as np\nimport numpy.typing as npt\n\n__all__ = [\n    \"ManimFloat\",\n    \"ManimInt\",\n    \"ManimColorDType\",\n    \"FloatRGB\",\n    \"FloatRGBLike\",\n    \"FloatRGB_Array\",\n    \"FloatRGBLike_Array\",\n    \"IntRGB\",\n    \"IntRGBLike\",\n    \"FloatRGBA\",\n    \"FloatRGBALike\",\n    \"FloatRGBA_Array\",\n    \"FloatRGBALike_Array\",\n    \"IntRGBA\",\n    \"IntRGBALike\",\n    \"FloatHSV\",\n    \"FloatHSVLike\",\n    \"FloatHSL\",\n    \"FloatHSLLike\",\n    \"FloatHSVA\",\n    \"FloatHSVALike\",\n    \"ManimColorInternal\",\n    \"PointDType\",\n    \"Point2D\",\n    \"Point2DLike\",\n    \"Point2D_Array\",\n    \"Point2DLike_Array\",\n    \"Point3D\",\n    \"Point3DLike\",\n    \"Point3D_Array\",\n    \"Point3DLike_Array\",\n    \"PointND\",\n    \"PointNDLike\",\n    \"PointND_Array\",\n    \"PointNDLike_Array\",\n    \"Vector2D\",\n    \"Vector2DLike\",\n    \"Vector2D_Array\",\n    \"Vector2DLike_Array\",\n    \"Vector3D\",\n    \"Vector3DLike\",\n    \"Vector3D_Array\",\n    \"Vector3DLike_Array\",\n    \"VectorND\",\n    \"VectorNDLike\",\n    \"VectorND_Array\",\n    \"VectorNDLike_Array\",\n    \"RowVector\",\n    \"ColVector\",\n    \"MatrixMN\",\n    \"Zeros\",\n    \"QuadraticBezierPoints\",\n    \"QuadraticBezierPointsLike\",\n    \"QuadraticBezierPoints_Array\",\n    \"QuadraticBezierPointsLike_Array\",\n    \"QuadraticBezierPath\",\n    \"QuadraticBezierPathLike\",\n    \"QuadraticSpline\",\n    \"QuadraticSplineLike\",\n    \"CubicBezierPoints\",\n    \"CubicBezierPointsLike\",\n    \"CubicBezierPoints_Array\",\n    \"CubicBezierPointsLike_Array\",\n    \"CubicBezierPath\",\n    \"CubicBezierPathLike\",\n    \"CubicSpline\",\n    \"CubicSplineLike\",\n    \"BezierPoints\",\n    \"BezierPointsLike\",\n    \"BezierPoints_Array\",\n    \"BezierPointsLike_Array\",\n    \"BezierPath\",\n    \"BezierPathLike\",\n    \"Spline\",\n    \"SplineLike\",\n    \"FlatBezierPoints\",\n    \"FunctionOverride\",\n    \"PathFuncType\",\n    \"MappingFunction\",\n    \"MultiMappingFunction\",\n    \"PixelArray\",\n    \"GrayscalePixelArray\",\n    \"RGBPixelArray\",\n    \"RGBAPixelArray\",\n    \"StrPath\",\n    \"StrOrBytesPath\",\n]\n\n\n\"\"\"\n[CATEGORY]\nPrimitive data types\n\"\"\"\n\nManimFloat: TypeAlias = np.float64\n\"\"\"A double-precision floating-point value (64 bits, or 8 bytes),\naccording to the IEEE 754 standard.\n\"\"\"\n\nManimInt: TypeAlias = np.int64\nr\"\"\"A long integer (64 bits, or 8 bytes).\n\nIt can take values between :math:`-2^{63}` and :math:`+2^{63} - 1`,\nwhich expressed in base 10 is a range between around\n:math:`-9.223 \\cdot 10^{18}` and :math:`+9.223 \\cdot 10^{18}`.\n\"\"\"\n\n\n\"\"\"\n[CATEGORY]\nColor types\n\"\"\"\n\nManimColorDType: TypeAlias = ManimFloat\n\"\"\"Data type used in :class:`~.ManimColorInternal`: a\ndouble-precision float between 0 and 1.\n\"\"\"\n\nFloatRGB: TypeAlias = npt.NDArray[ManimColorDType]\n\"\"\"``shape: (3,)``\n\nA :class:`numpy.ndarray` of 3 floats between 0 and 1, representing a\ncolor in RGB format.\n\nIts components describe, in order, the intensity of Red, Green, and\nBlue in the represented color.\n\"\"\"\n\nFloatRGBLike: TypeAlias = FloatRGB | tuple[float, float, float]\n\"\"\"``shape: (3,)``\n\nAn array of 3 floats between 0 and 1, representing a color in RGB\nformat.\n\nThis represents anything which can be converted to a :class:`.FloatRGB` NumPy\narray.\n\"\"\"\n\nFloatRGB_Array: TypeAlias = npt.NDArray[ManimColorDType]\n\"\"\"``shape: (M, 3)``\n\nA :class:`numpy.ndarray` of many rows of 3 floats representing RGB colors.\n\"\"\"\n\nFloatRGBLike_Array: TypeAlias = FloatRGB_Array | Sequence[FloatRGBLike]\n\"\"\"``shape: (M, 3)``\n\nAn array of many rows of 3 floats representing RGB colors.\n\nThis represents anything which can be converted to a :class:`.FloatRGB_Array` NumPy\narray.\n\"\"\"\n\nIntRGB: TypeAlias = npt.NDArray[ManimInt]\n\"\"\"``shape: (3,)``\n\nA :class:`numpy.ndarray` of 3 integers between 0 and 255,\nrepresenting a color in RGB format.\n\nIts components describe, in order, the intensity of Red, Green, and\nBlue in the represented color.\n\"\"\"\n\nIntRGBLike: TypeAlias = IntRGB | tuple[int, int, int]\n\"\"\"``shape: (3,)``\n\nAn array of 3 integers between 0 and 255, representing a color in RGB\nformat.\n\nThis represents anything which can be converted to an :class:`.IntRGB` NumPy\narray.\n\"\"\"\n\nFloatRGBA: TypeAlias = npt.NDArray[ManimColorDType]\n\"\"\"``shape: (4,)``\n\nA :class:`numpy.ndarray` of 4 floats between 0 and 1, representing a\ncolor in RGBA format.\n\nIts components describe, in order, the intensity of Red, Green, Blue\nand Alpha (opacity) in the represented color.\n\"\"\"\n\nFloatRGBALike: TypeAlias = FloatRGBA | tuple[float, float, float, float]\n\"\"\"``shape: (4,)``\n\nAn array of 4 floats between 0 and 1, representing a color in RGBA\nformat.\n\nThis represents anything which can be converted to a :class:`.FloatRGBA` NumPy\narray.\n\"\"\"\n\nFloatRGBA_Array: TypeAlias = npt.NDArray[ManimColorDType]\n\"\"\"``shape: (M, 4)``\n\nA :class:`numpy.ndarray` of many rows of 4 floats representing RGBA colors.\n\"\"\"\n\nFloatRGBALike_Array: TypeAlias = FloatRGBA_Array | Sequence[FloatRGBALike]\n\"\"\"``shape: (M, 4)``\n\nAn array of many rows of 4 floats representing RGBA colors.\n\nThis represents anything which can be converted to a :class:`.FloatRGBA_Array` NumPy\narray.\n\"\"\"\n\nIntRGBA: TypeAlias = npt.NDArray[ManimInt]\n\"\"\"``shape: (4,)``\n\nA :class:`numpy.ndarray` of 4 integers between 0 and 255,\nrepresenting a color in RGBA format.\n\nIts components describe, in order, the intensity of Red, Green, Blue\nand Alpha (opacity) in the represented color.\n\"\"\"\n\nIntRGBALike: TypeAlias = IntRGBA | tuple[int, int, int, int]\n\"\"\"``shape: (4,)``\n\nAn array of 4 integers between 0 and 255, representing a color in RGBA\nformat.\n\nThis represents anything which can be converted to an :class:`.IntRGBA` NumPy\narray.\n\"\"\"\n\nFloatHSV: TypeAlias = FloatRGB\n\"\"\"``shape: (3,)``\n\nA :class:`numpy.ndarray` of 3 floats between 0 and 1, representing a\ncolor in HSV (or HSB) format.\n\nIts components describe, in order, the Hue, Saturation and Value (or\nBrightness) in the represented color.\n\"\"\"\n\nFloatHSVLike: TypeAlias = FloatRGBLike\n\"\"\"``shape: (3,)``\n\nAn array of 3 floats between 0 and 1, representing a color in HSV (or\nHSB) format.\n\nThis represents anything which can be converted to a :class:`.FloatHSV` NumPy\narray.\n\"\"\"\n\nFloatHSVA: TypeAlias = FloatRGBA\n\"\"\"``shape: (4,)``\n\nA :class:`numpy.ndarray` of 4 floats between 0 and 1, representing a\ncolor in HSVA (or HSBA) format.\n\nIts components describe, in order, the Hue, Saturation and Value (or\nBrightness) in the represented color.\n\"\"\"\n\nFloatHSVALike: TypeAlias = FloatRGBALike\n\"\"\"``shape: (4,)``\n\nAn array of 4 floats between 0 and 1, representing a color in HSVA (or\nHSBA) format.\n\nThis represents anything which can be converted to a :class:`.FloatHSVA` NumPy\narray.\n\"\"\"\n\nFloatHSL: TypeAlias = FloatRGB\n\"\"\"``shape: (3,)``\n\nA :class:`numpy.ndarray` of 3 floats between 0 and 1, representing a\ncolor in HSL format.\n\nIts components describe, in order, the Hue, Saturation and Lightness\nin the represented color.\n\"\"\"\n\nFloatHSLLike: TypeAlias = FloatRGBLike\n\"\"\"``shape: (3,)``\n\nAn array of 3 floats between 0 and 1, representing a color in HSL format.\n\nThis represents anything which can be converted to a :class:`.FloatHSL` NumPy\narray.\n\"\"\"\n\nManimColorInternal: TypeAlias = FloatRGBA\n\"\"\"``shape: (4,)``\n\nInternal color representation used by :class:`~.ManimColor`,\nfollowing the RGBA format.\n\nIt is a :class:`numpy.ndarray` consisting of 4 floats between 0 and\n1, describing respectively the intensities of Red, Green, Blue and\nAlpha (opacity) in the represented color.\n\"\"\"\n\n\n\"\"\"\n[CATEGORY]\nPoint types\n\"\"\"\n\nPointDType: TypeAlias = ManimFloat\n\"\"\"Default type for arrays representing points: a double-precision\nfloating point value.\n\"\"\"\n\nPoint2D: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (2,)``\n\nA NumPy array representing a 2-dimensional point: ``[float, float]``.\n\"\"\"\n\nPoint2DLike: TypeAlias = Point2D | tuple[float, float]\n\"\"\"``shape: (2,)``\n\nA 2-dimensional point: ``[float, float]``.\n\nThis represents anything which can be converted to a :class:`.Point2D` NumPy\narray.\n\"\"\"\n\nPoint2D_Array: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (M, 2)``\n\nA NumPy array representing a sequence of :class:`.Point2D` objects:\n``[[float, float], ...]``.\n\"\"\"\n\nPoint2DLike_Array: TypeAlias = Point2D_Array | Sequence[Point2DLike]\n\"\"\"``shape: (M, 2)``\n\nAn array of :class:`.Point2DLike` objects: ``[[float, float], ...]``.\n\nThis represents anything which can be converted to a :class:`.Point2D_Array`\nNumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nPoint3D: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (3,)``\n\nA NumPy array representing a 3-dimensional point: ``[float, float, float]``.\n\"\"\"\n\nPoint3DLike: TypeAlias = Point3D | tuple[float, float, float]\n\"\"\"``shape: (3,)``\n\nA 3-dimensional point: ``[float, float, float]``.\n\nThis represents anything which can be converted to a :class:`.Point3D` NumPy\narray.\n\"\"\"\n\nPoint3D_Array: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (M, 3)``\n\nA NumPy array representing a sequence of :class:`.Point3D` objects:\n``[[float, float, float], ...]``.\n\"\"\"\n\nPoint3DLike_Array: TypeAlias = Point3D_Array | Sequence[Point3DLike]\n\"\"\"``shape: (M, 3)``\n\nAn array of :class:`.Point3DLike` objects: ``[[float, float, float], ...]``.\n\nThis represents anything which can be converted to a :class:`.Point3D_Array`\nNumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nPointND: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (N,)``\n\nA NumPy array representing an N-dimensional point: ``[float, ...]``.\n\"\"\"\n\nPointNDLike: TypeAlias = PointND | Sequence[float]\n\"\"\"``shape: (N,)``\n\nAn N-dimensional point: ``[float, ...]``.\n\nThis represents anything which can be converted to a :class:`.PointND` NumPy\narray.\n\"\"\"\n\nPointND_Array: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (M, N)``\n\nA NumPy array representing a sequence of :class:`.PointND` objects:\n``[[float, ...], ...]``.\n\"\"\"\n\nPointNDLike_Array: TypeAlias = PointND_Array | Sequence[PointNDLike]\n\"\"\"``shape: (M, N)``\n\nAn array of :class:`.PointNDLike` objects: ``[[float, ...], ...]``.\n\nThis represents anything which can be converted to a :class:`.PointND_Array`\nNumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\n\n\"\"\"\n[CATEGORY]\nVector types\n\"\"\"\n\nVector2D: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (2,)``\n\nA NumPy array representing a 2-dimensional vector: ``[float, float]``.\n\n.. caution::\n    Do not confuse with the :class:`~.Vector` or :class:`~.Arrow`\n    VMobjects!\n\"\"\"\n\nVector2DLike: TypeAlias = npt.NDArray[PointDType] | tuple[float, float]\n\"\"\"``shape: (2,)``\n\nA 2-dimensional vector: ``[float, float]``.\n\nThis represents anything which can be converted to a :class:`.Vector2D` NumPy\narray.\n\n.. caution::\n    Do not confuse with the :class:`~.Vector` or :class:`~.Arrow`\n    VMobjects!\n\"\"\"\n\nVector2D_Array: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (M, 2)``\n\nA NumPy array representing a sequence of :class:`.Vector2D` objects:\n``[[float, float], ...]``.\n\"\"\"\n\nVector2DLike_Array: TypeAlias = Vector2D_Array | Sequence[Vector2DLike]\n\"\"\"``shape: (M, 2)``\n\nAn array of :class:`.Vector2DLike` objects: ``[[float, float], ...]``.\n\nThis represents anything which can be converted to a :class:`.Vector2D_Array`\nNumPy array.\n\"\"\"\n\nVector3D: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (3,)``\n\nA NumPy array representing a 3-dimensional vector: ``[float, float, float]``.\n\n.. caution::\n    Do not confuse with the :class:`~.Vector` or :class:`~.Arrow3D`\n    VMobjects!\n\"\"\"\n\nVector3DLike: TypeAlias = npt.NDArray[PointDType] | tuple[float, float, float]\n\"\"\"``shape: (3,)``\n\nA 3-dimensional vector: ``[float, float, float]``.\n\nThis represents anything which can be converted to a :class:`.Vector3D` NumPy\narray.\n\n.. caution::\n    Do not confuse with the :class:`~.Vector` or :class:`~.Arrow3D`\n    VMobjects!\n\"\"\"\n\nVector3D_Array: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (M, 3)``\n\nAn NumPy array representing a sequence of :class:`.Vector3D` objects:\n``[[float, float, float], ...]``.\n\"\"\"\n\nVector3DLike_Array: TypeAlias = npt.NDArray[PointDType] | Sequence[Vector3DLike]\n\"\"\"``shape: (M, 3)``\n\nAn array of :class:`.Vector3DLike` objects: ``[[float, float, float], ...]``.\n\nThis represents anything which can be converted to a :class:`.Vector3D_Array`\nNumPy array.\n\"\"\"\n\nVectorND: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape (N,)``\n\nA NumPy array representing an :math:`N`-dimensional vector: ``[float, ...]``.\n\n.. caution::\n    Do not confuse with the :class:`~.Vector` VMobject! This type alias\n    is named \"VectorND\" instead of \"Vector\" to avoid potential name\n    collisions.\n\"\"\"\n\nVectorNDLike: TypeAlias = npt.NDArray[PointDType] | Sequence[float]\n\"\"\"``shape (N,)``\n\nAn :math:`N`-dimensional vector: ``[float, ...]``.\n\nThis represents anything which can be converted to a :class:`.VectorND` NumPy\narray.\n\n.. caution::\n    Do not confuse with the :class:`~.Vector` VMobject! This type alias\n    is named \"VectorND\" instead of \"Vector\" to avoid potential name\n    collisions.\n\"\"\"\n\nVectorND_Array: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape (M, N)``\n\nA NumPy array representing a sequence of :class:`.VectorND` objects:\n``[[float, ...], ...]``.\n\"\"\"\n\nVectorNDLike_Array: TypeAlias = npt.NDArray[PointDType] | Sequence[VectorNDLike]\n\"\"\"``shape (M, N)``\n\nAn array of :class:`.VectorNDLike` objects: ``[[float, ...], ...]``.\n\nThis represents anything which can be converted to a :class:`.VectorND_Array`\nNumPy array.\n\"\"\"\n\nRowVector: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (1, N)``\n\nA row vector: ``[[float, ...]]``.\n\"\"\"\n\nColVector: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (N, 1)``\n\nA column vector: ``[[float], [float], ...]``.\n\"\"\"\n\n\n\"\"\"\n[CATEGORY]\nMatrix types\n\"\"\"\n\nMatrixMN: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (M, N)``\n\nA matrix: ``[[float, ...], [float, ...], ...]``.\n\"\"\"\n\nZeros: TypeAlias = MatrixMN\n\"\"\"``shape: (M, N)``\n\nA :class:`.MatrixMN` filled with zeros, typically created with\n``numpy.zeros((M, N))``.\n\"\"\"\n\n\n\"\"\"\n[CATEGORY]\nBézier types\n\"\"\"\n\nQuadraticBezierPoints: TypeAlias = Point3D_Array\n\"\"\"``shape: (3, 3)``\n\nA :class:`.Point3D_Array` of three 3D control points for a single quadratic Bézier\ncurve:\n``[[float, float, float], [float, float, float], [float, float, float]]``.\n\"\"\"\n\nQuadraticBezierPointsLike: TypeAlias = (\n    QuadraticBezierPoints | tuple[Point3DLike, Point3DLike, Point3DLike]\n)\n\"\"\"``shape: (3, 3)``\n\nA :class:`.Point3DLike_Array` of three 3D control points for a single quadratic Bézier\ncurve:\n``[[float, float, float], [float, float, float], [float, float, float]]``.\n\nThis represents anything which can be converted to a\n:class:`.QuadraticBezierPoints` NumPy array.\n\"\"\"\n\nQuadraticBezierPoints_Array: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (N, 3, 3)``\n\nA NumPy array containing :math:`N` :class:`.QuadraticBezierPoints` objects:\n``[[[float, float, float], [float, float, float], [float, float, float]], ...]``.\n\"\"\"\n\nQuadraticBezierPointsLike_Array: TypeAlias = (\n    QuadraticBezierPoints_Array | Sequence[QuadraticBezierPointsLike]\n)\n\"\"\"``shape: (N, 3, 3)``\n\nA sequence of :math:`N` :class:`.QuadraticBezierPointsLike` objects:\n``[[[float, float, float], [float, float, float], [float, float, float]], ...]``.\n\nThis represents anything which can be converted to a\n:class:`.QuadraticBezierPoints_Array` NumPy array.\n\"\"\"\n\nQuadraticBezierPath: TypeAlias = Point3D_Array\n\"\"\"``shape: (3*N, 3)``\n\nA :class:`.Point3D_Array` of :math:`3N` points, where each one of the\n:math:`N` consecutive blocks of 3 points represents a quadratic\nBézier curve:\n``[[float, float, float], ...], ...]``.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nQuadraticBezierPathLike: TypeAlias = Point3DLike_Array\n\"\"\"``shape: (3*N, 3)``\n\nA :class:`.Point3DLike_Array` of :math:`3N` points, where each one of the\n:math:`N` consecutive blocks of 3 points represents a quadratic\nBézier curve:\n``[[float, float, float], ...], ...]``.\n\nThis represents anything which can be converted to a\n:class:`.QuadraticBezierPath` NumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nQuadraticSpline: TypeAlias = QuadraticBezierPath\n\"\"\"``shape: (3*N, 3)``\n\nA special case of :class:`.QuadraticBezierPath` where all the :math:`N`\nquadratic Bézier curves are connected, forming a quadratic spline:\n``[[float, float, float], ...], ...]``.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nQuadraticSplineLike: TypeAlias = QuadraticBezierPathLike\n\"\"\"``shape: (3*N, 3)``\n\nA special case of :class:`.QuadraticBezierPathLike` where all the :math:`N`\nquadratic Bézier curves are connected, forming a quadratic spline:\n``[[float, float, float], ...], ...]``.\n\nThis represents anything which can be converted to a :class:`.QuadraticSpline`\nNumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nCubicBezierPoints: TypeAlias = Point3D_Array\n\"\"\"``shape: (4, 3)``\n\nA :class:`.Point3D_Array` of four 3D control points for a single cubic Bézier curve:\n``[[float, float, float], [float, float, float], [float, float, float], [float, float, float]]``.\n\"\"\"\n\nCubicBezierPointsLike: TypeAlias = (\n    CubicBezierPoints | tuple[Point3DLike, Point3DLike, Point3DLike, Point3DLike]\n)\n\"\"\"``shape: (4, 3)``\n\nA :class:`.Point3DLike_Array` of 4 control points for a single cubic Bézier curve:\n``[[float, float, float], [float, float, float], [float, float, float], [float, float, float]]``.\n\nThis represents anything which can be converted to a :class:`.CubicBezierPoints`\nNumPy array.\n\"\"\"\n\nCubicBezierPoints_Array: TypeAlias = npt.NDArray[PointDType]\n\"\"\"``shape: (N, 4, 3)``\n\nA NumPy array containing :math:`N` :class:`.CubicBezierPoints` objects:\n``[[[float, float, float], [float, float, float], [float, float, float], [float, float, float]], ...]``.\n\"\"\"\n\nCubicBezierPointsLike_Array: TypeAlias = (\n    CubicBezierPoints_Array | Sequence[CubicBezierPointsLike]\n)\n\"\"\"``shape: (N, 4, 3)``\n\nA sequence of :math:`N` :class:`.CubicBezierPointsLike` objects:\n``[[[float, float, float], [float, float, float], [float, float, float], [float, float, float]], ...]``.\n\nThis represents anything which can be converted to a\n:class:`.CubicBezierPoints_Array` NumPy array.\n\"\"\"\n\nCubicBezierPath: TypeAlias = Point3D_Array\n\"\"\"``shape: (4*N, 3)``\n\nA :class:`.Point3D_Array` of :math:`4N` points, where each one of the\n:math:`N` consecutive blocks of 4 points represents a cubic Bézier\ncurve:\n``[[float, float, float], ...], ...]``.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nCubicBezierPathLike: TypeAlias = Point3DLike_Array\n\"\"\"``shape: (4*N, 3)``\n\nA :class:`.Point3DLike_Array` of :math:`4N` points, where each one of the\n:math:`N` consecutive blocks of 4 points represents a cubic Bézier\ncurve:\n``[[float, float, float], ...], ...]``.\n\nThis represents anything which can be converted to a\n:class:`.CubicBezierPath` NumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nCubicSpline: TypeAlias = CubicBezierPath\n\"\"\"``shape: (4*N, 3)``\n\nA special case of :class:`.CubicBezierPath` where all the :math:`N` cubic\nBézier curves are connected, forming a quadratic spline:\n``[[float, float, float], ...], ...]``.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nCubicSplineLike: TypeAlias = CubicBezierPathLike\n\"\"\"``shape: (4*N, 3)``\n\nA special case of :class:`.CubicBezierPath` where all the :math:`N` cubic\nBézier curves are connected, forming a quadratic spline:\n``[[float, float, float], ...], ...]``.\n\nThis represents anything which can be converted to a\n:class:`.CubicSpline` NumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nBezierPoints: TypeAlias = Point3D_Array\nr\"\"\"``shape: (PPC, 3)``\n\nA :class:`.Point3D_Array` of :math:`\\text{PPC}` control points\n(:math:`\\text{PPC: Points Per Curve} = n + 1`) for a single\n:math:`n`-th degree Bézier curve:\n``[[float, float, float], ...]``.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nBezierPointsLike: TypeAlias = Point3DLike_Array\nr\"\"\"``shape: (PPC, 3)``\n\nA :class:`.Point3DLike_Array` of :math:`\\text{PPC}` control points\n(:math:`\\text{PPC: Points Per Curve} = n + 1`) for a single\n:math:`n`-th degree Bézier curve:\n``[[float, float, float], ...]``.\n\nThis represents anything which can be converted to a\n:class:`.BezierPoints` NumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nBezierPoints_Array: TypeAlias = npt.NDArray[PointDType]\nr\"\"\"``shape: (N, PPC, 3)``\n\nA NumPy array of :math:`N` :class:`.BezierPoints` objects containing\n:math:`\\text{PPC}` :class:`.Point3D` objects each\n(:math:`\\text{PPC: Points Per Curve} = n + 1`):\n``[[[float, float, float], ...], ...]``.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nBezierPointsLike_Array: TypeAlias = BezierPoints_Array | Sequence[BezierPointsLike]\nr\"\"\"``shape: (N, PPC, 3)``\n\nA sequence of :math:`N` :class:`.BezierPointsLike` objects containing\n:math:`\\text{PPC}` :class:`.Point3DLike` objects each\n(:math:`\\text{PPC: Points Per Curve} = n + 1`):\n``[[[float, float, float], ...], ...]``.\n\nThis represents anything which can be converted to a\n:class:`.BezierPoints_Array` NumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nBezierPath: TypeAlias = Point3D_Array\nr\"\"\"``shape: (PPC*N, 3)``\n\nA :class:`.Point3D_Array` of :math:`\\text{PPC} \\cdot N` points, where each\none of the :math:`N` consecutive blocks of :math:`\\text{PPC}` control\npoints (:math:`\\text{PPC: Points Per Curve} = n + 1`) represents a\nBézier curve of :math:`n`-th degree:\n``[[float, float, float], ...], ...]``.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nBezierPathLike: TypeAlias = Point3DLike_Array\nr\"\"\"``shape: (PPC*N, 3)``\n\nA :class:`.Point3DLike_Array` of :math:`\\text{PPC} \\cdot N` points, where each\none of the :math:`N` consecutive blocks of :math:`\\text{PPC}` control\npoints (:math:`\\text{PPC: Points Per Curve} = n + 1`) represents a\nBézier curve of :math:`n`-th degree:\n``[[float, float, float], ...], ...]``.\n\nThis represents anything which can be converted to a\n:class:`.BezierPath` NumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nSpline: TypeAlias = BezierPath\nr\"\"\"``shape: (PPC*N, 3)``\n\nA special case of :class:`.BezierPath` where all the :math:`N` Bézier curves\nconsisting of :math:`\\text{PPC}` :class:`.Point3D` objects\n(:math:`\\text{PPC: Points Per Curve} = n + 1`) are connected, forming\nan :math:`n`-th degree spline:\n``[[float, float, float], ...], ...]``.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nSplineLike: TypeAlias = BezierPathLike\nr\"\"\"``shape: (PPC*N, 3)``\n\nA special case of :class:`.BezierPathLike` where all the :math:`N` Bézier curves\nconsisting of :math:`\\text{PPC}` :class:`.Point3D` objects\n(:math:`\\text{PPC: Points Per Curve} = n + 1`) are connected, forming\nan :math:`n`-th degree spline:\n``[[float, float, float], ...], ...]``.\n\nThis represents anything which can be converted to a\n:class:`.Spline` NumPy array.\n\nPlease refer to the documentation of the function you are using for\nfurther type information.\n\"\"\"\n\nFlatBezierPoints: TypeAlias = npt.NDArray[PointDType] | tuple[float, ...]\n\"\"\"``shape: (3*PPC*N,)``\n\nA flattened array of Bézier control points:\n``[float, ...]``.\n\"\"\"\n\n\n\"\"\"\n[CATEGORY]\nFunction types\n\"\"\"\n\n# Due to current limitations\n# (see https://github.com/python/mypy/issues/14656 / 8263),\n# we don't specify the first argument type (Mobject).\n# Nor are we able to specify the return type (Animation) since we cannot import\n# that here.\nFunctionOverride: TypeAlias = Callable\n\"\"\"Function type returning an :class:`~.Animation` for the specified\n:class:`~.Mobject`.\n\"\"\"\n\nPathFuncType: TypeAlias = Callable[[Point3DLike, Point3DLike, float], Point3DLike]\n\"\"\"Function mapping two :class:`.Point3D` objects and an alpha value to a new\n:class:`.Point3D`.\n\"\"\"\n\nMappingFunction: TypeAlias = Callable[[Point3D], Point3D]\n\"\"\"A function mapping a :class:`.Point3D` to another :class:`.Point3D`.\"\"\"\n\nMultiMappingFunction: TypeAlias = Callable[[Point3D_Array], Point3D_Array]\n\"\"\"A function mapping a :class:`.Point3D_Array` to another\n:class:`.Point3D_Array`.\n\"\"\"\n\n\"\"\"\n[CATEGORY]\nImage types\n\"\"\"\n\nPixelArray: TypeAlias = npt.NDArray[ManimInt]\n\"\"\"``shape: (height, width) | (height, width, 3) | (height, width, 4)``\n\nA rasterized image with a height of ``height`` pixels and a width of\n``width`` pixels.\n\nEvery value in the array is an integer from 0 to 255.\n\nEvery pixel is represented either by a single integer indicating its\nlightness (for greyscale images), an :class:`.RGB_Array_Int` or an\n`RGBA_Array_Int`.\n\"\"\"\n\nGrayscalePixelArray: TypeAlias = PixelArray\n\"\"\"``shape: (height, width)``\n\nA 100% opaque grayscale :class:`.PixelArray`, where every pixel value is a\n`ManimInt` indicating its lightness (black -> gray -> white).\n\"\"\"\n\nRGBPixelArray: TypeAlias = PixelArray\n\"\"\"``shape: (height, width, 3)``\n\nA 100% opaque :class:`.PixelArray` in color, where every pixel value is an\n`RGB_Array_Int` object.\n\"\"\"\n\nRGBAPixelArray: TypeAlias = PixelArray\n\"\"\"``shape: (height, width, 4)``\n\nA :class:`.PixelArray` in color where pixels can be transparent. Every pixel\nvalue is an :class:`.RGBA_Array_Int` object.\n\"\"\"\n\n\n\"\"\"\n[CATEGORY]\nPath types\n\"\"\"\n\nStrPath: TypeAlias = str | PathLike[str]\n\"\"\"A string or :class:`.os.PathLike` representing a path to a\ndirectory or file.\n\"\"\"\n\nStrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes]\n\"\"\"A string, bytes or :class:`.os.PathLike` object representing a path\nto a directory or file.\n\"\"\"\n"
  },
  {
    "path": "manim/utils/__init__.py",
    "content": ""
  },
  {
    "path": "manim/utils/bezier.py",
    "content": "\"\"\"Utility functions related to Bézier curves.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"bezier\",\n    \"partial_bezier_points\",\n    \"split_bezier\",\n    \"subdivide_bezier\",\n    \"bezier_remap\",\n    \"interpolate\",\n    \"integer_interpolate\",\n    \"mid\",\n    \"inverse_interpolate\",\n    \"match_interpolate\",\n    \"get_smooth_cubic_bezier_handle_points\",\n    \"is_closed\",\n    \"proportions_along_bezier_curve_for_point\",\n    \"point_lies_on_bezier\",\n]\n\n\nfrom collections.abc import Callable, Sequence\nfrom functools import reduce\nfrom typing import TYPE_CHECKING, overload\n\nimport numpy as np\n\nfrom manim.utils.simple_functions import choose\n\nif TYPE_CHECKING:\n    from manim.typing import (\n        BezierPoints,\n        BezierPoints_Array,\n        BezierPointsLike,\n        BezierPointsLike_Array,\n        ColVector,\n        MatrixMN,\n        Point3D,\n        Point3D_Array,\n        Point3DLike,\n        Point3DLike_Array,\n        QuadraticBezierPath,\n        QuadraticSpline,\n        Spline,\n    )\n\n# l is a commonly used name in linear algebra\n# ruff: noqa: E741\n\n\n@overload\ndef bezier(\n    points: BezierPointsLike,\n) -> Callable[[float | ColVector], Point3D | Point3D_Array]: ...\n\n\n@overload\ndef bezier(\n    points: Sequence[Point3DLike_Array],\n) -> Callable[[float | ColVector], Point3D_Array]: ...\n\n\ndef bezier(\n    points: Point3D_Array | Sequence[Point3D_Array],\n) -> Callable[[float | ColVector], Point3D_Array]:\n    \"\"\"Classic implementation of a Bézier curve.\n\n    Parameters\n    ----------\n    points\n        :math:`(d+1, 3)`-shaped array of :math:`d+1` control points defining a single Bézier\n        curve of degree :math:`d`. Alternatively, for vectorization purposes, ``points`` can\n        also be a :math:`(d+1, M, 3)`-shaped sequence of :math:`d+1` arrays of :math:`M`\n        control points each, which define `M` Bézier curves instead.\n\n    Returns\n    -------\n    bezier_func : :class:`typing.Callable` [[:class:`float` | :class:`~.ColVector`], :class:`~.Point3D` | :class:`~.Point3D_Array`]\n        Function describing the Bézier curve. The behaviour of this function depends on\n        the shape of ``points``:\n\n            *   If ``points`` was a :math:`(d+1, 3)` array representing a single Bézier curve,\n                then ``bezier_func`` can receive either:\n\n                *   a :class:`float` ``t``, in which case it returns a\n                    single :math:`(1, 3)`-shaped :class:`~.Point3D` representing the evaluation\n                    of the Bézier at ``t``, or\n                *   an :math:`(n, 1)`-shaped :class:`~.ColVector`\n                    containing :math:`n` values to evaluate the Bézier curve at, returning instead\n                    an :math:`(n, 3)`-shaped :class:`~.Point3D_Array` containing the points\n                    resulting from evaluating the Bézier at each of the :math:`n` values.\n\n                .. warning::\n                    If passing a vector of :math:`t`-values to ``bezier_func``, it **must**\n                    be a column vector/matrix of shape :math:`(n, 1)`. Passing an 1D array of\n                    shape :math:`(n,)` is not supported and **will result in undefined behaviour**.\n\n            *   If ``points`` was a :math:`(d+1, M, 3)` array describing :math:`M` Bézier curves,\n                then ``bezier_func`` can receive either:\n\n                *   a :class:`float` ``t``, in which case it returns an\n                    :math:`(M, 3)`-shaped :class:`~.Point3D_Array` representing the evaluation\n                    of the :math:`M` Bézier curves at the same value ``t``, or\n                *   an :math:`(M, 1)`-shaped\n                    :class:`~.ColVector` containing :math:`M` values, such that the :math:`i`-th\n                    Bézier curve defined by ``points`` is evaluated at the corresponding :math:`i`-th\n                    value in ``t``, returning again an :math:`(M, 3)`-shaped :class:`~.Point3D_Array`\n                    containing those :math:`M` evaluations.\n\n                .. warning::\n                    Unlike the previous case, if you pass a :class:`~.ColVector` to ``bezier_func``,\n                    it **must** contain exactly :math:`M` values, each value for each of the :math:`M`\n                    Bézier curves defined by ``points``. Any array of shape other than :math:`(M, 1)`\n                    **will result in undefined behaviour**.\n    \"\"\"\n    P = np.asarray(points)\n    degree = P.shape[0] - 1\n\n    if degree == 0:\n\n        def zero_bezier(t: float | ColVector) -> Point3D | Point3D_Array:\n            return np.ones_like(t) * P[0]\n\n        return zero_bezier\n\n    if degree == 1:\n\n        def linear_bezier(t: float | ColVector) -> Point3D | Point3D_Array:\n            return P[0] + t * (P[1] - P[0])\n\n        return linear_bezier\n\n    if degree == 2:\n\n        def quadratic_bezier(t: float | ColVector) -> Point3D | Point3D_Array:\n            t2 = t * t\n            mt = 1 - t\n            mt2 = mt * mt\n            return mt2 * P[0] + 2 * t * mt * P[1] + t2 * P[2]\n\n        return quadratic_bezier\n\n    if degree == 3:\n\n        def cubic_bezier(t: float | ColVector) -> Point3D | Point3D_Array:\n            t2 = t * t\n            t3 = t2 * t\n            mt = 1 - t\n            mt2 = mt * mt\n            mt3 = mt2 * mt\n            return mt3 * P[0] + 3 * t * mt2 * P[1] + 3 * t2 * mt * P[2] + t3 * P[3]\n\n        return cubic_bezier\n\n    def nth_grade_bezier(t: float | ColVector) -> Point3D | Point3D_Array:\n        is_scalar = not isinstance(t, np.ndarray)\n        if is_scalar:\n            B = np.empty((1, *P.shape))\n        else:\n            assert isinstance(t, np.ndarray)\n            t = t.reshape(-1, *[1 for dim in P.shape])\n            B = np.empty((t.shape[0], *P.shape))\n        B[:] = P\n\n        for i in range(degree):\n            # After the i-th iteration (i in [0, ..., d-1]) there are evaluations at t\n            # of (d-i) Bezier curves of grade (i+1), stored in the first d-i slots of B\n            B[:, : degree - i] += t * (B[:, 1 : degree - i + 1] - B[:, : degree - i])\n\n        # In the end, there shall be the evaluation at t of a single Bezier curve of\n        # grade d, stored in the first slot of B\n        if is_scalar:\n            val: Point3D = B[0, 0]\n            return val\n        return B[:, 0]\n\n    return nth_grade_bezier\n\n\ndef partial_bezier_points(points: BezierPointsLike, a: float, b: float) -> BezierPoints:\n    r\"\"\"Given an array of ``points`` which define a Bézier curve, and two numbers :math:`a, b`\n    such that :math:`0 \\le a < b \\le 1`, return an array of the same size, which describes the\n    portion of the original Bézier curve on the interval :math:`[a, b]`.\n\n    :func:`partial_bezier_points` is conceptually equivalent to calling :func:`split_bezier`\n    twice and discarding unused Bézier curves, but this is more efficient and doesn't waste\n    computations.\n\n    .. seealso::\n        See :func:`split_bezier` for an explanation on how to split Bézier curves.\n\n    .. note::\n        To find the portion of a Bézier curve with :math:`t` between :math:`a` and :math:`b`:\n\n        1.  Split the curve at :math:`t = a` and extract its 2nd subcurve.\n        2.  We cannot evaluate the new subcurve at :math:`t = b` because its range of values for :math:`t` is different.\n            To find the correct value, we need to transform the interval :math:`[a, 1]` into :math:`[0, 1]`\n            by first subtracting :math:`a` to get :math:`[0, 1-a]` and then dividing by :math:`1-a`. Thus, our new\n            value must be :math:`t = \\frac{b - a}{1 - a}`. Define :math:`u = \\frac{b - a}{1 - a}`.\n        3.  Split the subcurve at :math:`t = u` and extract its 1st subcurve.\n\n        The final portion is a linear combination of points, and thus the process can be\n        summarized as a linear transformation by some matrix in terms of :math:`a` and :math:`b`.\n        This matrix is given explicitly for Bézier curves up to degree 3, which are often used in Manim.\n        For higher degrees, the algorithm described previously is used.\n\n        For the case of a quadratic Bézier curve:\n\n        * Step 1:\n\n        .. math::\n            H'_1\n            =\n            \\begin{pmatrix}\n                (1-a)^2 & 2(1-a)a & a^2 \\\\\n                0 & (1-a) & a \\\\\n                0 & 0 & 1\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                p_0 \\\\\n                p_1 \\\\\n                p_2\n            \\end{pmatrix}\n\n        * Step 2:\n\n        .. math::\n            H''_0\n            &=\n            \\begin{pmatrix}\n                1 & 0 & 0 \\\\\n                (1-u) & u & 0\\\\\n                (1-u)^2 & 2(1-u)u & u^2\n            \\end{pmatrix}\n            H'_1\n            \\\\\n            &\n            \\\\\n            &=\n            \\begin{pmatrix}\n                1 & 0 & 0 \\\\\n                (1-u) & u & 0\\\\\n                (1-u)^2 & 2(1-u)u & u^2\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                (1-a)^2 & 2(1-a)a & a^2 \\\\\n                0 & (1-a) & a \\\\\n                0 & 0 & 1\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                p_0 \\\\\n                p_1 \\\\\n                p_2\n            \\end{pmatrix}\n            \\\\\n            &\n            \\\\\n            &=\n            \\begin{pmatrix}\n                (1-a)^2 & 2(1-a)a & a^2 \\\\\n                (1-a)(1-b) & a(1-b) + (1-a)b & ab \\\\\n                (1-b)^2 & 2(1-b)b & b^2\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                p_0 \\\\\n                p_1 \\\\\n                p_2\n            \\end{pmatrix}\n\n        from where one can define a :math:`(3, 3)` matrix :math:`P_2` which, when applied over\n        the array of ``points``, will return the desired partial quadratic Bézier curve:\n\n        .. math::\n            P_2\n            =\n            \\begin{pmatrix}\n                (1-a)^2 & 2(1-a)a & a^2 \\\\\n                (1-a)(1-b) & a(1-b) + (1-a)b & ab \\\\\n                (1-b)^2 & 2(1-b)b & b^2\n            \\end{pmatrix}\n\n        Similarly, for the cubic Bézier curve case, one can define the following\n        :math:`(4, 4)` matrix :math:`P_3`:\n\n        .. math::\n            P_3\n            =\n            \\begin{pmatrix}\n                (1-a)^3 & 3(1-a)^2a & 3(1-a)a^2 & a^3 \\\\\n                (1-a)^2(1-b) & 2(1-a)a(1-b) + (1-a)^2b & a^2(1-b) + 2(1-a)ab & a^2b \\\\\n                (1-a)(1-b)^2 & a(1-b)^2 + 2(1-a)(1-b)b & 2a(1-b)b + (1-a)b^2 & ab^2 \\\\\n                (1-b)^3 & 3(1-b)^2b & 3(1-b)b^2 & b^3\n            \\end{pmatrix}\n\n    Parameters\n    ----------\n    points\n        set of points defining the bezier curve.\n    a\n        lower bound of the desired partial bezier curve.\n    b\n        upper bound of the desired partial bezier curve.\n\n    Returns\n    -------\n    :class:`~.BezierPoints`\n        An array containing the control points defining the partial Bézier curve.\n    \"\"\"\n    # Border cases\n    if a == 1:\n        arr = np.array(points)\n        arr[:] = arr[-1]\n        return arr\n    if b == 0:\n        arr = np.array(points)\n        arr[:] = arr[0]\n        return arr\n\n    points = np.asarray(points)\n    degree = points.shape[0] - 1\n\n    if degree == 3:\n        ma, mb = 1 - a, 1 - b\n        a2, b2, ma2, mb2 = a * a, b * b, ma * ma, mb * mb\n        a3, b3, ma3, mb3 = a2 * a, b2 * b, ma2 * ma, mb2 * mb\n\n        portion_matrix = np.array(\n            [\n                [ma3, 3 * ma2 * a, 3 * ma * a2, a3],\n                [ma2 * mb, 2 * ma * a * mb + ma2 * b, a2 * mb + 2 * ma * a * b, a2 * b],\n                [ma * mb2, a * mb2 + 2 * ma * mb * b, 2 * a * mb * b + ma * b2, a * b2],\n                [mb3, 3 * mb2 * b, 3 * mb * b2, b3],\n            ]\n        )\n        return portion_matrix @ points\n\n    if degree == 2:\n        ma, mb = 1 - a, 1 - b\n\n        portion_matrix = np.array(\n            [\n                [ma * ma, 2 * a * ma, a * a],\n                [ma * mb, a * mb + ma * b, a * b],\n                [mb * mb, 2 * b * mb, b * b],\n            ]\n        )\n        return portion_matrix @ points\n\n    if degree == 1:\n        direction = points[1] - points[0]\n        return np.array(\n            [\n                points[0] + a * direction,\n                points[0] + b * direction,\n            ]\n        )\n\n    if degree == 0:\n        return points\n\n    # Fallback case for nth degree Béziers\n    # It is convenient that np.array copies points\n    arr = np.array(points, dtype=float)\n    N = arr.shape[0]\n\n    # Current state for an example Bézier curve C0 = [P0, P1, P2, P3]:\n    # arr = [P0, P1, P2, P3]\n    if a != 0:\n        for i in range(1, N):\n            # 1st iter: arr = [L0(a), L1(a), L2(a), P3]\n            # 2nd iter: arr = [Q0(a), Q1(a), L2(a), P3]\n            # 3rd iter: arr = [C0(a), Q1(a), L2(a), P3]\n            arr[: N - i] += a * (arr[1 : N - i + 1] - arr[: N - i])\n\n    # For faster calculations we shall define mu = 1 - u = (1 - b) / (1 - a).\n    # This is because:\n    # L0'(u) = P0' + u(P1' - P0')\n    #        = (1-u)P0' + uP1'\n    #        = muP0' + (1-mu)P1'\n    #        = P1' + mu(P0' - P1)\n    # In this way, one can do something similar to the first loop.\n    #\n    # Current state:\n    # arr = [C0(a), Q1(a), L2(a), P3]\n    #     = [P0', P1', P2', P3']\n    if b != 1:\n        mu = (1 - b) / (1 - a)\n        for i in range(1, N):\n            # 1st iter: arr = [P0', L0'(u), L1'(u), L2'(u)]\n            # 2nd iter: arr = [P0', L0'(u), Q0'(u), Q1'(u)]\n            # 3rd iter: arr = [P0', L0'(u), Q0'(u), C0'(u)]\n            arr[i:] += mu * (arr[i - 1 : -1] - arr[i:])\n\n    return arr\n\n\ndef split_bezier(points: BezierPointsLike, t: float) -> Spline:\n    r\"\"\"Split a Bézier curve at argument ``t`` into two curves.\n\n    .. note::\n\n        .. seealso::\n            `A Primer on Bézier Curves #10: Splitting curves. Pomax. <https://pomax.github.io/bezierinfo/#splitting>`_\n\n        As an example for a cubic Bézier curve, let :math:`p_0, p_1, p_2, p_3` be the points\n        needed for the curve :math:`C_0 = [p_0, \\ p_1, \\ p_2, \\ p_3]`.\n\n        Define the 3 linear Béziers :math:`L_0, L_1, L_2` as interpolations of :math:`p_0, p_1, p_2, p_3`:\n\n        .. math::\n            L_0(t) &= p_0 + t(p_1 - p_0) \\\\\n            L_1(t) &= p_1 + t(p_2 - p_1) \\\\\n            L_2(t) &= p_2 + t(p_3 - p_2)\n\n        Define the 2 quadratic Béziers :math:`Q_0, Q_1` as interpolations of :math:`L_0, L_1, L_2`:\n\n        .. math::\n            Q_0(t) &= L_0(t) + t(L_1(t) - L_0(t)) \\\\\n            Q_1(t) &= L_1(t) + t(L_2(t) - L_1(t))\n\n        Then :math:`C_0` is the following interpolation of :math:`Q_0` and :math:`Q_1`:\n\n        .. math::\n            C_0(t) = Q_0(t) + t(Q_1(t) - Q_0(t))\n\n        Evaluating :math:`C_0` at a value :math:`t=t'` splits :math:`C_0` into two cubic Béziers :math:`H_0`\n        and :math:`H_1`, defined by some of the points we calculated earlier:\n\n        .. math::\n            H_0 &= [p_0, &\\ L_0(t'), &\\ Q_0(t'), &\\ C_0(t') &] \\\\\n            H_1 &= [p_0(t'), &\\ Q_1(t'), &\\ L_2(t'), &\\ p_3 &]\n\n        As the resulting curves are obtained from linear combinations of ``points``, everything can\n        be encoded into a matrix for efficiency, which is done for Bézier curves of degree up to 3.\n\n        .. seealso::\n            `A Primer on Bézier Curves #11: Splitting curves using matrices. Pomax. <https://pomax.github.io/bezierinfo/#matrixsplit>`_\n\n        For the simpler case of a quadratic Bézier curve:\n\n        .. math::\n            H_0\n            &=\n            \\begin{pmatrix}\n                p_0 \\\\\n                (1-t) p_0 + t p_1 \\\\\n                (1-t)^2 p_0 + 2(1-t)t p_1 + t^2 p_2 \\\\\n            \\end{pmatrix}\n            &=\n            \\begin{pmatrix}\n                1 & 0 & 0 \\\\\n                (1-t) & t & 0\\\\\n                (1-t)^2 & 2(1-t)t & t^2\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                p_0 \\\\\n                p_1 \\\\\n                p_2\n            \\end{pmatrix}\n            \\\\\n            &\n            \\\\\n            H_1\n            &=\n            \\begin{pmatrix}\n                (1-t)^2 p_0 + 2(1-t)t p_1 + t^2 p_2 \\\\\n                (1-t) p_1 + t p_2 \\\\\n                p_2\n            \\end{pmatrix}\n            &=\n            \\begin{pmatrix}\n                (1-t)^2 & 2(1-t)t & t^2 \\\\\n                0 & (1-t) & t \\\\\n                0 & 0 & 1\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                p_0 \\\\\n                p_1 \\\\\n                p_2\n            \\end{pmatrix}\n\n        from where one can define a :math:`(6, 3)` split matrix :math:`S_2` which can multiply\n        the array of ``points`` to compute the return value:\n\n        .. math::\n            S_2\n            &=\n            \\begin{pmatrix}\n                1 & 0 & 0 \\\\\n                (1-t) & t & 0 \\\\\n                (1-t)^2 & 2(1-t)t & t^2 \\\\\n                (1-t)^2 & 2(1-t)t & t^2 \\\\\n                0 & (1-t) & t \\\\\n                0 & 0 & 1\n            \\end{pmatrix}\n            \\\\\n            &\n            \\\\\n            S_2 P\n            &=\n            \\begin{pmatrix}\n                1 & 0 & 0 \\\\\n                (1-t) & t & 0 \\\\\n                (1-t)^2 & 2(1-t)t & t^2 \\\\\n                (1-t)^2 & 2(1-t)t & t^2 \\\\\n                0 & (1-t) & t \\\\\n                0 & 0 & 1\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                p_0 \\\\\n                p_1 \\\\\n                p_2\n            \\end{pmatrix}\n            =\n            \\begin{pmatrix}\n                \\vert \\\\\n                H_0 \\\\\n                \\vert \\\\\n                \\vert \\\\\n                H_1 \\\\\n                \\vert\n            \\end{pmatrix}\n\n        For the previous example with a cubic Bézier curve:\n\n        .. math::\n            H_0\n            &=\n            \\begin{pmatrix}\n                p_0 \\\\\n                (1-t) p_0 + t p_1 \\\\\n                (1-t)^2 p_0 + 2(1-t)t p_1 + t^2 p_2 \\\\\n                (1-t)^3 p_0 + 3(1-t)^2 t p_1 + 3(1-t)t^2 p_2 + t^3 p_3\n            \\end{pmatrix}\n            &=\n            \\begin{pmatrix}\n                1 & 0 & 0 & 0 \\\\\n                (1-t) & t & 0 & 0 \\\\\n                (1-t)^2 & 2(1-t)t & t^2 & 0 \\\\\n                (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                p_0 \\\\\n                p_1 \\\\\n                p_2 \\\\\n                p_3\n            \\end{pmatrix}\n            \\\\\n            &\n            \\\\\n            H_1\n            &=\n            \\begin{pmatrix}\n                (1-t)^3 p_0 + 3(1-t)^2 t p_1 + 3(1-t)t^2 p_2 + t^3 p_3 \\\\\n                (1-t)^2 p_1 + 2(1-t)t p_2 + t^2 p_3 \\\\\n                (1-t) p_2 + t p_3 \\\\\n                p_3\n            \\end{pmatrix}\n            &=\n            \\begin{pmatrix}\n                (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \\\\\n                0 & (1-t)^2 & 2(1-t)t & t^2 \\\\\n                0 & 0 & (1-t) & t \\\\\n                0 & 0 & 0 & 1\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                p_0 \\\\\n                p_1 \\\\\n                p_2 \\\\\n                p_3\n            \\end{pmatrix}\n\n        from where one can define a :math:`(8, 4)` split matrix :math:`S_3` which can multiply\n        the array of ``points`` to compute the return value:\n\n        .. math::\n            S_3\n            &=\n            \\begin{pmatrix}\n                1 & 0 & 0 & 0 \\\\\n                (1-t) & t & 0 & 0 \\\\\n                (1-t)^2 & 2(1-t)t & t^2 & 0 \\\\\n                (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \\\\\n                (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \\\\\n                0 & (1-t)^2 & 2(1-t)t & t^2 \\\\\n                0 & 0 & (1-t) & t \\\\\n                0 & 0 & 0 & 1\n            \\end{pmatrix}\n            \\\\\n            &\n            \\\\\n            S_3 P\n            &=\n            \\begin{pmatrix}\n                1 & 0 & 0 & 0 \\\\\n                (1-t) & t & 0 & 0 \\\\\n                (1-t)^2 & 2(1-t)t & t^2 & 0 \\\\\n                (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \\\\\n                (1-t)^3 & 3(1-t)^2 t & 3(1-t)t^2 & t^3 \\\\\n                0 & (1-t)^2 & 2(1-t)t & t^2 \\\\\n                0 & 0 & (1-t) & t \\\\\n                0 & 0 & 0 & 1\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                p_0 \\\\\n                p_1 \\\\\n                p_2 \\\\\n                p_3\n            \\end{pmatrix}\n            =\n            \\begin{pmatrix}\n                \\vert \\\\\n                H_0 \\\\\n                \\vert \\\\\n                \\vert \\\\\n                H_1 \\\\\n                \\vert\n            \\end{pmatrix}\n\n    Parameters\n    ----------\n    points\n        The control points of the Bézier curve.\n\n    t\n        The ``t``-value at which to split the Bézier curve.\n\n    Returns\n    -------\n    :class:`~.Point3D_Array`\n        An array containing the control points defining the two Bézier curves.\n    \"\"\"\n    points = np.asarray(points)\n    N, dim = points.shape\n    degree = N - 1\n\n    if degree == 3:\n        mt = 1 - t\n        mt2 = mt * mt\n        mt3 = mt2 * mt\n        t2 = t * t\n        t3 = t2 * t\n        two_mt_t = 2 * mt * t\n        three_mt2_t = 3 * mt2 * t\n        three_mt_t2 = 3 * mt * t2\n\n        # Split matrix S3 explained in the docstring\n        split_matrix = np.array(\n            [\n                [1, 0, 0, 0],\n                [mt, t, 0, 0],\n                [mt2, two_mt_t, t2, 0],\n                [mt3, three_mt2_t, three_mt_t2, t3],\n                [mt3, three_mt2_t, three_mt_t2, t3],\n                [0, mt2, two_mt_t, t2],\n                [0, 0, mt, t],\n                [0, 0, 0, 1],\n            ]\n        )\n\n        return split_matrix @ points\n\n    if degree == 2:\n        mt = 1 - t\n        mt2 = mt * mt\n        t2 = t * t\n        two_tmt = 2 * t * mt\n\n        # Split matrix S2 explained in the docstring\n        split_matrix = np.array(\n            [\n                [1, 0, 0],\n                [mt, t, 0],\n                [mt2, two_tmt, t2],\n                [mt2, two_tmt, t2],\n                [0, mt, t],\n                [0, 0, 1],\n            ]\n        )\n\n        return split_matrix @ points\n\n    if degree == 1:\n        middle = points[0] + t * (points[1] - points[0])\n        return np.array([points[0], middle, middle, points[1]])\n\n    if degree == 0:\n        return np.array([points[0], points[0]])\n\n    # Fallback case for nth degree Béziers\n    arr = np.empty((2, N, dim))\n    arr[1] = points\n    arr[0, 0] = points[0]\n\n    # Example for a cubic Bézier\n    # arr[0] = [P0 .. .. ..]\n    # arr[1] = [P0 P1 P2 P3]\n    for i in range(1, N):\n        # 1st iter: arr[1] = [L0 L1 L2 P3]\n        # 2nd iter: arr[1] = [Q0 Q1 L2 P3]\n        # 3rd iter: arr[1] = [C0 Q1 L2 P3]\n        arr[1, : N - i] += t * (arr[1, 1 : N - i + 1] - arr[1, : N - i])\n        # 1st iter: arr[0] = [P0 L0 .. ..]\n        # 2nd iter: arr[0] = [P0 L0 Q0 ..]\n        # 3rd iter: arr[0] = [P0 L0 Q0 C0]\n        arr[0, i] = arr[1, 0]\n\n    return arr.reshape(2 * N, dim)\n\n\n# Memos explained in subdivide_bezier docstring\nSUBDIVISION_MATRICES: list[dict[int, MatrixMN]] = [{} for i in range(4)]\n\n\ndef _get_subdivision_matrix(n_points: int, n_divisions: int) -> MatrixMN:\n    \"\"\"Gets the matrix which subdivides a Bézier curve of\n    ``n_points`` control points into ``n_divisions`` parts.\n\n    Auxiliary function for :func:`subdivide_bezier`. See its\n    docstrings for an explanation of the matrix build process.\n\n    Parameters\n    ----------\n    n_points\n        The number of control points of the Bézier curve to\n        subdivide. This function only handles up to 4 points.\n    n_divisions\n        The number of parts to subdivide the Bézier curve into.\n\n    Returns\n    -------\n    MatrixMN\n        The matrix which, upon multiplying the control points of the\n        Bézier curve, subdivides it into ``n_divisions`` parts.\n    \"\"\"\n    if n_points not in (1, 2, 3, 4):\n        raise NotImplementedError(\n            \"This function does not support subdividing Bézier \"\n            \"curves with 0 or more than 4 control points.\"\n        )\n\n    subdivision_matrix = SUBDIVISION_MATRICES[n_points - 1].get(n_divisions, None)\n    if subdivision_matrix is not None:\n        return subdivision_matrix\n\n    subdivision_matrix = np.empty((n_points * n_divisions, n_points))\n\n    # Cubic Bézier\n    if n_points == 4:\n        for i in range(n_divisions):\n            i2 = i * i\n            i3 = i2 * i\n            ip1 = i + 1\n            ip12 = ip1 * ip1\n            ip13 = ip12 * ip1\n            nmi = n_divisions - i\n            nmi2 = nmi * nmi\n            nmi3 = nmi2 * nmi\n            nmim1 = nmi - 1\n            nmim12 = nmim1 * nmim1\n            nmim13 = nmim12 * nmim1\n\n            subdivision_matrix[4 * i : 4 * (i + 1)] = np.array(\n                [\n                    [\n                        nmi3,\n                        3 * nmi2 * i,\n                        3 * nmi * i2,\n                        i3,\n                    ],\n                    [\n                        nmi2 * nmim1,\n                        2 * nmi * nmim1 * i + nmi2 * ip1,\n                        nmim1 * i2 + 2 * nmi * i * ip1,\n                        i2 * ip1,\n                    ],\n                    [\n                        nmi * nmim12,\n                        nmim12 * i + 2 * nmi * nmim1 * ip1,\n                        2 * nmim1 * i * ip1 + nmi * ip12,\n                        i * ip12,\n                    ],\n                    [\n                        nmim13,\n                        3 * nmim12 * ip1,\n                        3 * nmim1 * ip12,\n                        ip13,\n                    ],\n                ]\n            )\n        subdivision_matrix /= n_divisions * n_divisions * n_divisions\n\n    # Quadratic Bézier\n    elif n_points == 3:\n        for i in range(n_divisions):\n            ip1 = i + 1\n            nmi = n_divisions - i\n            nmim1 = nmi - 1\n            subdivision_matrix[3 * i : 3 * (i + 1)] = np.array(\n                [\n                    [nmi * nmi, 2 * i * nmi, i * i],\n                    [nmi * nmim1, i * nmim1 + ip1 * nmi, i * ip1],\n                    [nmim1 * nmim1, 2 * ip1 * nmim1, ip1 * ip1],\n                ]\n            )\n        subdivision_matrix /= n_divisions * n_divisions\n\n    # Linear Bézier (straight line)\n    elif n_points == 2:\n        aux_range = np.arange(n_divisions + 1)\n        subdivision_matrix[::2, 1] = aux_range[:-1]\n        subdivision_matrix[1::2, 1] = aux_range[1:]\n        subdivision_matrix[:, 0] = subdivision_matrix[::-1, 1]\n        subdivision_matrix /= n_divisions\n\n    # Zero-degree Bézier (single point)\n    elif n_points == 1:\n        subdivision_matrix[:] = 1\n\n    SUBDIVISION_MATRICES[n_points - 1][n_divisions] = subdivision_matrix\n    return subdivision_matrix\n\n\ndef subdivide_bezier(points: BezierPointsLike, n_divisions: int) -> Spline:\n    r\"\"\"Subdivide a Bézier curve into :math:`n` subcurves which have the same shape.\n\n    The points at which the curve is split are located at the\n    arguments :math:`t = \\frac{i}{n}`, for :math:`i \\in \\{1, ..., n-1\\}`.\n\n    .. seealso::\n\n        * See :func:`split_bezier` for an explanation on how to split Bézier curves.\n        * See :func:`partial_bezier_points` for an extra understanding of this function.\n\n\n    .. note::\n        The resulting subcurves can be expressed as linear combinations of\n        ``points``, which can be encoded in a single matrix that is precalculated\n        for 2nd and 3rd degree Bézier curves.\n\n        As an example for a quadratic Bézier curve: taking inspiration from the\n        explanation in :func:`partial_bezier_points`, where the following matrix\n        :math:`P_2` was defined to extract the portion of a quadratic Bézier\n        curve for :math:`t \\in [a, b]`:\n\n        .. math::\n            P_2\n            =\n            \\begin{pmatrix}\n                (1-a)^2 & 2(1-a)a & a^2 \\\\\n                (1-a)(1-b) & a(1-b) + (1-a)b & ab \\\\\n                (1-b)^2 & 2(1-b)b & b^2\n            \\end{pmatrix}\n\n        the plan is to replace :math:`[a, b]` with\n        :math:`\\left[ \\frac{i-1}{n}, \\frac{i}{n} \\right], \\ \\forall i \\in \\{1, ..., n\\}`.\n\n        As an example for :math:`n = 2` divisions, construct :math:`P_1` for\n        the interval :math:`\\left[ 0, \\frac{1}{2} \\right]`, and :math:`P_2` for the\n        interval :math:`\\left[ \\frac{1}{2}, 1 \\right]`:\n\n        .. math::\n            P_1\n            =\n            \\begin{pmatrix}\n                1 & 0 & 0 \\\\\n                0.5 & 0.5 & 0 \\\\\n                0.25 & 0.5 & 0.25\n            \\end{pmatrix}\n            ,\n            \\quad\n            P_2\n            =\n            \\begin{pmatrix}\n                0.25 & 0.5 & 0.25 \\\\\n                0 & 0.5 & 0.5 \\\\\n                0 & 0 & 1\n            \\end{pmatrix}\n\n        Therefore, the following :math:`(6, 3)` subdivision matrix :math:`D_2` can be\n        constructed, which will subdivide an array of ``points`` into 2 parts:\n\n        .. math::\n            D_2\n            =\n            \\begin{pmatrix}\n                M_1 \\\\\n                M_2\n            \\end{pmatrix}\n            =\n            \\begin{pmatrix}\n                1 & 0 & 0 \\\\\n                0.5 & 0.5 & 0 \\\\\n                0.25 & 0.5 & 0.25 \\\\\n                0.25 & 0.5 & 0.25 \\\\\n                0 & 0.5 & 0.5 \\\\\n                0 & 0 & 1\n            \\end{pmatrix}\n\n        For quadratic and cubic Bézier curves, the subdivision matrices are memoized for\n        efficiency. For higher degree curves, an iterative algorithm inspired by the\n        one from :func:`split_bezier` is used instead.\n\n    .. image:: /_static/bezier_subdivision_example.png\n\n    Parameters\n    ----------\n    points\n        The control points of the Bézier curve.\n\n    n_divisions\n        The number of curves to subdivide the Bézier curve into\n\n    Returns\n    -------\n    :class:`~.Spline`\n        An array containing the points defining the new :math:`n` subcurves.\n    \"\"\"\n    points = np.asarray(points)\n    if n_divisions == 1:\n        return points\n\n    N, dim = points.shape\n\n    if N <= 4:\n        subdivision_matrix = _get_subdivision_matrix(N, n_divisions)\n        return subdivision_matrix @ points\n\n    # Fallback case for an nth degree Bézier: successive splitting\n    beziers = np.empty((n_divisions, N, dim))\n    beziers[-1] = points\n    for curve_num in range(n_divisions - 1, 0, -1):\n        curr = beziers[curve_num]\n        prev = beziers[curve_num - 1]\n        prev[0] = curr[0]\n        a = (n_divisions - curve_num) / (n_divisions - curve_num + 1)\n        # Current state for an example cubic Bézier curve:\n        # prev = [P0 .. .. ..]\n        # curr = [P0 P1 P2 P3]\n        for i in range(1, N):\n            # 1st iter: curr = [L0 L1 L2 P3]\n            # 2nd iter: curr = [Q0 Q1 L2 P3]\n            # 3rd iter: curr = [C0 Q1 L2 P3]\n            curr[: N - i] += a * (curr[1 : N - i + 1] - curr[: N - i])\n            # 1st iter: prev = [P0 L0 .. ..]\n            # 2nd iter: prev = [P0 L0 Q0 ..]\n            # 3rd iter: prev = [P0 L0 Q0 C0]\n            prev[i] = curr[0]\n\n    return beziers.reshape(n_divisions * N, dim)\n\n\ndef bezier_remap(\n    bezier_tuples: BezierPointsLike_Array,\n    new_number_of_curves: int,\n) -> BezierPoints_Array:\n    \"\"\"Subdivides each curve in ``bezier_tuples`` into as many parts as necessary, until the final number of\n    curves reaches a desired amount, ``new_number_of_curves``.\n\n    Parameters\n    ----------\n    bezier_tuples\n        An array of multiple Bézier curves of degree :math:`d` to be remapped. The shape of this array\n        must be ``(current_number_of_curves, nppc, dim)``, where:\n\n        *   ``current_number_of_curves`` is the current amount of curves in the array ``bezier_tuples``,\n        *   ``nppc`` is the amount of points per curve, such that their degree is ``nppc-1``, and\n        *   ``dim`` is the dimension of the points, usually :math:`3`.\n\n    new_number_of_curves\n        The number of curves that the output will contain. This needs to be higher than the current number.\n\n    Returns\n    -------\n    :class:`~.BezierPoints_Array`\n        The new array of shape ``(new_number_of_curves, nppc, dim)``,\n        containing the new Bézier curves after the remap.\n    \"\"\"\n    bezier_tuples = np.asarray(bezier_tuples)\n    current_number_of_curves, nppc, dim = bezier_tuples.shape\n    # This is an array with values ranging from 0\n    # up to curr_num_curves,  with repeats such that\n    # its total length is target_num_curves.  For example,\n    # with curr_num_curves = 10, target_num_curves = 15, this\n    # would be [0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9].\n    repeat_indices = (\n        np.arange(new_number_of_curves, dtype=\"i\") * current_number_of_curves\n    ) // new_number_of_curves\n\n    # If the nth term of this list is k, it means\n    # that the nth curve of our path should be split\n    # into k pieces.\n    # In the above example our array had the following elements\n    # [0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9]\n    # We have two 0s, one 1, two 2s and so on.\n    # The split factors array would hence be:\n    # [2, 1, 2, 1, 2, 1, 2, 1, 2, 1]\n    split_factors = np.zeros(current_number_of_curves, dtype=\"i\")\n    np.add.at(split_factors, repeat_indices, 1)\n\n    new_tuples = np.empty((new_number_of_curves, nppc, dim))\n    index = 0\n    for curve, sf in zip(bezier_tuples, split_factors, strict=True):\n        new_tuples[index : index + sf] = subdivide_bezier(curve, sf).reshape(\n            sf, nppc, dim\n        )\n        index += sf\n\n    return new_tuples\n\n\n# Linear interpolation variants\n\n\n@overload\ndef interpolate(start: float, end: float, alpha: float) -> float: ...\n\n\n@overload\ndef interpolate(start: float, end: float, alpha: ColVector) -> ColVector: ...\n\n\n@overload\ndef interpolate(start: Point3D, end: Point3D, alpha: float) -> Point3D: ...\n\n\n@overload\ndef interpolate(start: Point3D, end: Point3D, alpha: ColVector) -> Point3D_Array: ...\n\n\ndef interpolate(\n    start: float | Point3D,\n    end: float | Point3D,\n    alpha: float | ColVector,\n) -> float | ColVector | Point3D | Point3D_Array:\n    \"\"\"Linearly interpolates between two values ``start`` and ``end``.\n\n    Parameters\n    ----------\n    start\n        The start of the range.\n    end\n        The end of the range.\n    alpha\n        A float between 0 and 1, or an :math:`(n, 1)` column vector containing\n        :math:`n` floats between 0 and 1 to interpolate in a vectorized fashion.\n\n    Returns\n    -------\n    :class:`float` | :class:`~.ColVector` | :class:`~.Point3D` | :class:`~.Point3D_Array`\n        The result of the linear interpolation.\n\n        *   If ``start`` and ``end`` are of type :class:`float`, and:\n\n            * ``alpha`` is also a :class:`float`, the return is simply another :class:`float`.\n            * ``alpha`` is a :class:`~.ColVector`, the return is another :class:`~.ColVector`.\n\n        *   If ``start`` and ``end`` are of type :class:`~.Point3D`, and:\n\n            * ``alpha`` is a :class:`float`, the return is another :class:`~.Point3D`.\n            * ``alpha`` is a :class:`~.ColVector`, the return is a :class:`~.Point3D_Array`.\n    \"\"\"\n    return (1 - alpha) * start + alpha * end\n\n\ndef integer_interpolate(\n    start: float,\n    end: float,\n    alpha: float,\n) -> tuple[int, float]:\n    \"\"\"\n    This is a variant of interpolate that returns an integer and the residual\n\n    Parameters\n    ----------\n    start\n        The start of the range\n    end\n        The end of the range\n    alpha\n        a float between 0 and 1.\n\n    Returns\n    -------\n    tuple[int, float]\n        This returns an integer between start and end (inclusive) representing\n        appropriate interpolation between them, along with a\n        \"residue\" representing a new proportion between the\n        returned integer and the next one of the\n        list.\n\n    Example\n    -------\n\n    .. code-block:: pycon\n\n        >>> integer, residue = integer_interpolate(start=0, end=10, alpha=0.46)\n        >>> np.allclose((integer, residue), (4, 0.6))\n        True\n    \"\"\"\n    if alpha >= 1:\n        return (int(end - 1), 1.0)\n    if alpha <= 0:\n        return (int(start), 0)\n    value = int(interpolate(start, end, alpha))\n    residue = ((end - start) * alpha) % 1\n    return (value, residue)\n\n\n@overload\ndef mid(start: float, end: float) -> float: ...\n\n\n@overload\ndef mid(start: Point3D, end: Point3D) -> Point3D: ...\n\n\ndef mid(start: float | Point3D, end: float | Point3D) -> float | Point3D:\n    \"\"\"Returns the midpoint between two values.\n\n    Parameters\n    ----------\n    start\n        The first value\n    end\n        The second value\n\n    Returns\n    -------\n        The midpoint between the two values\n    \"\"\"\n    return (start + end) / 2.0\n\n\n@overload\ndef inverse_interpolate(start: float, end: float, value: float) -> float: ...\n\n\n@overload\ndef inverse_interpolate(start: float, end: float, value: Point3D) -> Point3D: ...\n\n\n@overload\ndef inverse_interpolate(start: Point3D, end: Point3D, value: Point3D) -> Point3D: ...\n\n\ndef inverse_interpolate(\n    start: float | Point3D,\n    end: float | Point3D,\n    value: float | Point3D,\n) -> float | Point3D:\n    \"\"\"Perform inverse interpolation to determine the alpha\n    values that would produce the specified ``value``\n    given the ``start`` and ``end`` values or points.\n\n    Parameters\n    ----------\n    start\n        The start value or point of the interpolation.\n    end\n        The end value or point of the interpolation.\n    value\n        The value or point for which the alpha value\n        should be determined.\n\n    Returns\n    -------\n        The alpha values producing the given input\n        when interpolating between ``start`` and ``end``.\n\n    Example\n    -------\n\n    .. code-block:: pycon\n\n        >>> inverse_interpolate(start=2, end=6, value=4)\n        np.float64(0.5)\n\n        >>> start = np.array([1, 2, 1])\n        >>> end = np.array([7, 8, 11])\n        >>> value = np.array([4, 5, 5])\n        >>> inverse_interpolate(start, end, value)\n        array([0.5, 0.5, 0.4])\n    \"\"\"\n    return np.true_divide(value - start, end - start)\n\n\n@overload\ndef match_interpolate(\n    new_start: float,\n    new_end: float,\n    old_start: float,\n    old_end: float,\n    old_value: float,\n) -> float: ...\n\n\n@overload\ndef match_interpolate(\n    new_start: float,\n    new_end: float,\n    old_start: float,\n    old_end: float,\n    old_value: Point3D,\n) -> Point3D: ...\n\n\ndef match_interpolate(\n    new_start: float,\n    new_end: float,\n    old_start: float,\n    old_end: float,\n    old_value: float | Point3D,\n) -> float | Point3D:\n    \"\"\"Interpolate a value from an old range to a new range.\n\n    Parameters\n    ----------\n    new_start\n        The start of the new range.\n    new_end\n        The end of the new range.\n    old_start\n        The start of the old range.\n    old_end\n        The end of the old range.\n    old_value\n        The value within the old range whose corresponding\n        value in the new range (with the same alpha value)\n        is desired.\n\n    Returns\n    -------\n        The interpolated value within the new range.\n\n    Examples\n    --------\n    >>> from manim import match_interpolate\n    >>> match_interpolate(0, 100, 10, 20, 15)\n    np.float64(50.0)\n    \"\"\"\n    old_alpha = inverse_interpolate(old_start, old_end, old_value)\n    return interpolate(\n        new_start,\n        new_end,\n        old_alpha,\n    )\n\n\n# Figuring out which Bézier curves most smoothly connect a sequence of points\ndef get_smooth_cubic_bezier_handle_points(\n    anchors: Point3DLike_Array,\n) -> tuple[Point3D_Array, Point3D_Array]:\n    \"\"\"Given an array of anchors for a cubic spline (array of connected cubic\n    Bézier curves), compute the 1st and 2nd handle for every curve, so that\n    the resulting spline is smooth.\n\n    Parameters\n    ----------\n    anchors\n        Anchors of a cubic spline.\n\n    Returns\n    -------\n    :class:`tuple` [:class:`~.Point3D_Array`, :class:`~.Point3D_Array`]\n        A tuple of two arrays: one containing the 1st handle for every curve in\n        the cubic spline, and the other containing the 2nd handles.\n    \"\"\"\n    anchors = np.asarray(anchors)\n    n_anchors = anchors.shape[0]\n\n    # If there's a single anchor, there's no Bézier curve.\n    # Return empty arrays.\n    if n_anchors == 1:\n        dim = anchors.shape[1]\n        return np.zeros((0, dim)), np.zeros((0, dim))\n\n    # If there are only two anchors (thus only one pair of handles),\n    # they can only be an interpolation of these two anchors with alphas\n    # 1/3 and 2/3, which will draw a straight line between the anchors.\n    if n_anchors == 2:\n        val = interpolate(anchors[0], anchors[1], np.array([[1 / 3], [2 / 3]]))\n        return (val[0], val[1])\n\n    # Handle different cases depending on whether the points form a closed\n    # curve or not\n    curve_is_closed = is_closed(anchors)\n    if curve_is_closed:\n        return get_smooth_closed_cubic_bezier_handle_points(anchors)\n    else:\n        return get_smooth_open_cubic_bezier_handle_points(anchors)\n\n\nCP_CLOSED_MEMO = np.array([1 / 3])\nUP_CLOSED_MEMO = np.array([1 / 3])\n\n\ndef get_smooth_closed_cubic_bezier_handle_points(\n    anchors: Point3DLike_Array,\n) -> tuple[Point3D_Array, Point3D_Array]:\n    r\"\"\"Special case of :func:`get_smooth_cubic_bezier_handle_points`,\n    when the ``anchors`` form a closed loop.\n\n    .. note::\n        A system of equations must be solved to get the first handles of\n        every Bézier curve (referred to as :math:`H_1`).\n        Then :math:`H_2` (the second handles) can be obtained separately.\n\n        .. seealso::\n            The equations were obtained from:\n\n            * `Conditions on control points for continuous curvature. (2016). Jaco Stuifbergen. <http://www.jacos.nl/jacos_html/spline/theory/theory_2.html>`_\n\n        In general, if there are :math:`N+1` anchors, there will be :math:`N` Bézier curves\n        and thus :math:`N` pairs of handles to find. We must solve the following\n        system of equations for the 1st handles (example for :math:`N = 5`):\n\n        .. math::\n            \\begin{pmatrix}\n                4 & 1 & 0 & 0 & 1 \\\\\n                1 & 4 & 1 & 0 & 0 \\\\\n                0 & 1 & 4 & 1 & 0 \\\\\n                0 & 0 & 1 & 4 & 1 \\\\\n                1 & 0 & 0 & 1 & 4\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                H_{1,0} \\\\\n                H_{1,1} \\\\\n                H_{1,2} \\\\\n                H_{1,3} \\\\\n                H_{1,4}\n            \\end{pmatrix}\n            =\n            \\begin{pmatrix}\n                4A_0 + 2A_1 \\\\\n                4A_1 + 2A_2 \\\\\n                4A_2 + 2A_3 \\\\\n                4A_3 + 2A_4 \\\\\n                4A_4 + 2A_5\n            \\end{pmatrix}\n\n        which will be expressed as :math:`RH_1 = D`.\n\n        :math:`R` is almost a tridiagonal matrix, so we could use Thomas' algorithm.\n\n        .. seealso::\n            `Tridiagonal matrix algorithm. Wikipedia. <https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm>`_\n\n        However, :math:`R` has ones at the opposite corners. A solution to this is\n        the first decomposition proposed in the link below, with :math:`\\alpha = 1`:\n\n        .. seealso::\n            `Tridiagonal matrix algorithm # Variants. Wikipedia. <https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm#Variants>`_\n\n        .. math::\n            R\n            =\n            \\begin{pmatrix}\n                4 & 1 & 0 & 0 & 1 \\\\\n                1 & 4 & 1 & 0 & 0 \\\\\n                0 & 1 & 4 & 1 & 0 \\\\\n                0 & 0 & 1 & 4 & 1 \\\\\n                1 & 0 & 0 & 1 & 4\n            \\end{pmatrix}\n            &=\n            \\begin{pmatrix}\n                3 & 1 & 0 & 0 & 0 \\\\\n                1 & 4 & 1 & 0 & 0 \\\\\n                0 & 1 & 4 & 1 & 0 \\\\\n                0 & 0 & 1 & 4 & 1 \\\\\n                0 & 0 & 0 & 1 & 3\n            \\end{pmatrix}\n            +\n            \\begin{pmatrix}\n                1 & 0 & 0 & 0 & 1 \\\\\n                0 & 0 & 0 & 0 & 0 \\\\\n                0 & 0 & 0 & 0 & 0 \\\\\n                0 & 0 & 0 & 0 & 0 \\\\\n                1 & 0 & 0 & 0 & 1\n            \\end{pmatrix}\n            \\\\\n            &\n            \\\\\n            &=\n            \\begin{pmatrix}\n                3 & 1 & 0 & 0 & 0 \\\\\n                1 & 4 & 1 & 0 & 0 \\\\\n                0 & 1 & 4 & 1 & 0 \\\\\n                0 & 0 & 1 & 4 & 1 \\\\\n                0 & 0 & 0 & 1 & 3\n            \\end{pmatrix}\n            +\n            \\begin{pmatrix}\n                1 \\\\\n                0 \\\\\n                0 \\\\\n                0 \\\\\n                1\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                1 & 0 & 0 & 0 & 1\n            \\end{pmatrix}\n            \\\\\n            &\n            \\\\\n            &=\n            T + uv^t\n\n        We decompose :math:`R = T + uv^t`, where :math:`T` is a tridiagonal matrix, and\n        :math:`u, v` are :math:`N`-D vectors such that :math:`u_0 = u_{N-1} = v_0 = v_{N-1} = 1`,\n        and :math:`u_i = v_i = 0, \\forall i \\in \\{1, ..., N-2\\}`.\n\n        Thus:\n\n        .. math::\n            RH_1 &= D \\\\\n            \\Rightarrow (T + uv^t)H_1 &= D\n\n        If we find a vector :math:`q` such that :math:`Tq = u`:\n\n        .. math::\n            \\Rightarrow (T + Tqv^t)H_1 &= D \\\\\n            \\Rightarrow T(I + qv^t)H_1 &= D \\\\\n            \\Rightarrow H_1 &= (I + qv^t)^{-1} T^{-1} D\n\n        According to Sherman-Morrison's formula:\n\n        .. seealso::\n            `Sherman-Morrison's formula. Wikipedia. <https://en.wikipedia.org/wiki/Sherman%E2%80%93Morrison_formula>`_\n\n        .. math::\n            (I + qv^t)^{-1} = I - \\frac{1}{1 + v^tq} qv^t\n\n        If we find :math:`Y = T^{-1} D`, or in other words, if we solve for\n        :math:`Y` in :math:`TY = D`:\n\n        .. math::\n            H_1 &= (I + qv^t)^{-1} T^{-1} D \\\\\n            &= (I + qv^t)^{-1} Y \\\\\n            &= (I - \\frac{1}{1 + v^tq} qv^t) Y \\\\\n            &= Y - \\frac{1}{1 + v^tq} qv^tY\n\n        Therefore, we must solve for :math:`q` and :math:`Y` in :math:`Tq = u` and :math:`TY = D`.\n        As :math:`T` is now tridiagonal, we shall use Thomas' algorithm.\n\n        Define:\n\n        *   :math:`a = [a_0, \\ a_1, \\ ..., \\ a_{N-2}]` as :math:`T`'s lower diagonal of :math:`N-1` elements,\n            such that :math:`a_0 = a_1 = ... = a_{N-2} = 1`, so this diagonal is filled with ones;\n        *   :math:`b = [b_0, \\ b_1, \\ ..., \\ b_{N-2}, \\ b_{N-1}]` as :math:`T`'s main diagonal of :math:`N` elements,\n            such that :math:`b_0 = b_{N-1} = 3`, and :math:`b_1 = b_2 = ... = b_{N-2} = 4`;\n        *   :math:`c = [c_0, \\ c_1, \\ ..., \\ c_{N-2}]` as :math:`T`'s upper diagonal of :math:`N-1` elements,\n            such that :math:`c_0 = c_1 = ... = c_{N-2} = 1`: this diagonal is also filled with ones.\n\n        If, according to Thomas' algorithm, we define:\n\n        .. math::\n            c'_0 &= \\frac{c_0}{b_0} & \\\\\n            c'_i &= \\frac{c_i}{b_i - a_{i-1} c'_{i-1}}, & \\quad \\forall i \\in \\{1, ..., N-2\\} \\\\\n            & & \\\\\n            u'_0 &= \\frac{u_0}{b_0} & \\\\\n            u'_i &= \\frac{u_i - a_{i-1} u'_{i-1}}{b_i - a_{i-1} c'_{i-1}}, & \\quad \\forall i \\in \\{1, ..., N-1\\} \\\\\n            & & \\\\\n            D'_0 &= \\frac{1}{b_0} D_0 & \\\\\n            D'_i &= \\frac{1}{b_i - a_{i-1} c'_{i-1}} (D_i - a_{i-1} D'_{i-1}), & \\quad \\forall i \\in \\{1, ..., N-1\\}\n\n        Then:\n\n        .. math::\n            c'_0     &= \\frac{1}{3} & \\\\\n            c'_i     &= \\frac{1}{4 - c'_{i-1}}, & \\quad \\forall i \\in \\{1, ..., N-2\\} \\\\\n            & & \\\\\n            u'_0     &= \\frac{1}{3} & \\\\\n            u'_i     &= \\frac{-u'_{i-1}}{4 - c'_{i-1}} = -c'_i u'_{i-1}, & \\quad \\forall i \\in \\{1, ..., N-2\\} \\\\\n            u'_{N-1} &= \\frac{1 - u'_{N-2}}{3 - c'_{N-2}} & \\\\\n            & & \\\\\n            D'_0     &= \\frac{1}{3} (4A_0 + 2A_1) & \\\\\n            D'_i     &= \\frac{1}{4 - c'_{i-1}} (4A_i + 2A_{i+1} - D'_{i-1}) & \\\\\n            &= c_i (4A_i + 2A_{i+1} - D'_{i-1}), & \\quad \\forall i \\in \\{1, ..., N-2\\} \\\\\n            D'_{N-1} &= \\frac{1}{3 - c'_{N-2}} (4A_{N-1} + 2A_N - D'_{N-2}) &\n\n        Finally, we can do Backward Substitution to find :math:`q` and :math:`Y`:\n\n        .. math::\n            q_{N-1} &= u'_{N-1} & \\\\\n            q_i     &= u'_{i} - c'_i q_{i+1}, & \\quad \\forall i \\in \\{0, ..., N-2\\} \\\\\n            & & \\\\\n            Y_{N-1} &= D'_{N-1} & \\\\\n            Y_i     &= D'_i - c'_i Y_{i+1},   & \\quad \\forall i \\in \\{0, ..., N-2\\}\n\n        With those values, we can finally calculate :math:`H_1 = Y - \\frac{1}{1 + v^tq} qv^tY`.\n        Given that :math:`v_0 = v_{N-1} = 1`, and :math:`v_1 = v_2 = ... = v_{N-2} = 0`, its dot products\n        with :math:`q` and :math:`Y` are respectively :math:`v^tq = q_0 + q_{N-1}` and\n        :math:`v^tY = Y_0 + Y_{N-1}`. Thus:\n\n        .. math::\n            H_1 = Y - \\frac{1}{1 + q_0 + q_{N-1}} q(Y_0 + Y_{N-1})\n\n        Once we have :math:`H_1`, we can get :math:`H_2` (the array of second handles) as follows:\n\n        .. math::\n            H_{2, i}   &= 2A_{i+1} - H_{1, i+1}, & \\quad \\forall i \\in \\{0, ..., N-2\\} \\\\\n            H_{2, N-1} &= 2A_0 - H_{1, 0} &\n\n        Because the matrix :math:`R` always follows the same pattern (and thus :math:`T, u, v` as well),\n        we can define a memo list for :math:`c'` and :math:`u'` to avoid recalculation. We cannot\n        memoize :math:`D` and :math:`Y`, however, because they are always different matrices. We\n        cannot make a memo for :math:`q` either, but we can calculate it faster because :math:`u'`\n        can be memoized.\n\n    Parameters\n    ----------\n    anchors\n        Anchors of a closed cubic spline.\n\n    Returns\n    -------\n    :class:`tuple` [:class:`~.Point3D_Array`, :class:`~.Point3D_Array`]\n        A tuple of two arrays: one containing the 1st handle for every curve in\n        the closed cubic spline, and the other containing the 2nd handles.\n    \"\"\"\n    global CP_CLOSED_MEMO\n    global UP_CLOSED_MEMO\n\n    A = np.asarray(anchors)\n    N = A.shape[0] - 1\n    dim = A.shape[1]\n\n    # Calculate cp (c prime) and up (u prime) with help from\n    # CP_CLOSED_MEMO and UP_CLOSED_MEMO.\n    len_memo = CP_CLOSED_MEMO.size\n    if len_memo < N - 1:\n        cp = np.empty(N - 1)\n        up = np.empty(N - 1)\n        cp[:len_memo] = CP_CLOSED_MEMO\n        up[:len_memo] = UP_CLOSED_MEMO\n        # Forward Substitution 1\n        # Calculate up (at the same time we calculate cp).\n        for i in range(len_memo, N - 1):\n            cp[i] = 1 / (4 - cp[i - 1])\n            up[i] = -cp[i] * up[i - 1]\n        CP_CLOSED_MEMO = cp\n        UP_CLOSED_MEMO = up\n    else:\n        cp = CP_CLOSED_MEMO[: N - 1]\n        up = UP_CLOSED_MEMO[: N - 1]\n\n    # The last element of u' is different\n    cp_last_division = 1 / (3 - cp[N - 2])\n    up_last = cp_last_division * (1 - up[N - 2])\n\n    # Backward Substitution 1\n    # Calculate q.\n    q = np.empty((N, dim))\n    q[N - 1] = up_last\n    for i in range(N - 2, -1, -1):\n        q[i] = up[i] - cp[i] * q[i + 1]\n\n    # Forward Substitution 2\n    # Calculate Dp (D prime).\n    Dp = np.empty((N, dim))\n    AUX = 4 * A[:N] + 2 * A[1:]  # Vectorize the sum for efficiency.\n    Dp[0] = AUX[0] / 3\n    for i in range(1, N - 1):\n        Dp[i] = cp[i] * (AUX[i] - Dp[i - 1])\n    Dp[N - 1] = cp_last_division * (AUX[N - 1] - Dp[N - 2])\n\n    # Backward Substitution\n    # Calculate Y, which is defined as a view of Dp for efficiency\n    # and semantic convenience at the same time.\n    Y = Dp\n    # Y[N-1] = Dp[N-1] (redundant)\n    for i in range(N - 2, -1, -1):\n        Y[i] = Dp[i] - cp[i] * Y[i + 1]\n\n    # Calculate H1.\n    H1 = Y - 1 / (1 + q[0] + q[N - 1]) * q * (Y[0] + Y[N - 1])\n\n    # Calculate H2.\n    H2 = np.empty((N, dim))\n    H2[0 : N - 1] = 2 * A[1:N] - H1[1:N]\n    H2[N - 1] = 2 * A[N] - H1[0]\n\n    return H1, H2\n\n\nCP_OPEN_MEMO = np.array([0.5])\n\n\ndef get_smooth_open_cubic_bezier_handle_points(\n    anchors: Point3DLike_Array,\n) -> tuple[Point3D_Array, Point3D_Array]:\n    r\"\"\"Special case of :func:`get_smooth_cubic_bezier_handle_points`,\n    when the ``anchors`` do not form a closed loop.\n\n    .. note::\n        A system of equations must be solved to get the first handles of\n        every Bèzier curve (referred to as :math:`H_1`).\n        Then :math:`H_2` (the second handles) can be obtained separately.\n\n        .. seealso::\n            The equations were obtained from:\n\n            * `Smooth Bézier Spline Through Prescribed Points. (2012). Particle in Cell Consulting LLC. <https://www.particleincell.com/2012/bezier-splines/>`_\n            * `Conditions on control points for continuous curvature. (2016). Jaco Stuifbergen. <http://www.jacos.nl/jacos_html/spline/theory/theory_2.html>`_\n\n        .. warning::\n            The equations in the first webpage have some typos which were corrected in the comments.\n\n        In general, if there are :math:`N+1` anchors, there will be :math:`N` Bézier curves\n        and thus :math:`N` pairs of handles to find. We must solve the following\n        system of equations for the 1st handles (example for :math:`N = 5`):\n\n        .. math::\n            \\begin{pmatrix}\n                2 & 1 & 0 & 0 & 0 \\\\\n                1 & 4 & 1 & 0 & 0 \\\\\n                0 & 1 & 4 & 1 & 0 \\\\\n                0 & 0 & 1 & 4 & 1 \\\\\n                0 & 0 & 0 & 2 & 7\n            \\end{pmatrix}\n            \\begin{pmatrix}\n                H_{1,0} \\\\\n                H_{1,1} \\\\\n                H_{1,2} \\\\\n                H_{1,3} \\\\\n                H_{1,4}\n            \\end{pmatrix}\n            =\n            \\begin{pmatrix}\n                A_0 + 2A_1 \\\\\n                4A_1 + 2A_2 \\\\\n                4A_2 + 2A_3 \\\\\n                4A_3 + 2A_4 \\\\\n                8A_4 + A_5\n            \\end{pmatrix}\n\n        which will be expressed as :math:`TH_1 = D`.\n        :math:`T` is a tridiagonal matrix, so the system can be solved in :math:`O(N)`\n        operations. Here we shall use Thomas' algorithm or the tridiagonal matrix\n        algorithm.\n\n        .. seealso::\n            `Tridiagonal matrix algorithm. Wikipedia. <https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm>`_\n\n        Define:\n\n        *   :math:`a = [a_0, \\ a_1, \\ ..., \\ a_{N-2}]` as :math:`T`'s lower diagonal of :math:`N-1` elements,\n            such that :math:`a_0 = a_1 = ... = a_{N-3} = 1`, and :math:`a_{N-2} = 2`;\n        *   :math:`b = [b_0, \\ b_1, \\ ..., \\ b_{N-2}, \\ b_{N-1}]` as :math:`T`'s main diagonal of :math:`N` elements,\n            such that :math:`b_0 = 2`, :math:`b_1 = b_2 = ... = b_{N-2} = 4`, and :math:`b_{N-1} = 7`;\n        *   :math:`c = [c_0, \\ c_1, \\ ..., \\ c_{N-2}]` as :math:`T`'s upper diagonal of :math:`{N-1}` elements,\n            such that :math:`c_0 = c_1 = ... = c_{N-2} = 1`: this diagonal is filled with ones.\n\n        If, according to Thomas' algorithm, we define:\n\n        .. math::\n            c'_0 &= \\frac{c_0}{b_0} & \\\\\n            c'_i &= \\frac{c_i}{b_i - a_{i-1} c'_{i-1}}, & \\quad \\forall i \\in \\{1, ..., N-2\\} \\\\\n            & & \\\\\n            D'_0 &= \\frac{1}{b_0} D_0 & \\\\\n            D'_i &= \\frac{1}{b_i - a_{i-1} c'{i-1}} (D_i - a_{i-1} D'_{i-1}), & \\quad \\forall i \\in \\{1, ..., N-1\\}\n\n        Then:\n\n        .. math::\n            c'_0     &= 0.5 & \\\\\n            c'_i     &= \\frac{1}{4 - c'_{i-1}}, & \\quad \\forall i \\in \\{1, ..., N-2\\} \\\\\n            & & \\\\\n            D'_0     &= 0.5A_0 + A_1 & \\\\\n            D'_i     &= \\frac{1}{4 - c'_{i-1}} (4A_i + 2A_{i+1} - D'_{i-1}) & \\\\\n            &= c_i (4A_i + 2A_{i+1} - D'_{i-1}), & \\quad \\forall i \\in \\{1, ..., N-2\\} \\\\\n            D'_{N-1} &= \\frac{1}{7 - 2c'_{N-2}} (8A_{N-1} + A_N - 2D'_{N-2}) &\n\n        Finally, we can do Backward Substitution to find :math:`H_1`:\n\n        .. math::\n            H_{1, N-1} &= D'_{N-1} & \\\\\n            H_{1, i}   &= D'_i - c'_i H_{1, i+1}, & \\quad \\forall i \\in \\{0, ..., N-2\\}\n\n        Once we have :math:`H_1`, we can get :math:`H_2` (the array of second handles) as follows:\n\n        .. math::\n            H_{2, i}   &= 2A_{i+1} - H_{1, i+1}, & \\quad \\forall i \\in \\{0, ..., N-2\\} \\\\\n            H_{2, N-1} &= 0.5A_N   + 0.5H_{1, N-1} &\n\n        As the matrix :math:`T` always follows the same pattern, we can define a memo list\n        for :math:`c'` to avoid recalculation. We cannot do the same for :math:`D`, however,\n        because it is always a different matrix.\n\n    Parameters\n    ----------\n    anchors\n        Anchors of an open cubic spline.\n\n    Returns\n    -------\n    :class:`tuple` [:class:`~.Point3D_Array`, :class:`~.Point3D_Array`]\n        A tuple of two arrays: one containing the 1st handle for every curve in\n        the open cubic spline, and the other containing the 2nd handles.\n    \"\"\"\n    global CP_OPEN_MEMO\n\n    A = np.asarray(anchors)\n    N = A.shape[0] - 1\n    dim = A.shape[1]\n\n    # Calculate cp (c prime) with help from CP_OPEN_MEMO.\n    len_memo = CP_OPEN_MEMO.size\n    if len_memo < N - 1:\n        cp = np.empty(N - 1)\n        cp[:len_memo] = CP_OPEN_MEMO\n        for i in range(len_memo, N - 1):\n            cp[i] = 1 / (4 - cp[i - 1])\n        CP_OPEN_MEMO = cp\n    else:\n        cp = CP_OPEN_MEMO[: N - 1]\n\n    # Calculate Dp (D prime).\n    Dp = np.empty((N, dim))\n    Dp[0] = 0.5 * A[0] + A[1]\n    AUX = 4 * A[1 : N - 1] + 2 * A[2:N]  # Vectorize the sum for efficiency.\n    for i in range(1, N - 1):\n        Dp[i] = cp[i] * (AUX[i - 1] - Dp[i - 1])\n    Dp[N - 1] = (1 / (7 - 2 * cp[N - 2])) * (8 * A[N - 1] + A[N] - 2 * Dp[N - 2])\n\n    # Backward Substitution.\n    # H1 (array of the first handles) is defined as a view of Dp for efficiency\n    # and semantic convenience at the same time.\n    H1 = Dp\n    # H1[N-1] = Dp[N-1] (redundant)\n    for i in range(N - 2, -1, -1):\n        H1[i] = Dp[i] - cp[i] * H1[i + 1]\n\n    # Calculate H2.\n    H2 = np.empty((N, dim))\n    H2[0 : N - 1] = 2 * A[1:N] - H1[1:N]\n    H2[N - 1] = 0.5 * (A[N] + H1[N - 1])\n\n    return H1, H2\n\n\n@overload\ndef get_quadratic_approximation_of_cubic(\n    a0: Point3DLike, h0: Point3DLike, h1: Point3DLike, a1: Point3DLike\n) -> QuadraticSpline: ...\n\n\n@overload\ndef get_quadratic_approximation_of_cubic(\n    a0: Point3DLike_Array,\n    h0: Point3DLike_Array,\n    h1: Point3DLike_Array,\n    a1: Point3DLike_Array,\n) -> QuadraticBezierPath: ...\n\n\ndef get_quadratic_approximation_of_cubic(\n    a0: Point3D | Point3D_Array,\n    h0: Point3D | Point3D_Array,\n    h1: Point3D | Point3D_Array,\n    a1: Point3D | Point3D_Array,\n) -> QuadraticSpline | QuadraticBezierPath:\n    r\"\"\"If ``a0``, ``h0``, ``h1`` and ``a1`` are the control points of a cubic\n    Bézier curve, approximate the curve with two quadratic Bézier curves and\n    return an array of 6 points, where the first 3 points represent the first\n    quadratic curve and the last 3 represent the second one.\n\n    Otherwise, if ``a0``, ``h0``, ``h1`` and ``a1`` are _arrays_ of :math:`N`\n    points representing :math:`N` cubic Bézier curves, return an array of\n    :math:`6N` points where each group of :math:`6` consecutive points\n    approximates each of the :math:`N` curves in a similar way as above.\n\n    .. note::\n        If the cubic spline given by the original cubic Bézier curves is\n        smooth, this algorithm will generate a quadratic spline which is also\n        smooth.\n\n        If a cubic Bézier is given by\n\n        .. math::\n            C(t) = (1-t)^3 A_0 + 3(1-t)^2 t H_0 + 3(1-t)t^2 H_1 + t^3 A_1\n\n        where :math:`A_0`, :math:`H_0`, :math:`H_1` and :math:`A_1` are its\n        control points, then this algorithm should generate two quadratic\n        Béziers given by\n\n        .. math::\n            Q_0(t) &= (1-t)^2 A_0 + 2(1-t)t M_0 + t^2 K \\\\\n            Q_1(t) &= (1-t)^2 K + 2(1-t)t M_1 + t^2 A_1\n\n        where :math:`M_0` and :math:`M_1` are the respective handles to be\n        found for both curves, and :math:`K` is the end anchor of the 1st curve\n        and the start anchor of the 2nd, which must also be found.\n\n        To solve for :math:`M_0`, :math:`M_1` and :math:`K`, three conditions\n        can be imposed:\n\n        1.  :math:`Q_0'(0) = \\frac{1}{2}C'(0)`. The derivative of the first\n            quadratic curve at :math:`t = 0` should be proportional to that of\n            the original cubic curve, also at :math:`t = 0`. Because the cubic\n            curve is split into two parts, it is necessary to divide this by\n            two: the speed of a point travelling through the curve should be\n            half of the original. This gives:\n\n            .. math::\n                Q_0'(0) &= \\frac{1}{2}C'(0) \\\\\n                2(M_0 - A_0) &= \\frac{3}{2}(H_0 - A_0) \\\\\n                2M_0 - 2A_0 &= \\frac{3}{2}H_0 - \\frac{3}{2}A_0 \\\\\n                2M_0 &= \\frac{3}{2}H_0 + \\frac{1}{2}A_0 \\\\\n                M_0 &= \\frac{1}{4}(3H_0 + A_0)\n\n        2.  :math:`Q_1'(1) = \\frac{1}{2}C'(1)`. The derivative of the second\n            quadratic curve at :math:`t = 1` should be half of that of the\n            original cubic curve for the same reasons as above, also at\n            :math:`t = 1`. This gives:\n\n            .. math::\n                Q_1'(1) &= \\frac{1}{2}C'(1) \\\\\n                2(A_1 - M_1) &= \\frac{3}{2}(A_1 - H_1) \\\\\n                2A_1 - 2M_1 &= \\frac{3}{2}A_1 - \\frac{3}{2}H_1 \\\\\n                -2M_1 &= -\\frac{1}{2}A_1 - \\frac{3}{2}H_1 \\\\\n                M_1 &= \\frac{1}{4}(3H_1 + A_1)\n\n        3.  :math:`Q_0'(1) = Q_1'(0)`. The derivatives of both quadratic curves\n            should match at the point :math:`K`, in order for the final spline\n            to be smooth. This gives:\n\n            .. math::\n                Q_0'(1) &= Q_1'(0) \\\\\n                2(K - M_0) &= 2(M_1 - K) \\\\\n                2K - 2M_0 &= 2M_1 - 2K \\\\\n                4K &= 2M_0 + 2M_1 \\\\\n                K &= \\frac{1}{2}(M_0 + M_1)\n\n        This is sufficient to find proper control points for the quadratic\n        Bézier curves.\n\n    Parameters\n    ----------\n    a0\n        The start anchor of a single cubic Bézier curve, or an array of\n        :math:`N` start anchors for :math:`N` curves.\n    h0\n        The first handle of a single cubic Bézier curve, or an array of\n        :math:`N` first handles for :math:`N` curves.\n    h1\n        The second handle of a single cubic Bézier curve, or an array of\n        :math:`N` second handles for :math:`N` curves.\n    a1\n        The end anchor of a single cubic Bézier curve, or an array of\n        :math:`N` end anchors for :math:`N` curves.\n\n    Returns\n    -------\n    result\n        An array containing either 6 points for 2 quadratic Bézier curves\n        approximating the original cubic curve, or :math:`6N` points for\n        :math:`2N` quadratic curves approximating :math:`N` cubic curves.\n\n    Raises\n    ------\n    ValueError\n        If ``a0``, ``h0``, ``h1`` and ``a1`` have different dimensions, or\n        if their number of dimensions is not 1 or 2.\n    \"\"\"\n    a0c = np.asarray(a0)\n    h0c = np.asarray(h0)\n    h1c = np.asarray(h1)\n    a1c = np.asarray(a1)\n\n    if all(arr.ndim == 1 for arr in (a0c, h0c, h1c, a1c)):\n        num_curves, dim = 1, a0c.shape[0]\n    elif all(arr.ndim == 2 for arr in (a0c, h0c, h1c, a1c)):\n        num_curves, dim = a0c.shape\n    else:\n        raise ValueError(\"All arguments must be Point3D or Point3D_Array.\")\n\n    m0 = 0.25 * (3 * h0c + a0c)\n    m1 = 0.25 * (3 * h1c + a1c)\n    k = 0.5 * (m0 + m1)\n\n    result = np.empty((6 * num_curves, dim))\n    result[0::6] = a0c\n    result[1::6] = m0\n    result[2::6] = k\n    result[3::6] = k\n    result[4::6] = m1\n    result[5::6] = a1c\n    return result\n\n\ndef is_closed(points: Point3D_Array) -> bool:\n    \"\"\"Returns ``True`` if the spline given by ``points`` is closed, by\n    checking if its first and last points are close to each other, or``False``\n    otherwise.\n\n    .. note::\n\n        This function reimplements :meth:`np.allclose`, because repeated\n        calling of :meth:`np.allclose` for only 2 points is inefficient.\n\n    Parameters\n    ----------\n    points\n        An array of points defining a spline.\n\n    Returns\n    -------\n    :class:`bool`\n        Whether the first and last points of the array are close enough or not\n        to be considered the same, thus considering the defined spline as\n        closed.\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> import numpy as np\n        >>> from manim import is_closed\n        >>> is_closed(\n        ...     np.array(\n        ...         [\n        ...             [0, 0, 0],\n        ...             [1, 2, 3],\n        ...             [3, 2, 1],\n        ...             [0, 0, 0],\n        ...         ]\n        ...     )\n        ... )\n        True\n        >>> is_closed(\n        ...     np.array(\n        ...         [\n        ...             [0, 0, 0],\n        ...             [1, 2, 3],\n        ...             [3, 2, 1],\n        ...             [1e-10, 1e-10, 1e-10],\n        ...         ]\n        ...     )\n        ... )\n        True\n        >>> is_closed(\n        ...     np.array(\n        ...         [\n        ...             [0, 0, 0],\n        ...             [1, 2, 3],\n        ...             [3, 2, 1],\n        ...             [1e-2, 1e-2, 1e-2],\n        ...         ]\n        ...     )\n        ... )\n        False\n    \"\"\"\n    start, end = points[0], points[-1]\n    rtol = 1e-5\n    atol = 1e-8\n    tolerance = atol + rtol * start\n    if abs(end[0] - start[0]) > tolerance[0]:\n        return False\n    if abs(end[1] - start[1]) > tolerance[1]:\n        return False\n    return bool(abs(end[2] - start[2]) <= tolerance[2])\n\n\ndef proportions_along_bezier_curve_for_point(\n    point: Point3DLike,\n    control_points: BezierPointsLike,\n    round_to: float = 1e-6,\n) -> MatrixMN:\n    \"\"\"Obtains the proportion along the bezier curve corresponding to a given point\n    given the bezier curve's control points.\n\n    The bezier polynomial is constructed using the coordinates of the given point\n    as well as the bezier curve's control points. On solving the polynomial for each dimension,\n    if there are roots common to every dimension, those roots give the proportion along the\n    curve the point is at. If there are no real roots, the point does not lie on the curve.\n\n    Parameters\n    ----------\n    point\n        The Cartesian Coordinates of the point whose parameter\n        should be obtained.\n    control_points\n        The Cartesian Coordinates of the ordered control\n        points of the bezier curve on which the point may\n        or may not lie.\n    round_to\n        A float whose number of decimal places all values\n        such as coordinates of points will be rounded.\n\n    Returns\n    -------\n        np.ndarray[float]\n            List containing possible parameters (the proportions along the bezier curve)\n            for the given point on the given bezier curve.\n            This usually only contains one or zero elements, but if the\n            point is, say, at the beginning/end of a closed loop, may return\n            a list with more than 1 value, corresponding to the beginning and\n            end etc. of the loop.\n\n    Raises\n    ------\n    :class:`ValueError`\n        When ``point`` and the control points have different shapes.\n    \"\"\"\n    # Method taken from\n    # http://polymathprogrammer.com/2012/04/03/does-point-lie-on-bezier-curve/\n\n    if not all(np.shape(point) == np.shape(c_p) for c_p in control_points):\n        raise ValueError(\n            f\"Point {point} and Control Points {control_points} have different shapes.\",\n        )\n\n    control_points = np.array(control_points)\n    n = len(control_points) - 1\n\n    roots = []\n    for dim, coord in enumerate(point):\n        control_coords = control_points[:, dim]\n        terms = []\n        for term_power in range(n, -1, -1):\n            outercoeff = choose(n, term_power)\n            term = []\n            sign = 1\n            for subterm_num in range(term_power, -1, -1):\n                innercoeff = choose(term_power, subterm_num) * sign\n                subterm = innercoeff * control_coords[subterm_num]\n                if term_power == 0:\n                    subterm -= coord\n                term.append(subterm)\n                sign *= -1\n            terms.append(outercoeff * sum(np.array(term)))\n        if all(term == 0 for term in terms):\n            # Then both Bezier curve and Point lie on the same plane.\n            # Roots will be none, but in this specific instance, we don't need to consider that.\n            continue\n        bezier_polynom = np.polynomial.Polynomial(terms[::-1])\n        polynom_roots = bezier_polynom.roots()\n        if len(polynom_roots) > 0:\n            polynom_roots = np.around(polynom_roots, int(np.log10(1 / round_to)))\n        roots.append(polynom_roots)\n\n    roots = [[root for root in rootlist if root.imag == 0] for rootlist in roots]\n    # Get common roots\n    # arg-type: ignore\n    roots = reduce(np.intersect1d, roots)\n    result = np.asarray([r.real for r in roots if 0 <= r.real <= 1])\n    return result\n\n\ndef point_lies_on_bezier(\n    point: Point3DLike,\n    control_points: BezierPointsLike,\n    round_to: float = 1e-6,\n) -> bool:\n    \"\"\"Checks if a given point lies on the bezier curves with the given control points.\n\n    This is done by solving the bezier polynomial with the point as the constant term; if\n    any real roots exist, the point lies on the bezier curve.\n\n    Parameters\n    ----------\n    point\n        The Cartesian Coordinates of the point to check.\n    control_points\n        The Cartesian Coordinates of the ordered control\n        points of the bezier curve on which the point may\n        or may not lie.\n    round_to\n        A float whose number of decimal places all values\n        such as coordinates of points will be rounded.\n\n    Returns\n    -------\n    bool\n        Whether the point lies on the curve.\n    \"\"\"\n    roots = proportions_along_bezier_curve_for_point(point, control_points, round_to)\n\n    return len(roots) > 0\n"
  },
  {
    "path": "manim/utils/caching.py",
    "content": "from __future__ import annotations\n\nfrom collections.abc import Callable\nfrom typing import TYPE_CHECKING, Any\n\nfrom .. import config, logger\nfrom ..utils.hashing import get_hash_from_play_call\n\n__all__ = [\"handle_caching_play\"]\n\nif TYPE_CHECKING:\n    from manim.renderer.opengl_renderer import OpenGLRenderer\n    from manim.scene.scene import Scene\n\n\ndef handle_caching_play(func: Callable[..., None]) -> Callable[..., None]:\n    \"\"\"Decorator that returns a wrapped version of func that will compute\n    the hash of the play invocation.\n\n    The returned function will act according to the computed hash: either skip\n    the animation because it's already cached, or let the invoked function\n    play normally.\n\n    Parameters\n    ----------\n    func\n        The play like function that has to be written to the video file stream.\n        Take the same parameters as `scene.play`.\n    \"\"\"\n    # NOTE : This is only kept for OpenGL renderer.\n    # The play logic of the cairo renderer as been refactored and does not need this function anymore.\n    # When OpenGL renderer will have a proper testing system,\n    # the play logic of the latter has to be refactored in the same way the cairo renderer has been, and thus this\n    # method has to be deleted.\n\n    def wrapper(self: OpenGLRenderer, scene: Scene, *args: Any, **kwargs: Any) -> None:\n        self.skip_animations = self._original_skipping_status\n        self.update_skipping_status()\n        animations = scene.compile_animations(*args, **kwargs)\n        scene.add_mobjects_from_animations(animations)\n        if self.skip_animations:\n            logger.debug(f\"Skipping animation {self.num_plays}\")\n            func(self, scene, *args, **kwargs)\n            # If the animation is skipped, we mark its hash as None.\n            # When sceneFileWriter will start combining partial movie files, it won't take into account None hashes.\n            self.animations_hashes.append(None)\n            self.file_writer.add_partial_movie_file(None)\n            return\n        if not config[\"disable_caching\"]:\n            mobjects_on_scene = scene.mobjects\n            hash_play = get_hash_from_play_call(\n                scene,\n                self.camera,\n                animations,\n                mobjects_on_scene,\n            )\n            if self.file_writer.is_already_cached(hash_play):\n                logger.info(\n                    f\"Animation {self.num_plays} : Using cached data (hash : %(hash_play)s)\",\n                    {\"hash_play\": hash_play},\n                )\n                self.skip_animations = True\n        else:\n            hash_play = f\"uncached_{self.num_plays:05}\"\n        self.animations_hashes.append(hash_play)\n        self.file_writer.add_partial_movie_file(hash_play)\n        logger.debug(\n            \"List of the first few animation hashes of the scene: %(h)s\",\n            {\"h\": str(self.animations_hashes[:5])},\n        )\n        func(self, scene, *args, **kwargs)\n\n    return wrapper\n"
  },
  {
    "path": "manim/utils/color/AS2700.py",
    "content": "\"\"\"Australian Color Standard\n\nIn 1985 the Australian Independent Color Standard AS 2700 was created. In\nthis standard, all colors can be identified via a category code (one of\nB -- Blue, G -- Green, N -- Neutrals (grey), P -- Purple, R -- Red, T -- Blue/Green,\nX -- Yellow/Red, Y -- Yellow) and a number. The colors also have (natural) names.\n\nTo use the colors from this list, access them directly from the module (which\nis exposed to Manim's global name space):\n\n.. code:: pycon\n\n    >>> from manim import AS2700\n    >>> AS2700.B23_BRIGHT_BLUE\n    ManimColor('#174F90')\n\nList of Color Constants\n-----------------------\n\nThese hex values (taken from https://www.w3schools.com/colors/colors_australia.asp)\nare non official approximate values intended to simulate AS 2700 colors:\n\n.. automanimcolormodule:: manim.utils.color.AS2700\n\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom .core import ManimColor\n\nB11_RICH_BLUE = ManimColor(\"#2B3770\")\nB12_ROYAL_BLUE = ManimColor(\"#2C3563\")\nB13_NAVY_BLUE = ManimColor(\"#28304D\")\nB14_SAPHHIRE = ManimColor(\"#28426B\")\nB15_MID_BLUE = ManimColor(\"#144B6F\")\nB21_ULTRAMARINE = ManimColor(\"#2C5098\")\nB22_HOMEBUSH_BLUE = ManimColor(\"#215097\")\nB23_BRIGHT_BLUE = ManimColor(\"#174F90\")\nB24_HARBOUR_BLUE = ManimColor(\"#1C6293\")\nB25_AQUA = ManimColor(\"#5097AC\")\nB32_POWDER_BLUE = ManimColor(\"#B7C8DB\")\nB33_MIST_BLUE = ManimColor(\"#E0E6E2\")\nB34_PARADISE_BLUE = ManimColor(\"#3499BA\")\nB35_PALE_BLUE = ManimColor(\"#CDE4E2\")\nB41_BLUEBELL = ManimColor(\"#5B94D1\")\nB42_PURPLE_BLUE = ManimColor(\"#5E7899\")\nB43_GREY_BLUE = ManimColor(\"#627C8D\")\nB44_LIGHT_GREY_BLUE = ManimColor(\"#C0C0C1\")\nB45_SKY_BLUE = ManimColor(\"#7DB7C7\")\nB51_PERIWINKLE = ManimColor(\"#3871AC\")\nB53_DARK_GREY_BLUE = ManimColor(\"#4F6572\")\nB55_STORM_BLUE = ManimColor(\"#3F7C94\")\nB61_CORAL_SEA = ManimColor(\"#2B3873\")\nB62_MIDNIGHT_BLUE = ManimColor(\"#292A34\")\nB64_CHARCOAL = ManimColor(\"#363E45\")\nG11_BOTTLE_GREEN = ManimColor(\"#253A32\")\nG12_HOLLY = ManimColor(\"#21432D\")\nG13_EMERALD = ManimColor(\"#195F35\")\nG14_MOSS_GREEN = ManimColor(\"#33572D\")\nG15_RAINFOREST_GREEN = ManimColor(\"#3D492D\")\nG16_TRAFFIC_GREEN = ManimColor(\"#305442\")\nG17_MINT_GREEN = ManimColor(\"#006B45\")\nG21_JADE = ManimColor(\"#127453\")\nG22_SERPENTINE = ManimColor(\"#78A681\")\nG23_SHAMROCK = ManimColor(\"#336634\")\nG24_FERN_TREE = ManimColor(\"#477036\")\nG25_OLIVE = ManimColor(\"#595B2A\")\nG26_APPLE_GREEN = ManimColor(\"#4E9843\")\nG27_HOMEBUSH_GREEN = ManimColor(\"#017F4D\")\nG31_VERTIGRIS = ManimColor(\"#468A65\")\nG32_OPALINE = ManimColor(\"#AFCBB8\")\nG33_LETTUCE = ManimColor(\"#7B9954\")\nG34_AVOCADO = ManimColor(\"#757C4C\")\nG35_LIME_GREEN = ManimColor(\"#89922E\")\nG36_KIKUYU = ManimColor(\"#95B43B\")\nG37_BEANSTALK = ManimColor(\"#45A56A\")\nG41_LAWN_GREEN = ManimColor(\"#0D875D\")\nG42_GLACIER = ManimColor(\"#D5E1D2\")\nG43_SURF_GREEN = ManimColor(\"#C8C8A7\")\nG44_PALM_GREEN = ManimColor(\"#99B179\")\nG45_CHARTREUSE = ManimColor(\"#C7C98D\")\nG46_CITRONELLA = ManimColor(\"#BFC83E\")\nG47_CRYSTAL_GREEN = ManimColor(\"#ADCCA8\")\nG51_SPRUCE = ManimColor(\"#05674F\")\nG52_EUCALYPTUS = ManimColor(\"#66755B\")\nG53_BANKSIA = ManimColor(\"#929479\")\nG54_MIST_GREEN = ManimColor(\"#7A836D\")\nG55_LICHEN = ManimColor(\"#A7A98C\")\nG56_SAGE_GREEN = ManimColor(\"#677249\")\nG61_DARK_GREEN = ManimColor(\"#283533\")\nG62_RIVERGUM = ManimColor(\"#617061\")\nG63_DEEP_BRONZE_GREEN = ManimColor(\"#333334\")\nG64_SLATE = ManimColor(\"#5E6153\")\nG65_TI_TREE = ManimColor(\"#5D5F4E\")\nG66_ENVIRONMENT_GREEN = ManimColor(\"#484C3F\")\nG67_ZUCCHINI = ManimColor(\"#2E443A\")\nN11_PEARL_GREY = ManimColor(\"#D8D3C7\")\nN12_PASTEL_GREY = ManimColor(\"#CCCCCC\")\nN14_WHITE = ManimColor(\"#FFFFFF\")\nN15_HOMEBUSH_GREY = ManimColor(\"#A29B93\")\nN22_CLOUD_GREY = ManimColor(\"#C4C1B9\")\nN23_NEUTRAL_GREY = ManimColor(\"#CCCCCC\")\nN24_SILVER_GREY = ManimColor(\"#BDC7C5\")\nN25_BIRCH_GREY = ManimColor(\"#ABA498\")\nN32_GREEN_GREY = ManimColor(\"#8E9282\")\nN33_LIGHTBOX_GREY = ManimColor(\"#ACADAD\")\nN35_LIGHT_GREY = ManimColor(\"#A6A7A1\")\nN41_OYSTER = ManimColor(\"#998F78\")\nN42_STORM_GREY = ManimColor(\"#858F88\")\nN43_PIPELINE_GREY = ManimColor(\"#999999\")\nN44_BRIDGE_GREY = ManimColor(\"#767779\")\nN45_KOALA_GREY = ManimColor(\"#928F88\")\nN52_MID_GREY = ManimColor(\"#727A77\")\nN53_BLUE_GREY = ManimColor(\"#7C8588\")\nN54_BASALT = ManimColor(\"#585C63\")\nN55_LEAD_GREY = ManimColor(\"#5E5C58\")\nN61_BLACK = ManimColor(\"#2A2A2C\")\nN63_PEWTER = ManimColor(\"#596064\")\nN64_DARK_GREY = ManimColor(\"#4B5259\")\nN65_GRAPHITE_GREY = ManimColor(\"#45474A\")\nP11_MAGENTA = ManimColor(\"#7B2B48\")\nP12_PURPLE = ManimColor(\"#85467B\")\nP13_VIOLET = ManimColor(\"#5D3A61\")\nP14_BLUEBERRY = ManimColor(\"#4C4176\")\nP21_SUNSET_PINK = ManimColor(\"#E3BBBD\")\nP22_CYCLAMEN = ManimColor(\"#83597D\")\nP23_LILAC = ManimColor(\"#A69FB1\")\nP24_JACKARANDA = ManimColor(\"#795F91\")\nP31_DUSTY_PINK = ManimColor(\"#DBBEBC\")\nP33_RIBBON_PINK = ManimColor(\"#D1BCC9\")\nP41_ERICA_PINK = ManimColor(\"#C55A83\")\nP42_MULBERRY = ManimColor(\"#A06574\")\nP43_WISTERIA = ManimColor(\"#756D91\")\nP52_PLUM = ManimColor(\"#6E3D4B\")\nR11_INTERNATIONAL_ORANGE = ManimColor(\"#CE482A\")\nR12_SCARLET = ManimColor(\"#CD392A\")\nR13_SIGNAL_RED = ManimColor(\"#BA312B\")\nR14_WARATAH = ManimColor(\"#AA2429\")\nR15_CRIMSON = ManimColor(\"#9E2429\")\nR21_TANGERINE = ManimColor(\"#E96957\")\nR22_HOMEBUSH_RED = ManimColor(\"#D83A2D\")\nR23_LOLLIPOP = ManimColor(\"#CC5058\")\nR24_STRAWBERRY = ManimColor(\"#B4292A\")\nR25_ROSE_PINK = ManimColor(\"#E8919C\")\nR32_APPLE_BLOSSOM = ManimColor(\"#F2E1D8\")\nR33_GHOST_GUM = ManimColor(\"#E8DAD4\")\nR34_MUSHROOM = ManimColor(\"#D7C0B6\")\nR35_DEEP_ROSE = ManimColor(\"#CD6D71\")\nR41_SHELL_PINK = ManimColor(\"#F9D9BB\")\nR42_SALMON_PINK = ManimColor(\"#D99679\")\nR43_RED_DUST = ManimColor(\"#D0674F\")\nR44_POSSUM = ManimColor(\"#A18881\")\nR45_RUBY = ManimColor(\"#8F3E5C\")\nR51_BURNT_PINK = ManimColor(\"#E19B8E\")\nR52_TERRACOTTA = ManimColor(\"#A04C36\")\nR53_RED_GUM = ManimColor(\"#8D4338\")\nR54_RASPBERRY = ManimColor(\"#852F31\")\nR55_CLARET = ManimColor(\"#67292D\")\nR62_VENETIAN_RED = ManimColor(\"#77372B\")\nR63_RED_OXIDE = ManimColor(\"#663334\")\nR64_DEEP_INDIAN_RED = ManimColor(\"#542E2B\")\nR65_MAROON = ManimColor(\"#3F2B3C\")\nT11_TROPICAL_BLUE = ManimColor(\"#006698\")\nT12_DIAMANTIA = ManimColor(\"#006C74\")\nT14_MALACHITE = ManimColor(\"#105154\")\nT15_TURQUOISE = ManimColor(\"#098587\")\nT22_ORIENTAL_BLUE = ManimColor(\"#358792\")\nT24_BLUE_JADE = ManimColor(\"#427F7E\")\nT32_HUON_GREEN = ManimColor(\"#72B3B1\")\nT33_SMOKE_BLUE = ManimColor(\"#9EB6B2\")\nT35_GREEN_ICE = ManimColor(\"#78AEA2\")\nT44_BLUE_GUM = ManimColor(\"#6A8A88\")\nT45_COOTAMUNDRA = ManimColor(\"#759E91\")\nT51_MOUNTAIN_BLUE = ManimColor(\"#295668\")\nT53_PEACOCK_BLUE = ManimColor(\"#245764\")\nT63_TEAL = ManimColor(\"#183F4E\")\nX11_BUTTERSCOTCH = ManimColor(\"#D38F43\")\nX12_PUMPKIN = ManimColor(\"#DD7E1A\")\nX13_MARIGOLD = ManimColor(\"#ED7F15\")\nX14_MANDARIN = ManimColor(\"#E45427\")\nX15_ORANGE = ManimColor(\"#E36C2B\")\nX21_PALE_OCHRE = ManimColor(\"#DAA45F\")\nX22_SAFFRON = ManimColor(\"#F6AA51\")\nX23_APRICOT = ManimColor(\"#FEB56D\")\nX24_ROCKMELON = ManimColor(\"#F6894B\")\nX31_RAFFIA = ManimColor(\"#EBC695\")\nX32_MAGNOLIA = ManimColor(\"#F1DEBE\")\nX33_WARM_WHITE = ManimColor(\"#F3E7D4\")\nX34_DRIFTWOOD = ManimColor(\"#D5C4AE\")\nX41_BUFF = ManimColor(\"#C28A44\")\nX42_BISCUIT = ManimColor(\"#DEBA92\")\nX43_BEIGE = ManimColor(\"#C9AA8C\")\nX45_CINNAMON = ManimColor(\"#AC826D\")\nX51_TAN = ManimColor(\"#8F5F32\")\nX52_COFFEE = ManimColor(\"#AD7948\")\nX53_GOLDEN_TAN = ManimColor(\"#925629\")\nX54_BROWN = ManimColor(\"#68452C\")\nX55_NUT_BROWN = ManimColor(\"#764832\")\nX61_WOMBAT = ManimColor(\"#6E5D52\")\nX62_DARK_EARTH = ManimColor(\"#6E5D52\")\nX63_IRONBARK = ManimColor(\"#443B36\")\nX64_CHOCOLATE = ManimColor(\"#4A3B31\")\nX65_DARK_BROWN = ManimColor(\"#4F372D\")\nY11_CANARY = ManimColor(\"#E7BD11\")\nY12_WATTLE = ManimColor(\"#E8AF01\")\nY13_VIVID_YELLOW = ManimColor(\"#FCAE01\")\nY14_GOLDEN_YELLOW = ManimColor(\"#F5A601\")\nY15_SUNFLOWER = ManimColor(\"#FFA709\")\nY16_INCA_GOLD = ManimColor(\"#DF8C19\")\nY21_PRIMROSE = ManimColor(\"#F5CF5B\")\nY22_CUSTARD = ManimColor(\"#EFD25C\")\nY23_BUTTERCUP = ManimColor(\"#E0CD41\")\nY24_STRAW = ManimColor(\"#E3C882\")\nY25_DEEP_CREAM = ManimColor(\"#F3C968\")\nY26_HOMEBUSH_GOLD = ManimColor(\"#FCC51A\")\nY31_LILY_GREEN = ManimColor(\"#E3E3CD\")\nY32_FLUMMERY = ManimColor(\"#E6DF9E\")\nY33_PALE_PRIMROSE = ManimColor(\"#F5F3CE\")\nY34_CREAM = ManimColor(\"#EFE3BE\")\nY35_OFF_WHITE = ManimColor(\"#F1E9D5\")\nY41_OLIVE_YELLOW = ManimColor(\"#8E7426\")\nY42_MUSTARD = ManimColor(\"#C4A32E\")\nY43_PARCHMENT = ManimColor(\"#D4C9A3\")\nY44_SAND = ManimColor(\"#DCC18B\")\nY45_MANILLA = ManimColor(\"#E5D0A7\")\nY51_BRONZE_OLIVE = ManimColor(\"#695D3E\")\nY52_CHAMOIS = ManimColor(\"#BEA873\")\nY53_SANDSTONE = ManimColor(\"#D5BF8E\")\nY54_OATMEAL = ManimColor(\"#CAAE82\")\nY55_DEEP_STONE = ManimColor(\"#BC9969\")\nY56_MERINO = ManimColor(\"#C9B79E\")\nY61_BLACK_OLIVE = ManimColor(\"#47473B\")\nY62_SUGAR_CANE = ManimColor(\"#BCA55C\")\nY63_KHAKI = ManimColor(\"#826843\")\nY65_MUSHROOM = ManimColor(\"#A39281\")\nY66_MUDSTONE = ManimColor(\"#574E45\")\n"
  },
  {
    "path": "manim/utils/color/BS381.py",
    "content": "\"\"\"British Color Standard\n\nThis module contains colors defined in one of the British Standards\nfor colors, BS381C. This standard specifies colors used in identification,\ncoding, and other special purposes. See https://www.britishstandardcolour.com/\nfor more information.\n\nTo use the colors from this list, access them directly from the module (which\nis exposed to Manim's global name space):\n\n.. code:: pycon\n\n    >>> from manim import BS381\n    >>> BS381.OXFORD_BLUE\n    ManimColor('#1F3057')\n\nList of Color Constants\n-----------------------\n\nThese hex values (taken from https://www.w3schools.com/colors/colors_british.asp)\nare non official approximate values intended to simulate the ones defined\nin the standard:\n\n.. automanimcolormodule:: manim.utils.color.BS381\n\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom .core import ManimColor\n\nBS381_101 = ManimColor(\"#94BFAC\")\nSKY_BLUE = ManimColor(\"#94BFAC\")\nBS381_102 = ManimColor(\"#5B9291\")\nTURQUOISE_BLUE = ManimColor(\"#5B9291\")\nBS381_103 = ManimColor(\"#3B6879\")\nPEACOCK_BLUE = ManimColor(\"#3B6879\")\nBS381_104 = ManimColor(\"#264D7E\")\nAZURE_BLUE = ManimColor(\"#264D7E\")\nBS381_105 = ManimColor(\"#1F3057\")\nOXFORD_BLUE = ManimColor(\"#1F3057\")\nBS381_106 = ManimColor(\"#2A283D\")\nROYAL_BLUE = ManimColor(\"#2A283D\")\nBS381_107 = ManimColor(\"#3A73A9\")\nSTRONG_BLUE = ManimColor(\"#3A73A9\")\nBS381_108 = ManimColor(\"#173679\")\nAIRCRAFT_BLUE = ManimColor(\"#173679\")\nBS381_109 = ManimColor(\"#1C5680\")\nMIDDLE_BLUE = ManimColor(\"#1C5680\")\nBS381_110 = ManimColor(\"#2C3E75\")\nROUNDEL_BLUE = ManimColor(\"#2C3E75\")\nBS381_111 = ManimColor(\"#8CC5BB\")\nPALE_BLUE = ManimColor(\"#8CC5BB\")\nBS381_112 = ManimColor(\"#78ADC2\")\nARCTIC_BLUE = ManimColor(\"#78ADC2\")\nFIESTA_BLUE = ManimColor(\"#78ADC2\")\nBS381_113 = ManimColor(\"#3F687D\")\nDEEP_SAXE_BLUE = ManimColor(\"#3F687D\")\nBS381_114 = ManimColor(\"#1F4B61\")\nRAIL_BLUE = ManimColor(\"#1F4B61\")\nBS381_115 = ManimColor(\"#5F88C1\")\nCOBALT_BLUE = ManimColor(\"#5F88C1\")\nBS381_166 = ManimColor(\"#2458AF\")\nFRENCH_BLUE = ManimColor(\"#2458AF\")\nBS381_169 = ManimColor(\"#135B75\")\nTRAFFIC_BLUE = ManimColor(\"#135B75\")\nBS381_172 = ManimColor(\"#A7C6EB\")\nPALE_ROUNDEL_BLUE = ManimColor(\"#A7C6EB\")\nBS381_174 = ManimColor(\"#64A0AA\")\nORIENT_BLUE = ManimColor(\"#64A0AA\")\nBS381_175 = ManimColor(\"#4F81C5\")\nLIGHT_FRENCH_BLUE = ManimColor(\"#4F81C5\")\nBS381_210 = ManimColor(\"#BBC9A5\")\nSKY = ManimColor(\"#BBC9A5\")\nBS381_216 = ManimColor(\"#BCD890\")\nEAU_DE_NIL = ManimColor(\"#BCD890\")\nBS381_217 = ManimColor(\"#96BF65\")\nSEA_GREEN = ManimColor(\"#96BF65\")\nBS381_218 = ManimColor(\"#698B47\")\nGRASS_GREEN = ManimColor(\"#698B47\")\nBS381_219 = ManimColor(\"#757639\")\nSAGE_GREEN = ManimColor(\"#757639\")\nBS381_220 = ManimColor(\"#4B5729\")\nOLIVE_GREEN = ManimColor(\"#4B5729\")\nBS381_221 = ManimColor(\"#507D3A\")\nBRILLIANT_GREEN = ManimColor(\"#507D3A\")\nBS381_222 = ManimColor(\"#6A7031\")\nLIGHT_BRONZE_GREEN = ManimColor(\"#6A7031\")\nBS381_223 = ManimColor(\"#49523A\")\nMIDDLE_BRONZE_GREEN = ManimColor(\"#49523A\")\nBS381_224 = ManimColor(\"#3E4630\")\nDEEP_BRONZE_GREEN = ManimColor(\"#3E4630\")\nBS381_225 = ManimColor(\"#406A28\")\nLIGHT_BRUNSWICK_GREEN = ManimColor(\"#406A28\")\nBS381_226 = ManimColor(\"#33533B\")\nMID_BRUNSWICK_GREEN = ManimColor(\"#33533B\")\nBS381_227 = ManimColor(\"#254432\")\nDEEP_BRUNSWICK_GREEN = ManimColor(\"#254432\")\nBS381_228 = ManimColor(\"#428B64\")\nEMERALD_GREEN = ManimColor(\"#428B64\")\nBS381_241 = ManimColor(\"#4F5241\")\nDARK_GREEN = ManimColor(\"#4F5241\")\nBS381_262 = ManimColor(\"#44945E\")\nBOLD_GREEN = ManimColor(\"#44945E\")\nBS381_267 = ManimColor(\"#476A4C\")\nDEEP_CHROME_GREEN = ManimColor(\"#476A4C\")\nTRAFFIC_GREEN = ManimColor(\"#476A4C\")\nBS381_275 = ManimColor(\"#8FC693\")\nOPALINE_GREEN = ManimColor(\"#8FC693\")\nBS381_276 = ManimColor(\"#2E4C1E\")\nLINCON_GREEN = ManimColor(\"#2E4C1E\")\nBS381_277 = ManimColor(\"#364A20\")\nCYPRESS_GREEN = ManimColor(\"#364A20\")\nBS381_278 = ManimColor(\"#87965A\")\nLIGHT_OLIVE_GREEN = ManimColor(\"#87965A\")\nBS381_279 = ManimColor(\"#3B3629\")\nSTEEL_FURNITURE_GREEN = ManimColor(\"#3B3629\")\nBS381_280 = ManimColor(\"#68AB77\")\nVERDIGRIS_GREEN = ManimColor(\"#68AB77\")\nBS381_282 = ManimColor(\"#506B52\")\nFOREST_GREEN = ManimColor(\"#506B52\")\nBS381_283 = ManimColor(\"#7E8F6E\")\nAIRCRAFT_GREY_GREEN = ManimColor(\"#7E8F6E\")\nBS381_284 = ManimColor(\"#6B6F5A\")\nSPRUCE_GREEN = ManimColor(\"#6B6F5A\")\nBS381_285 = ManimColor(\"#5F5C4B\")\nNATO_GREEN = ManimColor(\"#5F5C4B\")\nBS381_298 = ManimColor(\"#4F5138\")\nOLIVE_DRAB = ManimColor(\"#4F5138\")\nBS381_309 = ManimColor(\"#FEEC04\")\nCANARY_YELLOW = ManimColor(\"#FEEC04\")\nBS381_310 = ManimColor(\"#FEF963\")\nPRIMROSE = ManimColor(\"#FEF963\")\nBS381_315 = ManimColor(\"#FEF96A\")\nGRAPEFRUIT = ManimColor(\"#FEF96A\")\nBS381_320 = ManimColor(\"#9E7339\")\nLIGHT_BROWN = ManimColor(\"#9E7339\")\nBS381_337 = ManimColor(\"#4C4A3C\")\nVERY_DARK_DRAB = ManimColor(\"#4C4A3C\")\nBS381_350 = ManimColor(\"#7B6B4F\")\nDARK_EARTH = ManimColor(\"#7B6B4F\")\nBS381_352 = ManimColor(\"#FCED96\")\nPALE_CREAM = ManimColor(\"#FCED96\")\nBS381_353 = ManimColor(\"#FDF07A\")\nDEEP_CREAM = ManimColor(\"#FDF07A\")\nBS381_354 = ManimColor(\"#E9BB43\")\nPRIMROSE_2 = ManimColor(\"#E9BB43\")\nBS381_355 = ManimColor(\"#FDD906\")\nLEMON = ManimColor(\"#FDD906\")\nBS381_356 = ManimColor(\"#FCC808\")\nGOLDEN_YELLOW = ManimColor(\"#FCC808\")\nBS381_358 = ManimColor(\"#F6C870\")\nLIGHT_BUFF = ManimColor(\"#F6C870\")\nBS381_359 = ManimColor(\"#DBAC50\")\nMIDDLE_BUFF = ManimColor(\"#DBAC50\")\nBS381_361 = ManimColor(\"#D4B97D\")\nLIGHT_STONE = ManimColor(\"#D4B97D\")\nBS381_362 = ManimColor(\"#AC7C42\")\nMIDDLE_STONE = ManimColor(\"#AC7C42\")\nBS381_363 = ManimColor(\"#FDE706\")\nBOLD_YELLOW = ManimColor(\"#FDE706\")\nBS381_364 = ManimColor(\"#CEC093\")\nPORTLAND_STONE = ManimColor(\"#CEC093\")\nBS381_365 = ManimColor(\"#F4F0BD\")\nVELLUM = ManimColor(\"#F4F0BD\")\nBS381_366 = ManimColor(\"#F5E7A1\")\nLIGHT_BEIGE = ManimColor(\"#F5E7A1\")\nBS381_367 = ManimColor(\"#FEF6BF\")\nMANILLA = ManimColor(\"#fef6bf\")\nBS381_368 = ManimColor(\"#DD7B00\")\nTRAFFIC_YELLOW = ManimColor(\"#DD7B00\")\nBS381_369 = ManimColor(\"#FEEBA8\")\nBISCUIT = ManimColor(\"#feeba8\")\nBS381_380 = ManimColor(\"#BBA38A\")\nCAMOUFLAGE_DESERT_SAND = ManimColor(\"#BBA38A\")\nBS381_384 = ManimColor(\"#EEDFA5\")\nLIGHT_STRAW = ManimColor(\"#EEDFA5\")\nBS381_385 = ManimColor(\"#E8C88F\")\nLIGHT_BISCUIT = ManimColor(\"#E8C88F\")\nBS381_386 = ManimColor(\"#E6C18D\")\nCHAMPAGNE = ManimColor(\"#e6c18d\")\nBS381_387 = ManimColor(\"#CFB48A\")\nSUNRISE = ManimColor(\"#cfb48a\")\nSUNSHINE = ManimColor(\"#cfb48a\")\nBS381_388 = ManimColor(\"#E4CF93\")\nBEIGE = ManimColor(\"#e4cf93\")\nBS381_389 = ManimColor(\"#B2A788\")\nCAMOUFLAGE_BEIGE = ManimColor(\"#B2A788\")\nBS381_397 = ManimColor(\"#F3D163\")\nJASMINE_YELLOW = ManimColor(\"#F3D163\")\nBS381_411 = ManimColor(\"#74542F\")\nMIDDLE_BROWN = ManimColor(\"#74542F\")\nBS381_412 = ManimColor(\"#5C422E\")\nDARK_BROWN = ManimColor(\"#5C422E\")\nBS381_413 = ManimColor(\"#402D21\")\nNUT_BROWN = ManimColor(\"#402D21\")\nBS381_414 = ManimColor(\"#A86C29\")\nGOLDEN_BROWN = ManimColor(\"#A86C29\")\nBS381_415 = ManimColor(\"#61361E\")\nIMPERIAL_BROWN = ManimColor(\"#61361E\")\nBS381_420 = ManimColor(\"#A89177\")\nDARK_CAMOUFLAGE_DESERT_SAND = ManimColor(\"#A89177\")\nBS381_435 = ManimColor(\"#845B4D\")\nCAMOUFLAGE_RED = ManimColor(\"#845B4D\")\nBS381_436 = ManimColor(\"#564B47\")\nDARK_CAMOUFLAGE_BROWN = ManimColor(\"#564B47\")\nBS381_439 = ManimColor(\"#753B1E\")\nORANGE_BROWN = ManimColor(\"#753B1E\")\nBS381_443 = ManimColor(\"#C98A71\")\nSALMON = ManimColor(\"#c98a71\")\nBS381_444 = ManimColor(\"#A65341\")\nTERRACOTTA = ManimColor(\"#a65341\")\nBS381_445 = ManimColor(\"#83422B\")\nVENETIAN_RED = ManimColor(\"#83422B\")\nBS381_446 = ManimColor(\"#774430\")\nRED_OXIDE = ManimColor(\"#774430\")\nBS381_447 = ManimColor(\"#F3B28B\")\nSALMON_PINK = ManimColor(\"#F3B28B\")\nBS381_448 = ManimColor(\"#67403A\")\nDEEP_INDIAN_RED = ManimColor(\"#67403A\")\nBS381_449 = ManimColor(\"#693B3F\")\nLIGHT_PURPLE_BROWN = ManimColor(\"#693B3F\")\nBS381_452 = ManimColor(\"#613339\")\nDARK_CRIMSON = ManimColor(\"#613339\")\nBS381_453 = ManimColor(\"#FBDED6\")\nSHELL_PINK = ManimColor(\"#FBDED6\")\nBS381_454 = ManimColor(\"#E8A1A2\")\nPALE_ROUNDEL_RED = ManimColor(\"#E8A1A2\")\nBS381_460 = ManimColor(\"#BD8F56\")\nDEEP_BUFF = ManimColor(\"#BD8F56\")\nBS381_473 = ManimColor(\"#793932\")\nGULF_RED = ManimColor(\"#793932\")\nBS381_489 = ManimColor(\"#8D5B41\")\nLEAF_BROWN = ManimColor(\"#8D5B41\")\nBS381_490 = ManimColor(\"#573320\")\nBEECH_BROWN = ManimColor(\"#573320\")\nBS381_499 = ManimColor(\"#59493E\")\nSERVICE_BROWN = ManimColor(\"#59493E\")\nBS381_536 = ManimColor(\"#BB3016\")\nPOPPY = ManimColor(\"#bb3016\")\nBS381_537 = ManimColor(\"#DD3420\")\nSIGNAL_RED = ManimColor(\"#DD3420\")\nBS381_538 = ManimColor(\"#C41C22\")\nPOST_OFFICE_RED = ManimColor(\"#C41C22\")\nCHERRY = ManimColor(\"#c41c22\")\nBS381_539 = ManimColor(\"#D21E2B\")\nCURRANT_RED = ManimColor(\"#D21E2B\")\nBS381_540 = ManimColor(\"#8B1A32\")\nCRIMSON = ManimColor(\"#8b1a32\")\nBS381_541 = ManimColor(\"#471B21\")\nMAROON = ManimColor(\"#471b21\")\nBS381_542 = ManimColor(\"#982D57\")\nRUBY = ManimColor(\"#982d57\")\nBS381_557 = ManimColor(\"#EF841E\")\nLIGHT_ORANGE = ManimColor(\"#EF841E\")\nBS381_564 = ManimColor(\"#DD3524\")\nBOLD_RED = ManimColor(\"#DD3524\")\nBS381_568 = ManimColor(\"#FB9C06\")\nAPRICOT = ManimColor(\"#fb9c06\")\nBS381_570 = ManimColor(\"#A83C19\")\nTRAFFIC_RED = ManimColor(\"#A83C19\")\nBS381_591 = ManimColor(\"#D04E09\")\nDEEP_ORANGE = ManimColor(\"#D04E09\")\nBS381_592 = ManimColor(\"#E45523\")\nINTERNATIONAL_ORANGE = ManimColor(\"#E45523\")\nBS381_593 = ManimColor(\"#F24816\")\nRAIL_RED = ManimColor(\"#F24816\")\nAZO_ORANGE = ManimColor(\"#F24816\")\nBS381_626 = ManimColor(\"#A0A9AA\")\nCAMOUFLAGE_GREY = ManimColor(\"#A0A9AA\")\nBS381_627 = ManimColor(\"#BEC0B8\")\nLIGHT_AIRCRAFT_GREY = ManimColor(\"#BEC0B8\")\nBS381_628 = ManimColor(\"#9D9D7E\")\nSILVER_GREY = ManimColor(\"#9D9D7E\")\nBS381_629 = ManimColor(\"#7A838B\")\nDARK_CAMOUFLAGE_GREY = ManimColor(\"#7A838B\")\nBS381_630 = ManimColor(\"#A5AD98\")\nFRENCH_GREY = ManimColor(\"#A5AD98\")\nBS381_631 = ManimColor(\"#9AAA9F\")\nLIGHT_GREY = ManimColor(\"#9AAA9F\")\nBS381_632 = ManimColor(\"#6B7477\")\nDARK_ADMIRALTY_GREY = ManimColor(\"#6B7477\")\nBS381_633 = ManimColor(\"#424C53\")\nRAF_BLUE_GREY = ManimColor(\"#424C53\")\nBS381_634 = ManimColor(\"#6F7264\")\nSLATE = ManimColor(\"#6f7264\")\nBS381_635 = ManimColor(\"#525B55\")\nLEAD = ManimColor(\"#525b55\")\nBS381_636 = ManimColor(\"#5F7682\")\nPRU_BLUE = ManimColor(\"#5F7682\")\nBS381_637 = ManimColor(\"#8E9B9C\")\nMEDIUM_SEA_GREY = ManimColor(\"#8E9B9C\")\nBS381_638 = ManimColor(\"#6C7377\")\nDARK_SEA_GREY = ManimColor(\"#6C7377\")\nBS381_639 = ManimColor(\"#667563\")\nLIGHT_SLATE_GREY = ManimColor(\"#667563\")\nBS381_640 = ManimColor(\"#566164\")\nEXTRA_DARK_SEA_GREY = ManimColor(\"#566164\")\nBS381_642 = ManimColor(\"#282B2F\")\nNIGHT = ManimColor(\"#282b2f\")\nBS381_671 = ManimColor(\"#4E5355\")\nMIDDLE_GRAPHITE = ManimColor(\"#4E5355\")\nBS381_676 = ManimColor(\"#A9B7B9\")\nLIGHT_WEATHERWORK_GREY = ManimColor(\"#A9B7B9\")\nBS381_677 = ManimColor(\"#676F76\")\nDARK_WEATHERWORK_GREY = ManimColor(\"#676F76\")\nBS381_692 = ManimColor(\"#7B93A3\")\nSMOKE_GREY = ManimColor(\"#7B93A3\")\nBS381_693 = ManimColor(\"#88918D\")\nAIRCRAFT_GREY = ManimColor(\"#88918D\")\nBS381_694 = ManimColor(\"#909A92\")\nDOVE_GREY = ManimColor(\"#909A92\")\nBS381_697 = ManimColor(\"#B6D3CC\")\nLIGHT_ADMIRALTY_GREY = ManimColor(\"#B6D3CC\")\nBS381_796 = ManimColor(\"#6E4A75\")\nDARK_VIOLET = ManimColor(\"#6E4A75\")\nBS381_797 = ManimColor(\"#C9A8CE\")\nLIGHT_VIOLET = ManimColor(\"#C9A8CE\")\n"
  },
  {
    "path": "manim/utils/color/DVIPSNAMES.py",
    "content": "r\"\"\"dvips Colors\n\nThis module contains the colors defined in the dvips driver, which are commonly accessed\nas named colors in LaTeX via the ``\\usepackage[dvipsnames]{xcolor}`` package.\n\nTo use the colors from this list, access them directly from the module (which\nis exposed to Manim's global name space):\n\n.. code:: pycon\n\n    >>> from manim import DVIPSNAMES\n    >>> DVIPSNAMES.DARKORCHID\n    ManimColor('#A4538A')\n\nList of Color Constants\n-----------------------\n\nThese hex values are derived from those specified in the ``xcolor`` package\ndocumentation (see https://ctan.org/pkg/xcolor):\n\n.. automanimcolormodule:: manim.utils.color.DVIPSNAMES\n\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom .core import ManimColor\n\nAQUAMARINE = ManimColor(\"#00B5BE\")\nBITTERSWEET = ManimColor(\"#C04F17\")\nAPRICOT = ManimColor(\"#FBB982\")\nBLACK = ManimColor(\"#221E1F\")\nBLUE = ManimColor(\"#2D2F92\")\nBLUEGREEN = ManimColor(\"#00B3B8\")\nBLUEVIOLET = ManimColor(\"#473992\")\nBRICKRED = ManimColor(\"#B6321C\")\nBROWN = ManimColor(\"#792500\")\nBURNTORANGE = ManimColor(\"#F7921D\")\nCADETBLUE = ManimColor(\"#74729A\")\nCARNATIONPINK = ManimColor(\"#F282B4\")\nCERULEAN = ManimColor(\"#00A2E3\")\nCORNFLOWERBLUE = ManimColor(\"#41B0E4\")\nCYAN = ManimColor(\"#00AEEF\")\nDANDELION = ManimColor(\"#FDBC42\")\nDARKORCHID = ManimColor(\"#A4538A\")\nEMERALD = ManimColor(\"#00A99D\")\nFORESTGREEN = ManimColor(\"#009B55\")\nFUCHSIA = ManimColor(\"#8C368C\")\nGOLDENROD = ManimColor(\"#FFDF42\")\nGRAY = ManimColor(\"#949698\")\nGREEN = ManimColor(\"#00A64F\")\nGREENYELLOW = ManimColor(\"#DFE674\")\nJUNGLEGREEN = ManimColor(\"#00A99A\")\nLAVENDER = ManimColor(\"#F49EC4\")\nLIMEGREEN = ManimColor(\"#8DC73E\")\nMAGENTA = ManimColor(\"#EC008C\")\nMAHOGANY = ManimColor(\"#A9341F\")\nMAROON = ManimColor(\"#AF3235\")\nMELON = ManimColor(\"#F89E7B\")\nMIDNIGHTBLUE = ManimColor(\"#006795\")\nMULBERRY = ManimColor(\"#A93C93\")\nNAVYBLUE = ManimColor(\"#006EB8\")\nOLIVEGREEN = ManimColor(\"#3C8031\")\nORANGE = ManimColor(\"#F58137\")\nORANGERED = ManimColor(\"#ED135A\")\nORCHID = ManimColor(\"#AF72B0\")\nPEACH = ManimColor(\"#F7965A\")\nPERIWINKLE = ManimColor(\"#7977B8\")\nPINEGREEN = ManimColor(\"#008B72\")\nPLUM = ManimColor(\"#92268F\")\nPROCESSBLUE = ManimColor(\"#00B0F0\")\nPURPLE = ManimColor(\"#99479B\")\nRAWSIENNA = ManimColor(\"#974006\")\nRED = ManimColor(\"#ED1B23\")\nREDORANGE = ManimColor(\"#F26035\")\nREDVIOLET = ManimColor(\"#A1246B\")\nRHODAMINE = ManimColor(\"#EF559F\")\nROYALBLUE = ManimColor(\"#0071BC\")\nROYALPURPLE = ManimColor(\"#613F99\")\nRUBINERED = ManimColor(\"#ED017D\")\nSALMON = ManimColor(\"#F69289\")\nSEAGREEN = ManimColor(\"#3FBC9D\")\nSEPIA = ManimColor(\"#671800\")\nSKYBLUE = ManimColor(\"#46C5DD\")\nSPRINGGREEN = ManimColor(\"#C6DC67\")\nTAN = ManimColor(\"#DA9D76\")\nTEALBLUE = ManimColor(\"#00AEB3\")\nTHISTLE = ManimColor(\"#D883B7\")\nTURQUOISE = ManimColor(\"#00B4CE\")\nVIOLET = ManimColor(\"#58429B\")\nVIOLETRED = ManimColor(\"#EF58A0\")\nWHITE = ManimColor(\"#FFFFFF\")\nWILDSTRAWBERRY = ManimColor(\"#EE2967\")\nYELLOW = ManimColor(\"#FFF200\")\nYELLOWGREEN = ManimColor(\"#98CC70\")\nYELLOWORANGE = ManimColor(\"#FAA21A\")\n"
  },
  {
    "path": "manim/utils/color/SVGNAMES.py",
    "content": "r\"\"\"SVG 1.1 Colors\n\nThis module contains the colors defined in the SVG 1.1 specification, which are commonly\naccessed as named colors in LaTeX via the ``\\usepackage[svgnames]{xcolor}`` package.\n\nTo use the colors from this list, access them directly from the module (which\nis exposed to Manim's global name space):\n\n.. code:: pycon\n\n    >>> from manim import SVGNAMES\n    >>> SVGNAMES.LIGHTCORAL\n    ManimColor('#EF7F7F')\n\nList of Color Constants\n-----------------------\n\nThese hex values are derived from those specified in the ``xcolor`` package\ndocumentation (see https://ctan.org/pkg/xcolor):\n\n.. automanimcolormodule:: manim.utils.color.SVGNAMES\n\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom .core import ManimColor\n\nALICEBLUE = ManimColor(\"#EFF7FF\")\nANTIQUEWHITE = ManimColor(\"#F9EAD7\")\nAQUA = ManimColor(\"#00FFFF\")\nAQUAMARINE = ManimColor(\"#7EFFD3\")\nAZURE = ManimColor(\"#EFFFFF\")\nBEIGE = ManimColor(\"#F4F4DC\")\nBISQUE = ManimColor(\"#FFE3C4\")\nBLACK = ManimColor(\"#000000\")\nBLANCHEDALMOND = ManimColor(\"#FFEACD\")\nBLUE = ManimColor(\"#0000FF\")\nBLUEVIOLET = ManimColor(\"#892BE2\")\nBROWN = ManimColor(\"#A52A2A\")\nBURLYWOOD = ManimColor(\"#DDB787\")\nCADETBLUE = ManimColor(\"#5E9EA0\")\nCHARTREUSE = ManimColor(\"#7EFF00\")\nCHOCOLATE = ManimColor(\"#D2681D\")\nCORAL = ManimColor(\"#FF7E4F\")\nCORNFLOWERBLUE = ManimColor(\"#6395ED\")\nCORNSILK = ManimColor(\"#FFF7DC\")\nCRIMSON = ManimColor(\"#DC143B\")\nCYAN = ManimColor(\"#00FFFF\")\nDARKBLUE = ManimColor(\"#00008A\")\nDARKCYAN = ManimColor(\"#008A8A\")\nDARKGOLDENROD = ManimColor(\"#B7850B\")\nDARKGRAY = ManimColor(\"#A9A9A9\")\nDARKGREEN = ManimColor(\"#006300\")\nDARKGREY = ManimColor(\"#A9A9A9\")\nDARKKHAKI = ManimColor(\"#BCB66B\")\nDARKMAGENTA = ManimColor(\"#8A008A\")\nDARKOLIVEGREEN = ManimColor(\"#546B2F\")\nDARKORANGE = ManimColor(\"#FF8C00\")\nDARKORCHID = ManimColor(\"#9931CC\")\nDARKRED = ManimColor(\"#8A0000\")\nDARKSALMON = ManimColor(\"#E8967A\")\nDARKSEAGREEN = ManimColor(\"#8EBB8E\")\nDARKSLATEBLUE = ManimColor(\"#483D8A\")\nDARKSLATEGRAY = ManimColor(\"#2F4F4F\")\nDARKSLATEGREY = ManimColor(\"#2F4F4F\")\nDARKTURQUOISE = ManimColor(\"#00CED1\")\nDARKVIOLET = ManimColor(\"#9300D3\")\nDEEPPINK = ManimColor(\"#FF1492\")\nDEEPSKYBLUE = ManimColor(\"#00BFFF\")\nDIMGRAY = ManimColor(\"#686868\")\nDIMGREY = ManimColor(\"#686868\")\nDODGERBLUE = ManimColor(\"#1D90FF\")\nFIREBRICK = ManimColor(\"#B12121\")\nFLORALWHITE = ManimColor(\"#FFF9EF\")\nFORESTGREEN = ManimColor(\"#218A21\")\nFUCHSIA = ManimColor(\"#FF00FF\")\nGAINSBORO = ManimColor(\"#DCDCDC\")\nGHOSTWHITE = ManimColor(\"#F7F7FF\")\nGOLD = ManimColor(\"#FFD700\")\nGOLDENROD = ManimColor(\"#DAA51F\")\nGRAY = ManimColor(\"#7F7F7F\")\nGREEN = ManimColor(\"#007F00\")\nGREENYELLOW = ManimColor(\"#ADFF2F\")\nGREY = ManimColor(\"#7F7F7F\")\nHONEYDEW = ManimColor(\"#EFFFEF\")\nHOTPINK = ManimColor(\"#FF68B3\")\nINDIANRED = ManimColor(\"#CD5B5B\")\nINDIGO = ManimColor(\"#4A0082\")\nIVORY = ManimColor(\"#FFFFEF\")\nKHAKI = ManimColor(\"#EFE58C\")\nLAVENDER = ManimColor(\"#E5E5F9\")\nLAVENDERBLUSH = ManimColor(\"#FFEFF4\")\nLAWNGREEN = ManimColor(\"#7CFC00\")\nLEMONCHIFFON = ManimColor(\"#FFF9CD\")\nLIGHTBLUE = ManimColor(\"#ADD8E5\")\nLIGHTCORAL = ManimColor(\"#EF7F7F\")\nLIGHTCYAN = ManimColor(\"#E0FFFF\")\nLIGHTGOLDENROD = ManimColor(\"#EDDD82\")\nLIGHTGOLDENRODYELLOW = ManimColor(\"#F9F9D2\")\nLIGHTGRAY = ManimColor(\"#D3D3D3\")\nLIGHTGREEN = ManimColor(\"#90ED90\")\nLIGHTGREY = ManimColor(\"#D3D3D3\")\nLIGHTPINK = ManimColor(\"#FFB5C0\")\nLIGHTSALMON = ManimColor(\"#FFA07A\")\nLIGHTSEAGREEN = ManimColor(\"#1FB1AA\")\nLIGHTSKYBLUE = ManimColor(\"#87CEF9\")\nLIGHTSLATEBLUE = ManimColor(\"#8470FF\")\nLIGHTSLATEGRAY = ManimColor(\"#778799\")\nLIGHTSLATEGREY = ManimColor(\"#778799\")\nLIGHTSTEELBLUE = ManimColor(\"#AFC4DD\")\nLIGHTYELLOW = ManimColor(\"#FFFFE0\")\nLIME = ManimColor(\"#00FF00\")\nLIMEGREEN = ManimColor(\"#31CD31\")\nLINEN = ManimColor(\"#F9EFE5\")\nMAGENTA = ManimColor(\"#FF00FF\")\nMAROON = ManimColor(\"#7F0000\")\nMEDIUMAQUAMARINE = ManimColor(\"#66CDAA\")\nMEDIUMBLUE = ManimColor(\"#0000CD\")\nMEDIUMORCHID = ManimColor(\"#BA54D3\")\nMEDIUMPURPLE = ManimColor(\"#9270DB\")\nMEDIUMSEAGREEN = ManimColor(\"#3BB271\")\nMEDIUMSLATEBLUE = ManimColor(\"#7B68ED\")\nMEDIUMSPRINGGREEN = ManimColor(\"#00F99A\")\nMEDIUMTURQUOISE = ManimColor(\"#48D1CC\")\nMEDIUMVIOLETRED = ManimColor(\"#C61584\")\nMIDNIGHTBLUE = ManimColor(\"#181870\")\nMINTCREAM = ManimColor(\"#F4FFF9\")\nMISTYROSE = ManimColor(\"#FFE3E1\")\nMOCCASIN = ManimColor(\"#FFE3B5\")\nNAVAJOWHITE = ManimColor(\"#FFDDAD\")\nNAVY = ManimColor(\"#00007F\")\nNAVYBLUE = ManimColor(\"#00007F\")\nOLDLACE = ManimColor(\"#FCF4E5\")\nOLIVE = ManimColor(\"#7F7F00\")\nOLIVEDRAB = ManimColor(\"#6B8D22\")\nORANGE = ManimColor(\"#FFA500\")\nORANGERED = ManimColor(\"#FF4400\")\nORCHID = ManimColor(\"#DA70D6\")\nPALEGOLDENROD = ManimColor(\"#EDE8AA\")\nPALEGREEN = ManimColor(\"#97FB97\")\nPALETURQUOISE = ManimColor(\"#AFEDED\")\nPALEVIOLETRED = ManimColor(\"#DB7092\")\nPAPAYAWHIP = ManimColor(\"#FFEED4\")\nPEACHPUFF = ManimColor(\"#FFDAB8\")\nPERU = ManimColor(\"#CD843F\")\nPINK = ManimColor(\"#FFBFCA\")\nPLUM = ManimColor(\"#DDA0DD\")\nPOWDERBLUE = ManimColor(\"#AFE0E5\")\nPURPLE = ManimColor(\"#7F007F\")\nRED = ManimColor(\"#FF0000\")\nROSYBROWN = ManimColor(\"#BB8E8E\")\nROYALBLUE = ManimColor(\"#4168E1\")\nSADDLEBROWN = ManimColor(\"#8A4413\")\nSALMON = ManimColor(\"#F97F72\")\nSANDYBROWN = ManimColor(\"#F3A45F\")\nSEAGREEN = ManimColor(\"#2D8A56\")\nSEASHELL = ManimColor(\"#FFF4ED\")\nSIENNA = ManimColor(\"#A0512C\")\nSILVER = ManimColor(\"#BFBFBF\")\nSKYBLUE = ManimColor(\"#87CEEA\")\nSLATEBLUE = ManimColor(\"#6959CD\")\nSLATEGRAY = ManimColor(\"#707F90\")\nSLATEGREY = ManimColor(\"#707F90\")\nSNOW = ManimColor(\"#FFF9F9\")\nSPRINGGREEN = ManimColor(\"#00FF7E\")\nSTEELBLUE = ManimColor(\"#4682B3\")\nTAN = ManimColor(\"#D2B38C\")\nTEAL = ManimColor(\"#007F7F\")\nTHISTLE = ManimColor(\"#D8BFD8\")\nTOMATO = ManimColor(\"#FF6347\")\nTURQUOISE = ManimColor(\"#3FE0CF\")\nVIOLET = ManimColor(\"#ED82ED\")\nVIOLETRED = ManimColor(\"#D01F90\")\nWHEAT = ManimColor(\"#F4DDB2\")\nWHITE = ManimColor(\"#FFFFFF\")\nWHITESMOKE = ManimColor(\"#F4F4F4\")\nYELLOW = ManimColor(\"#FFFF00\")\nYELLOWGREEN = ManimColor(\"#9ACD30\")\n"
  },
  {
    "path": "manim/utils/color/X11.py",
    "content": "# from https://www.w3schools.com/colors/colors_x11.asp\n\n\"\"\"X11 Colors\n\nThese color and their names (taken from\nhttps://www.w3schools.com/colors/colors_x11.asp) were developed at the\nMassachusetts Intitute of Technology (MIT) during\nthe development of color based computer display system.\n\nTo use the colors from this list, access them directly from the module (which\nis exposed to Manim's global name space):\n\n.. code:: pycon\n\n    >>> from manim import X11\n    >>> X11.BEIGE\n    ManimColor('#F5F5DC')\n\n\nList of Color Constants\n-----------------------\n\n.. automanimcolormodule:: manim.utils.color.X11\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom .core import ManimColor\n\nALICEBLUE = ManimColor(\"#F0F8FF\")\nANTIQUEWHITE = ManimColor(\"#FAEBD7\")\nANTIQUEWHITE1 = ManimColor(\"#FFEFDB\")\nANTIQUEWHITE2 = ManimColor(\"#EEDFCC\")\nANTIQUEWHITE3 = ManimColor(\"#CDC0B0\")\nANTIQUEWHITE4 = ManimColor(\"#8B8378\")\nAQUAMARINE1 = ManimColor(\"#7FFFD4\")\nAQUAMARINE2 = ManimColor(\"#76EEC6\")\nAQUAMARINE4 = ManimColor(\"#458B74\")\nAZURE1 = ManimColor(\"#F0FFFF\")\nAZURE2 = ManimColor(\"#E0EEEE\")\nAZURE3 = ManimColor(\"#C1CDCD\")\nAZURE4 = ManimColor(\"#838B8B\")\nBEIGE = ManimColor(\"#F5F5DC\")\nBISQUE1 = ManimColor(\"#FFE4C4\")\nBISQUE2 = ManimColor(\"#EED5B7\")\nBISQUE3 = ManimColor(\"#CDB79E\")\nBISQUE4 = ManimColor(\"#8B7D6B\")\nBLACK = ManimColor(\"#000000\")\nBLANCHEDALMOND = ManimColor(\"#FFEBCD\")\nBLUE1 = ManimColor(\"#0000FF\")\nBLUE2 = ManimColor(\"#0000EE\")\nBLUE4 = ManimColor(\"#00008B\")\nBLUEVIOLET = ManimColor(\"#8A2BE2\")\nBROWN = ManimColor(\"#A52A2A\")\nBROWN1 = ManimColor(\"#FF4040\")\nBROWN2 = ManimColor(\"#EE3B3B\")\nBROWN3 = ManimColor(\"#CD3333\")\nBROWN4 = ManimColor(\"#8B2323\")\nBURLYWOOD = ManimColor(\"#DEB887\")\nBURLYWOOD1 = ManimColor(\"#FFD39B\")\nBURLYWOOD2 = ManimColor(\"#EEC591\")\nBURLYWOOD3 = ManimColor(\"#CDAA7D\")\nBURLYWOOD4 = ManimColor(\"#8B7355\")\nCADETBLUE = ManimColor(\"#5F9EA0\")\nCADETBLUE1 = ManimColor(\"#98F5FF\")\nCADETBLUE2 = ManimColor(\"#8EE5EE\")\nCADETBLUE3 = ManimColor(\"#7AC5CD\")\nCADETBLUE4 = ManimColor(\"#53868B\")\nCHARTREUSE1 = ManimColor(\"#7FFF00\")\nCHARTREUSE2 = ManimColor(\"#76EE00\")\nCHARTREUSE3 = ManimColor(\"#66CD00\")\nCHARTREUSE4 = ManimColor(\"#458B00\")\nCHOCOLATE = ManimColor(\"#D2691E\")\nCHOCOLATE1 = ManimColor(\"#FF7F24\")\nCHOCOLATE2 = ManimColor(\"#EE7621\")\nCHOCOLATE3 = ManimColor(\"#CD661D\")\nCORAL = ManimColor(\"#FF7F50\")\nCORAL1 = ManimColor(\"#FF7256\")\nCORAL2 = ManimColor(\"#EE6A50\")\nCORAL3 = ManimColor(\"#CD5B45\")\nCORAL4 = ManimColor(\"#8B3E2F\")\nCORNFLOWERBLUE = ManimColor(\"#6495ED\")\nCORNSILK1 = ManimColor(\"#FFF8DC\")\nCORNSILK2 = ManimColor(\"#EEE8CD\")\nCORNSILK3 = ManimColor(\"#CDC8B1\")\nCORNSILK4 = ManimColor(\"#8B8878\")\nCYAN1 = ManimColor(\"#00FFFF\")\nCYAN2 = ManimColor(\"#00EEEE\")\nCYAN3 = ManimColor(\"#00CDCD\")\nCYAN4 = ManimColor(\"#008B8B\")\nDARKGOLDENROD = ManimColor(\"#B8860B\")\nDARKGOLDENROD1 = ManimColor(\"#FFB90F\")\nDARKGOLDENROD2 = ManimColor(\"#EEAD0E\")\nDARKGOLDENROD3 = ManimColor(\"#CD950C\")\nDARKGOLDENROD4 = ManimColor(\"#8B6508\")\nDARKGREEN = ManimColor(\"#006400\")\nDARKKHAKI = ManimColor(\"#BDB76B\")\nDARKOLIVEGREEN = ManimColor(\"#556B2F\")\nDARKOLIVEGREEN1 = ManimColor(\"#CAFF70\")\nDARKOLIVEGREEN2 = ManimColor(\"#BCEE68\")\nDARKOLIVEGREEN3 = ManimColor(\"#A2CD5A\")\nDARKOLIVEGREEN4 = ManimColor(\"#6E8B3D\")\nDARKORANGE = ManimColor(\"#FF8C00\")\nDARKORANGE1 = ManimColor(\"#FF7F00\")\nDARKORANGE2 = ManimColor(\"#EE7600\")\nDARKORANGE3 = ManimColor(\"#CD6600\")\nDARKORANGE4 = ManimColor(\"#8B4500\")\nDARKORCHID = ManimColor(\"#9932CC\")\nDARKORCHID1 = ManimColor(\"#BF3EFF\")\nDARKORCHID2 = ManimColor(\"#B23AEE\")\nDARKORCHID3 = ManimColor(\"#9A32CD\")\nDARKORCHID4 = ManimColor(\"#68228B\")\nDARKSALMON = ManimColor(\"#E9967A\")\nDARKSEAGREEN = ManimColor(\"#8FBC8F\")\nDARKSEAGREEN1 = ManimColor(\"#C1FFC1\")\nDARKSEAGREEN2 = ManimColor(\"#B4EEB4\")\nDARKSEAGREEN3 = ManimColor(\"#9BCD9B\")\nDARKSEAGREEN4 = ManimColor(\"#698B69\")\nDARKSLATEBLUE = ManimColor(\"#483D8B\")\nDARKSLATEGRAY = ManimColor(\"#2F4F4F\")\nDARKSLATEGRAY1 = ManimColor(\"#97FFFF\")\nDARKSLATEGRAY2 = ManimColor(\"#8DEEEE\")\nDARKSLATEGRAY3 = ManimColor(\"#79CDCD\")\nDARKSLATEGRAY4 = ManimColor(\"#528B8B\")\nDARKTURQUOISE = ManimColor(\"#00CED1\")\nDARKVIOLET = ManimColor(\"#9400D3\")\nDEEPPINK1 = ManimColor(\"#FF1493\")\nDEEPPINK2 = ManimColor(\"#EE1289\")\nDEEPPINK3 = ManimColor(\"#CD1076\")\nDEEPPINK4 = ManimColor(\"#8B0A50\")\nDEEPSKYBLUE1 = ManimColor(\"#00BFFF\")\nDEEPSKYBLUE2 = ManimColor(\"#00B2EE\")\nDEEPSKYBLUE3 = ManimColor(\"#009ACD\")\nDEEPSKYBLUE4 = ManimColor(\"#00688B\")\nDIMGRAY = ManimColor(\"#696969\")\nDODGERBLUE1 = ManimColor(\"#1E90FF\")\nDODGERBLUE2 = ManimColor(\"#1C86EE\")\nDODGERBLUE3 = ManimColor(\"#1874CD\")\nDODGERBLUE4 = ManimColor(\"#104E8B\")\nFIREBRICK = ManimColor(\"#B22222\")\nFIREBRICK1 = ManimColor(\"#FF3030\")\nFIREBRICK2 = ManimColor(\"#EE2C2C\")\nFIREBRICK3 = ManimColor(\"#CD2626\")\nFIREBRICK4 = ManimColor(\"#8B1A1A\")\nFLORALWHITE = ManimColor(\"#FFFAF0\")\nFORESTGREEN = ManimColor(\"#228B22\")\nGAINSBORO = ManimColor(\"#DCDCDC\")\nGHOSTWHITE = ManimColor(\"#F8F8FF\")\nGOLD1 = ManimColor(\"#FFD700\")\nGOLD2 = ManimColor(\"#EEC900\")\nGOLD3 = ManimColor(\"#CDAD00\")\nGOLD4 = ManimColor(\"#8B7500\")\nGOLDENROD = ManimColor(\"#DAA520\")\nGOLDENROD1 = ManimColor(\"#FFC125\")\nGOLDENROD2 = ManimColor(\"#EEB422\")\nGOLDENROD3 = ManimColor(\"#CD9B1D\")\nGOLDENROD4 = ManimColor(\"#8B6914\")\nGRAY = ManimColor(\"#BEBEBE\")\nGRAY1 = ManimColor(\"#030303\")\nGRAY2 = ManimColor(\"#050505\")\nGRAY3 = ManimColor(\"#080808\")\nGRAY4 = ManimColor(\"#0A0A0A\")\nGRAY5 = ManimColor(\"#0D0D0D\")\nGRAY6 = ManimColor(\"#0F0F0F\")\nGRAY7 = ManimColor(\"#121212\")\nGRAY8 = ManimColor(\"#141414\")\nGRAY9 = ManimColor(\"#171717\")\nGRAY10 = ManimColor(\"#1A1A1A\")\nGRAY11 = ManimColor(\"#1C1C1C\")\nGRAY12 = ManimColor(\"#1F1F1F\")\nGRAY13 = ManimColor(\"#212121\")\nGRAY14 = ManimColor(\"#242424\")\nGRAY15 = ManimColor(\"#262626\")\nGRAY16 = ManimColor(\"#292929\")\nGRAY17 = ManimColor(\"#2B2B2B\")\nGRAY18 = ManimColor(\"#2E2E2E\")\nGRAY19 = ManimColor(\"#303030\")\nGRAY20 = ManimColor(\"#333333\")\nGRAY21 = ManimColor(\"#363636\")\nGRAY22 = ManimColor(\"#383838\")\nGRAY23 = ManimColor(\"#3B3B3B\")\nGRAY24 = ManimColor(\"#3D3D3D\")\nGRAY25 = ManimColor(\"#404040\")\nGRAY26 = ManimColor(\"#424242\")\nGRAY27 = ManimColor(\"#454545\")\nGRAY28 = ManimColor(\"#474747\")\nGRAY29 = ManimColor(\"#4A4A4A\")\nGRAY30 = ManimColor(\"#4D4D4D\")\nGRAY31 = ManimColor(\"#4F4F4F\")\nGRAY32 = ManimColor(\"#525252\")\nGRAY33 = ManimColor(\"#545454\")\nGRAY34 = ManimColor(\"#575757\")\nGRAY35 = ManimColor(\"#595959\")\nGRAY36 = ManimColor(\"#5C5C5C\")\nGRAY37 = ManimColor(\"#5E5E5E\")\nGRAY38 = ManimColor(\"#616161\")\nGRAY39 = ManimColor(\"#636363\")\nGRAY40 = ManimColor(\"#666666\")\nGRAY41 = ManimColor(\"#696969\")\nGRAY42 = ManimColor(\"#6B6B6B\")\nGRAY43 = ManimColor(\"#6E6E6E\")\nGRAY44 = ManimColor(\"#707070\")\nGRAY45 = ManimColor(\"#737373\")\nGRAY46 = ManimColor(\"#757575\")\nGRAY47 = ManimColor(\"#787878\")\nGRAY48 = ManimColor(\"#7A7A7A\")\nGRAY49 = ManimColor(\"#7D7D7D\")\nGRAY50 = ManimColor(\"#7F7F7F\")\nGRAY51 = ManimColor(\"#828282\")\nGRAY52 = ManimColor(\"#858585\")\nGRAY53 = ManimColor(\"#878787\")\nGRAY54 = ManimColor(\"#8A8A8A\")\nGRAY55 = ManimColor(\"#8C8C8C\")\nGRAY56 = ManimColor(\"#8F8F8F\")\nGRAY57 = ManimColor(\"#919191\")\nGRAY58 = ManimColor(\"#949494\")\nGRAY59 = ManimColor(\"#969696\")\nGRAY60 = ManimColor(\"#999999\")\nGRAY61 = ManimColor(\"#9C9C9C\")\nGRAY62 = ManimColor(\"#9E9E9E\")\nGRAY63 = ManimColor(\"#A1A1A1\")\nGRAY64 = ManimColor(\"#A3A3A3\")\nGRAY65 = ManimColor(\"#A6A6A6\")\nGRAY66 = ManimColor(\"#A8A8A8\")\nGRAY67 = ManimColor(\"#ABABAB\")\nGRAY68 = ManimColor(\"#ADADAD\")\nGRAY69 = ManimColor(\"#B0B0B0\")\nGRAY70 = ManimColor(\"#B3B3B3\")\nGRAY71 = ManimColor(\"#B5B5B5\")\nGRAY72 = ManimColor(\"#B8B8B8\")\nGRAY73 = ManimColor(\"#BABABA\")\nGRAY74 = ManimColor(\"#BDBDBD\")\nGRAY75 = ManimColor(\"#BFBFBF\")\nGRAY76 = ManimColor(\"#C2C2C2\")\nGRAY77 = ManimColor(\"#C4C4C4\")\nGRAY78 = ManimColor(\"#C7C7C7\")\nGRAY79 = ManimColor(\"#C9C9C9\")\nGRAY80 = ManimColor(\"#CCCCCC\")\nGRAY81 = ManimColor(\"#CFCFCF\")\nGRAY82 = ManimColor(\"#D1D1D1\")\nGRAY83 = ManimColor(\"#D4D4D4\")\nGRAY84 = ManimColor(\"#D6D6D6\")\nGRAY85 = ManimColor(\"#D9D9D9\")\nGRAY86 = ManimColor(\"#DBDBDB\")\nGRAY87 = ManimColor(\"#DEDEDE\")\nGRAY88 = ManimColor(\"#E0E0E0\")\nGRAY89 = ManimColor(\"#E3E3E3\")\nGRAY90 = ManimColor(\"#E5E5E5\")\nGRAY91 = ManimColor(\"#E8E8E8\")\nGRAY92 = ManimColor(\"#EBEBEB\")\nGRAY93 = ManimColor(\"#EDEDED\")\nGRAY94 = ManimColor(\"#F0F0F0\")\nGRAY95 = ManimColor(\"#F2F2F2\")\nGRAY97 = ManimColor(\"#F7F7F7\")\nGRAY98 = ManimColor(\"#FAFAFA\")\nGRAY99 = ManimColor(\"#FCFCFC\")\nGREEN1 = ManimColor(\"#00FF00\")\nGREEN2 = ManimColor(\"#00EE00\")\nGREEN3 = ManimColor(\"#00CD00\")\nGREEN4 = ManimColor(\"#008B00\")\nGREENYELLOW = ManimColor(\"#ADFF2F\")\nHONEYDEW1 = ManimColor(\"#F0FFF0\")\nHONEYDEW2 = ManimColor(\"#E0EEE0\")\nHONEYDEW3 = ManimColor(\"#C1CDC1\")\nHONEYDEW4 = ManimColor(\"#838B83\")\nHOTPINK = ManimColor(\"#FF69B4\")\nHOTPINK1 = ManimColor(\"#FF6EB4\")\nHOTPINK2 = ManimColor(\"#EE6AA7\")\nHOTPINK3 = ManimColor(\"#CD6090\")\nHOTPINK4 = ManimColor(\"#8B3A62\")\nINDIANRED = ManimColor(\"#CD5C5C\")\nINDIANRED1 = ManimColor(\"#FF6A6A\")\nINDIANRED2 = ManimColor(\"#EE6363\")\nINDIANRED3 = ManimColor(\"#CD5555\")\nINDIANRED4 = ManimColor(\"#8B3A3A\")\nIVORY1 = ManimColor(\"#FFFFF0\")\nIVORY2 = ManimColor(\"#EEEEE0\")\nIVORY3 = ManimColor(\"#CDCDC1\")\nIVORY4 = ManimColor(\"#8B8B83\")\nKHAKI = ManimColor(\"#F0E68C\")\nKHAKI1 = ManimColor(\"#FFF68F\")\nKHAKI2 = ManimColor(\"#EEE685\")\nKHAKI3 = ManimColor(\"#CDC673\")\nKHAKI4 = ManimColor(\"#8B864E\")\nLAVENDER = ManimColor(\"#E6E6FA\")\nLAVENDERBLUSH1 = ManimColor(\"#FFF0F5\")\nLAVENDERBLUSH2 = ManimColor(\"#EEE0E5\")\nLAVENDERBLUSH3 = ManimColor(\"#CDC1C5\")\nLAVENDERBLUSH4 = ManimColor(\"#8B8386\")\nLAWNGREEN = ManimColor(\"#7CFC00\")\nLEMONCHIFFON1 = ManimColor(\"#FFFACD\")\nLEMONCHIFFON2 = ManimColor(\"#EEE9BF\")\nLEMONCHIFFON3 = ManimColor(\"#CDC9A5\")\nLEMONCHIFFON4 = ManimColor(\"#8B8970\")\nLIGHT = ManimColor(\"#EEDD82\")\nLIGHTBLUE = ManimColor(\"#ADD8E6\")\nLIGHTBLUE1 = ManimColor(\"#BFEFFF\")\nLIGHTBLUE2 = ManimColor(\"#B2DFEE\")\nLIGHTBLUE3 = ManimColor(\"#9AC0CD\")\nLIGHTBLUE4 = ManimColor(\"#68838B\")\nLIGHTCORAL = ManimColor(\"#F08080\")\nLIGHTCYAN1 = ManimColor(\"#E0FFFF\")\nLIGHTCYAN2 = ManimColor(\"#D1EEEE\")\nLIGHTCYAN3 = ManimColor(\"#B4CDCD\")\nLIGHTCYAN4 = ManimColor(\"#7A8B8B\")\nLIGHTGOLDENROD1 = ManimColor(\"#FFEC8B\")\nLIGHTGOLDENROD2 = ManimColor(\"#EEDC82\")\nLIGHTGOLDENROD3 = ManimColor(\"#CDBE70\")\nLIGHTGOLDENROD4 = ManimColor(\"#8B814C\")\nLIGHTGOLDENRODYELLOW = ManimColor(\"#FAFAD2\")\nLIGHTGRAY = ManimColor(\"#D3D3D3\")\nLIGHTPINK = ManimColor(\"#FFB6C1\")\nLIGHTPINK1 = ManimColor(\"#FFAEB9\")\nLIGHTPINK2 = ManimColor(\"#EEA2AD\")\nLIGHTPINK3 = ManimColor(\"#CD8C95\")\nLIGHTPINK4 = ManimColor(\"#8B5F65\")\nLIGHTSALMON1 = ManimColor(\"#FFA07A\")\nLIGHTSALMON2 = ManimColor(\"#EE9572\")\nLIGHTSALMON3 = ManimColor(\"#CD8162\")\nLIGHTSALMON4 = ManimColor(\"#8B5742\")\nLIGHTSEAGREEN = ManimColor(\"#20B2AA\")\nLIGHTSKYBLUE = ManimColor(\"#87CEFA\")\nLIGHTSKYBLUE1 = ManimColor(\"#B0E2FF\")\nLIGHTSKYBLUE2 = ManimColor(\"#A4D3EE\")\nLIGHTSKYBLUE3 = ManimColor(\"#8DB6CD\")\nLIGHTSKYBLUE4 = ManimColor(\"#607B8B\")\nLIGHTSLATEBLUE = ManimColor(\"#8470FF\")\nLIGHTSLATEGRAY = ManimColor(\"#778899\")\nLIGHTSTEELBLUE = ManimColor(\"#B0C4DE\")\nLIGHTSTEELBLUE1 = ManimColor(\"#CAE1FF\")\nLIGHTSTEELBLUE2 = ManimColor(\"#BCD2EE\")\nLIGHTSTEELBLUE3 = ManimColor(\"#A2B5CD\")\nLIGHTSTEELBLUE4 = ManimColor(\"#6E7B8B\")\nLIGHTYELLOW1 = ManimColor(\"#FFFFE0\")\nLIGHTYELLOW2 = ManimColor(\"#EEEED1\")\nLIGHTYELLOW3 = ManimColor(\"#CDCDB4\")\nLIGHTYELLOW4 = ManimColor(\"#8B8B7A\")\nLIMEGREEN = ManimColor(\"#32CD32\")\nLINEN = ManimColor(\"#FAF0E6\")\nMAGENTA = ManimColor(\"#FF00FF\")\nMAGENTA2 = ManimColor(\"#EE00EE\")\nMAGENTA3 = ManimColor(\"#CD00CD\")\nMAGENTA4 = ManimColor(\"#8B008B\")\nMAROON = ManimColor(\"#B03060\")\nMAROON1 = ManimColor(\"#FF34B3\")\nMAROON2 = ManimColor(\"#EE30A7\")\nMAROON3 = ManimColor(\"#CD2990\")\nMAROON4 = ManimColor(\"#8B1C62\")\nMEDIUM = ManimColor(\"#66CDAA\")\nMEDIUMAQUAMARINE = ManimColor(\"#66CDAA\")\nMEDIUMBLUE = ManimColor(\"#0000CD\")\nMEDIUMORCHID = ManimColor(\"#BA55D3\")\nMEDIUMORCHID1 = ManimColor(\"#E066FF\")\nMEDIUMORCHID2 = ManimColor(\"#D15FEE\")\nMEDIUMORCHID3 = ManimColor(\"#B452CD\")\nMEDIUMORCHID4 = ManimColor(\"#7A378B\")\nMEDIUMPURPLE = ManimColor(\"#9370DB\")\nMEDIUMPURPLE1 = ManimColor(\"#AB82FF\")\nMEDIUMPURPLE2 = ManimColor(\"#9F79EE\")\nMEDIUMPURPLE3 = ManimColor(\"#8968CD\")\nMEDIUMPURPLE4 = ManimColor(\"#5D478B\")\nMEDIUMSEAGREEN = ManimColor(\"#3CB371\")\nMEDIUMSLATEBLUE = ManimColor(\"#7B68EE\")\nMEDIUMSPRINGGREEN = ManimColor(\"#00FA9A\")\nMEDIUMTURQUOISE = ManimColor(\"#48D1CC\")\nMEDIUMVIOLETRED = ManimColor(\"#C71585\")\nMIDNIGHTBLUE = ManimColor(\"#191970\")\nMINTCREAM = ManimColor(\"#F5FFFA\")\nMISTYROSE1 = ManimColor(\"#FFE4E1\")\nMISTYROSE2 = ManimColor(\"#EED5D2\")\nMISTYROSE3 = ManimColor(\"#CDB7B5\")\nMISTYROSE4 = ManimColor(\"#8B7D7B\")\nMOCCASIN = ManimColor(\"#FFE4B5\")\nNAVAJOWHITE1 = ManimColor(\"#FFDEAD\")\nNAVAJOWHITE2 = ManimColor(\"#EECFA1\")\nNAVAJOWHITE3 = ManimColor(\"#CDB38B\")\nNAVAJOWHITE4 = ManimColor(\"#8B795E\")\nNAVYBLUE = ManimColor(\"#000080\")\nOLDLACE = ManimColor(\"#FDF5E6\")\nOLIVEDRAB = ManimColor(\"#6B8E23\")\nOLIVEDRAB1 = ManimColor(\"#C0FF3E\")\nOLIVEDRAB2 = ManimColor(\"#B3EE3A\")\nOLIVEDRAB4 = ManimColor(\"#698B22\")\nORANGE1 = ManimColor(\"#FFA500\")\nORANGE2 = ManimColor(\"#EE9A00\")\nORANGE3 = ManimColor(\"#CD8500\")\nORANGE4 = ManimColor(\"#8B5A00\")\nORANGERED1 = ManimColor(\"#FF4500\")\nORANGERED2 = ManimColor(\"#EE4000\")\nORANGERED3 = ManimColor(\"#CD3700\")\nORANGERED4 = ManimColor(\"#8B2500\")\nORCHID = ManimColor(\"#DA70D6\")\nORCHID1 = ManimColor(\"#FF83FA\")\nORCHID2 = ManimColor(\"#EE7AE9\")\nORCHID3 = ManimColor(\"#CD69C9\")\nORCHID4 = ManimColor(\"#8B4789\")\nPALE = ManimColor(\"#DB7093\")\nPALEGOLDENROD = ManimColor(\"#EEE8AA\")\nPALEGREEN = ManimColor(\"#98FB98\")\nPALEGREEN1 = ManimColor(\"#9AFF9A\")\nPALEGREEN2 = ManimColor(\"#90EE90\")\nPALEGREEN3 = ManimColor(\"#7CCD7C\")\nPALEGREEN4 = ManimColor(\"#548B54\")\nPALETURQUOISE = ManimColor(\"#AFEEEE\")\nPALETURQUOISE1 = ManimColor(\"#BBFFFF\")\nPALETURQUOISE2 = ManimColor(\"#AEEEEE\")\nPALETURQUOISE3 = ManimColor(\"#96CDCD\")\nPALETURQUOISE4 = ManimColor(\"#668B8B\")\nPALEVIOLETRED = ManimColor(\"#DB7093\")\nPALEVIOLETRED1 = ManimColor(\"#FF82AB\")\nPALEVIOLETRED2 = ManimColor(\"#EE799F\")\nPALEVIOLETRED3 = ManimColor(\"#CD6889\")\nPALEVIOLETRED4 = ManimColor(\"#8B475D\")\nPAPAYAWHIP = ManimColor(\"#FFEFD5\")\nPEACHPUFF1 = ManimColor(\"#FFDAB9\")\nPEACHPUFF2 = ManimColor(\"#EECBAD\")\nPEACHPUFF3 = ManimColor(\"#CDAF95\")\nPEACHPUFF4 = ManimColor(\"#8B7765\")\nPINK = ManimColor(\"#FFC0CB\")\nPINK1 = ManimColor(\"#FFB5C5\")\nPINK2 = ManimColor(\"#EEA9B8\")\nPINK3 = ManimColor(\"#CD919E\")\nPINK4 = ManimColor(\"#8B636C\")\nPLUM = ManimColor(\"#DDA0DD\")\nPLUM1 = ManimColor(\"#FFBBFF\")\nPLUM2 = ManimColor(\"#EEAEEE\")\nPLUM3 = ManimColor(\"#CD96CD\")\nPLUM4 = ManimColor(\"#8B668B\")\nPOWDERBLUE = ManimColor(\"#B0E0E6\")\nPURPLE = ManimColor(\"#A020F0\")\nPURPLE1 = ManimColor(\"#9B30FF\")\nPURPLE2 = ManimColor(\"#912CEE\")\nPURPLE3 = ManimColor(\"#7D26CD\")\nPURPLE4 = ManimColor(\"#551A8B\")\nRED1 = ManimColor(\"#FF0000\")\nRED2 = ManimColor(\"#EE0000\")\nRED3 = ManimColor(\"#CD0000\")\nRED4 = ManimColor(\"#8B0000\")\nROSYBROWN = ManimColor(\"#BC8F8F\")\nROSYBROWN1 = ManimColor(\"#FFC1C1\")\nROSYBROWN2 = ManimColor(\"#EEB4B4\")\nROSYBROWN3 = ManimColor(\"#CD9B9B\")\nROSYBROWN4 = ManimColor(\"#8B6969\")\nROYALBLUE = ManimColor(\"#4169E1\")\nROYALBLUE1 = ManimColor(\"#4876FF\")\nROYALBLUE2 = ManimColor(\"#436EEE\")\nROYALBLUE3 = ManimColor(\"#3A5FCD\")\nROYALBLUE4 = ManimColor(\"#27408B\")\nSADDLEBROWN = ManimColor(\"#8B4513\")\nSALMON = ManimColor(\"#FA8072\")\nSALMON1 = ManimColor(\"#FF8C69\")\nSALMON2 = ManimColor(\"#EE8262\")\nSALMON3 = ManimColor(\"#CD7054\")\nSALMON4 = ManimColor(\"#8B4C39\")\nSANDYBROWN = ManimColor(\"#F4A460\")\nSEAGREEN1 = ManimColor(\"#54FF9F\")\nSEAGREEN2 = ManimColor(\"#4EEE94\")\nSEAGREEN3 = ManimColor(\"#43CD80\")\nSEAGREEN4 = ManimColor(\"#2E8B57\")\nSEASHELL1 = ManimColor(\"#FFF5EE\")\nSEASHELL2 = ManimColor(\"#EEE5DE\")\nSEASHELL3 = ManimColor(\"#CDC5BF\")\nSEASHELL4 = ManimColor(\"#8B8682\")\nSIENNA = ManimColor(\"#A0522D\")\nSIENNA1 = ManimColor(\"#FF8247\")\nSIENNA2 = ManimColor(\"#EE7942\")\nSIENNA3 = ManimColor(\"#CD6839\")\nSIENNA4 = ManimColor(\"#8B4726\")\nSKYBLUE = ManimColor(\"#87CEEB\")\nSKYBLUE1 = ManimColor(\"#87CEFF\")\nSKYBLUE2 = ManimColor(\"#7EC0EE\")\nSKYBLUE3 = ManimColor(\"#6CA6CD\")\nSKYBLUE4 = ManimColor(\"#4A708B\")\nSLATEBLUE = ManimColor(\"#6A5ACD\")\nSLATEBLUE1 = ManimColor(\"#836FFF\")\nSLATEBLUE2 = ManimColor(\"#7A67EE\")\nSLATEBLUE3 = ManimColor(\"#6959CD\")\nSLATEBLUE4 = ManimColor(\"#473C8B\")\nSLATEGRAY = ManimColor(\"#708090\")\nSLATEGRAY1 = ManimColor(\"#C6E2FF\")\nSLATEGRAY2 = ManimColor(\"#B9D3EE\")\nSLATEGRAY3 = ManimColor(\"#9FB6CD\")\nSLATEGRAY4 = ManimColor(\"#6C7B8B\")\nSNOW1 = ManimColor(\"#FFFAFA\")\nSNOW2 = ManimColor(\"#EEE9E9\")\nSNOW3 = ManimColor(\"#CDC9C9\")\nSNOW4 = ManimColor(\"#8B8989\")\nSPRINGGREEN1 = ManimColor(\"#00FF7F\")\nSPRINGGREEN2 = ManimColor(\"#00EE76\")\nSPRINGGREEN3 = ManimColor(\"#00CD66\")\nSPRINGGREEN4 = ManimColor(\"#008B45\")\nSTEELBLUE = ManimColor(\"#4682B4\")\nSTEELBLUE1 = ManimColor(\"#63B8FF\")\nSTEELBLUE2 = ManimColor(\"#5CACEE\")\nSTEELBLUE3 = ManimColor(\"#4F94CD\")\nSTEELBLUE4 = ManimColor(\"#36648B\")\nTAN = ManimColor(\"#D2B48C\")\nTAN1 = ManimColor(\"#FFA54F\")\nTAN2 = ManimColor(\"#EE9A49\")\nTAN3 = ManimColor(\"#CD853F\")\nTAN4 = ManimColor(\"#8B5A2B\")\nTHISTLE = ManimColor(\"#D8BFD8\")\nTHISTLE1 = ManimColor(\"#FFE1FF\")\nTHISTLE2 = ManimColor(\"#EED2EE\")\nTHISTLE3 = ManimColor(\"#CDB5CD\")\nTHISTLE4 = ManimColor(\"#8B7B8B\")\nTOMATO1 = ManimColor(\"#FF6347\")\nTOMATO2 = ManimColor(\"#EE5C42\")\nTOMATO3 = ManimColor(\"#CD4F39\")\nTOMATO4 = ManimColor(\"#8B3626\")\nTURQUOISE = ManimColor(\"#40E0D0\")\nTURQUOISE1 = ManimColor(\"#00F5FF\")\nTURQUOISE2 = ManimColor(\"#00E5EE\")\nTURQUOISE3 = ManimColor(\"#00C5CD\")\nTURQUOISE4 = ManimColor(\"#00868B\")\nVIOLET = ManimColor(\"#EE82EE\")\nVIOLETRED = ManimColor(\"#D02090\")\nVIOLETRED1 = ManimColor(\"#FF3E96\")\nVIOLETRED2 = ManimColor(\"#EE3A8C\")\nVIOLETRED3 = ManimColor(\"#CD3278\")\nVIOLETRED4 = ManimColor(\"#8B2252\")\nWHEAT = ManimColor(\"#F5DEB3\")\nWHEAT1 = ManimColor(\"#FFE7BA\")\nWHEAT2 = ManimColor(\"#EED8AE\")\nWHEAT3 = ManimColor(\"#CDBA96\")\nWHEAT4 = ManimColor(\"#8B7E66\")\nWHITE = ManimColor(\"#FFFFFF\")\nWHITESMOKE = ManimColor(\"#F5F5F5\")\nYELLOW1 = ManimColor(\"#FFFF00\")\nYELLOW2 = ManimColor(\"#EEEE00\")\nYELLOW3 = ManimColor(\"#CDCD00\")\nYELLOW4 = ManimColor(\"#8B8B00\")\nYELLOWGREEN = ManimColor(\"#9ACD32\")\n"
  },
  {
    "path": "manim/utils/color/XKCD.py",
    "content": "\"\"\"Colors from the XKCD Color Name Survey\n\nXKCD is a popular `web comic <https://xkcd.com/353/>`__ created by Randall Munroe.\nHis \"`Color Name Survey <http://blog.xkcd.com/2010/05/03/color-survey-results/>`__\" (with\n200000 participants) resulted in a list of nearly 1000 color names.\n\nWhile the ``XKCD`` module is exposed to Manim's global name space, the colors included\nin it are not. This means that in order to use the colors, access them via the module name:\n\n.. code:: pycon\n\n    >>> from manim import XKCD\n    >>> XKCD.MANGO\n    ManimColor('#FFA62B')\n\n\nList of Color Constants\n-----------------------\n\nThese hex values are non official approximate values intended to simulate the colors in HTML,\ntaken from https://www.w3schools.com/colors/colors_xkcd.asp.\n\n.. automanimcolormodule:: manim.utils.color.XKCD\n\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom .core import ManimColor\n\nACIDGREEN = ManimColor(\"#8FFE09\")\nADOBE = ManimColor(\"#BD6C48\")\nALGAE = ManimColor(\"#54AC68\")\nALGAEGREEN = ManimColor(\"#21C36F\")\nALMOSTBLACK = ManimColor(\"#070D0D\")\nAMBER = ManimColor(\"#FEB308\")\nAMETHYST = ManimColor(\"#9B5FC0\")\nAPPLE = ManimColor(\"#6ECB3C\")\nAPPLEGREEN = ManimColor(\"#76CD26\")\nAPRICOT = ManimColor(\"#FFB16D\")\nAQUA = ManimColor(\"#13EAC9\")\nAQUABLUE = ManimColor(\"#02D8E9\")\nAQUAGREEN = ManimColor(\"#12E193\")\nAQUAMARINE = ManimColor(\"#2EE8BB\")\nARMYGREEN = ManimColor(\"#4B5D16\")\nASPARAGUS = ManimColor(\"#77AB56\")\nAUBERGINE = ManimColor(\"#3D0734\")\nAUBURN = ManimColor(\"#9A3001\")\nAVOCADO = ManimColor(\"#90B134\")\nAVOCADOGREEN = ManimColor(\"#87A922\")\nAZUL = ManimColor(\"#1D5DEC\")\nAZURE = ManimColor(\"#069AF3\")\nBABYBLUE = ManimColor(\"#A2CFFE\")\nBABYGREEN = ManimColor(\"#8CFF9E\")\nBABYPINK = ManimColor(\"#FFB7CE\")\nBABYPOO = ManimColor(\"#AB9004\")\nBABYPOOP = ManimColor(\"#937C00\")\nBABYPOOPGREEN = ManimColor(\"#8F9805\")\nBABYPUKEGREEN = ManimColor(\"#B6C406\")\nBABYPURPLE = ManimColor(\"#CA9BF7\")\nBABYSHITBROWN = ManimColor(\"#AD900D\")\nBABYSHITGREEN = ManimColor(\"#889717\")\nBANANA = ManimColor(\"#FFFF7E\")\nBANANAYELLOW = ManimColor(\"#FAFE4B\")\nBARBIEPINK = ManimColor(\"#FE46A5\")\nBARFGREEN = ManimColor(\"#94AC02\")\nBARNEY = ManimColor(\"#AC1DB8\")\nBARNEYPURPLE = ManimColor(\"#A00498\")\nBATTLESHIPGREY = ManimColor(\"#6B7C85\")\nBEIGE = ManimColor(\"#E6DAA6\")\nBERRY = ManimColor(\"#990F4B\")\nBILE = ManimColor(\"#B5C306\")\nBLACK = ManimColor(\"#000000\")\nBLAND = ManimColor(\"#AFA88B\")\nBLOOD = ManimColor(\"#770001\")\nBLOODORANGE = ManimColor(\"#FE4B03\")\nBLOODRED = ManimColor(\"#980002\")\nBLUE = ManimColor(\"#0343DF\")\nBLUEBERRY = ManimColor(\"#464196\")\nBLUEBLUE = ManimColor(\"#2242C7\")\nBLUEGREEN = ManimColor(\"#0F9B8E\")\nBLUEGREY = ManimColor(\"#85A3B2\")\nBLUEPURPLE = ManimColor(\"#5A06EF\")\nBLUEVIOLET = ManimColor(\"#5D06E9\")\nBLUEWITHAHINTOFPURPLE = ManimColor(\"#533CC6\")\nBLUEYGREEN = ManimColor(\"#2BB179\")\nBLUEYGREY = ManimColor(\"#89A0B0\")\nBLUEYPURPLE = ManimColor(\"#6241C7\")\nBLUISH = ManimColor(\"#2976BB\")\nBLUISHGREEN = ManimColor(\"#10A674\")\nBLUISHGREY = ManimColor(\"#748B97\")\nBLUISHPURPLE = ManimColor(\"#703BE7\")\nBLURPLE = ManimColor(\"#5539CC\")\nBLUSH = ManimColor(\"#F29E8E\")\nBLUSHPINK = ManimColor(\"#FE828C\")\nBOOGER = ManimColor(\"#9BB53C\")\nBOOGERGREEN = ManimColor(\"#96B403\")\nBORDEAUX = ManimColor(\"#7B002C\")\nBORINGGREEN = ManimColor(\"#63B365\")\nBOTTLEGREEN = ManimColor(\"#044A05\")\nBRICK = ManimColor(\"#A03623\")\nBRICKORANGE = ManimColor(\"#C14A09\")\nBRICKRED = ManimColor(\"#8F1402\")\nBRIGHTAQUA = ManimColor(\"#0BF9EA\")\nBRIGHTBLUE = ManimColor(\"#0165FC\")\nBRIGHTCYAN = ManimColor(\"#41FDFE\")\nBRIGHTGREEN = ManimColor(\"#01FF07\")\nBRIGHTLAVENDER = ManimColor(\"#C760FF\")\nBRIGHTLIGHTBLUE = ManimColor(\"#26F7FD\")\nBRIGHTLIGHTGREEN = ManimColor(\"#2DFE54\")\nBRIGHTLILAC = ManimColor(\"#C95EFB\")\nBRIGHTLIME = ManimColor(\"#87FD05\")\nBRIGHTLIMEGREEN = ManimColor(\"#65FE08\")\nBRIGHTMAGENTA = ManimColor(\"#FF08E8\")\nBRIGHTOLIVE = ManimColor(\"#9CBB04\")\nBRIGHTORANGE = ManimColor(\"#FF5B00\")\nBRIGHTPINK = ManimColor(\"#FE01B1\")\nBRIGHTPURPLE = ManimColor(\"#BE03FD\")\nBRIGHTRED = ManimColor(\"#FF000D\")\nBRIGHTSEAGREEN = ManimColor(\"#05FFA6\")\nBRIGHTSKYBLUE = ManimColor(\"#02CCFE\")\nBRIGHTTEAL = ManimColor(\"#01F9C6\")\nBRIGHTTURQUOISE = ManimColor(\"#0FFEF9\")\nBRIGHTVIOLET = ManimColor(\"#AD0AFD\")\nBRIGHTYELLOW = ManimColor(\"#FFFD01\")\nBRIGHTYELLOWGREEN = ManimColor(\"#9DFF00\")\nBRITISHRACINGGREEN = ManimColor(\"#05480D\")\nBRONZE = ManimColor(\"#A87900\")\nBROWN = ManimColor(\"#653700\")\nBROWNGREEN = ManimColor(\"#706C11\")\nBROWNGREY = ManimColor(\"#8D8468\")\nBROWNISH = ManimColor(\"#9C6D57\")\nBROWNISHGREEN = ManimColor(\"#6A6E09\")\nBROWNISHGREY = ManimColor(\"#86775F\")\nBROWNISHORANGE = ManimColor(\"#CB7723\")\nBROWNISHPINK = ManimColor(\"#C27E79\")\nBROWNISHPURPLE = ManimColor(\"#76424E\")\nBROWNISHRED = ManimColor(\"#9E3623\")\nBROWNISHYELLOW = ManimColor(\"#C9B003\")\nBROWNORANGE = ManimColor(\"#B96902\")\nBROWNRED = ManimColor(\"#922B05\")\nBROWNYELLOW = ManimColor(\"#B29705\")\nBROWNYGREEN = ManimColor(\"#6F6C0A\")\nBROWNYORANGE = ManimColor(\"#CA6B02\")\nBRUISE = ManimColor(\"#7E4071\")\nBUBBLEGUM = ManimColor(\"#FF6CB5\")\nBUBBLEGUMPINK = ManimColor(\"#FF69AF\")\nBUFF = ManimColor(\"#FEF69E\")\nBURGUNDY = ManimColor(\"#610023\")\nBURNTORANGE = ManimColor(\"#C04E01\")\nBURNTRED = ManimColor(\"#9F2305\")\nBURNTSIENA = ManimColor(\"#B75203\")\nBURNTSIENNA = ManimColor(\"#B04E0F\")\nBURNTUMBER = ManimColor(\"#A0450E\")\nBURNTYELLOW = ManimColor(\"#D5AB09\")\nBURPLE = ManimColor(\"#6832E3\")\nBUTTER = ManimColor(\"#FFFF81\")\nBUTTERSCOTCH = ManimColor(\"#FDB147\")\nBUTTERYELLOW = ManimColor(\"#FFFD74\")\nCADETBLUE = ManimColor(\"#4E7496\")\nCAMEL = ManimColor(\"#C69F59\")\nCAMO = ManimColor(\"#7F8F4E\")\nCAMOGREEN = ManimColor(\"#526525\")\nCAMOUFLAGEGREEN = ManimColor(\"#4B6113\")\nCANARY = ManimColor(\"#FDFF63\")\nCANARYYELLOW = ManimColor(\"#FFFE40\")\nCANDYPINK = ManimColor(\"#FF63E9\")\nCARAMEL = ManimColor(\"#AF6F09\")\nCARMINE = ManimColor(\"#9D0216\")\nCARNATION = ManimColor(\"#FD798F\")\nCARNATIONPINK = ManimColor(\"#FF7FA7\")\nCAROLINABLUE = ManimColor(\"#8AB8FE\")\nCELADON = ManimColor(\"#BEFDB7\")\nCELERY = ManimColor(\"#C1FD95\")\nCEMENT = ManimColor(\"#A5A391\")\nCERISE = ManimColor(\"#DE0C62\")\nCERULEAN = ManimColor(\"#0485D1\")\nCERULEANBLUE = ManimColor(\"#056EEE\")\nCHARCOAL = ManimColor(\"#343837\")\nCHARCOALGREY = ManimColor(\"#3C4142\")\nCHARTREUSE = ManimColor(\"#C1F80A\")\nCHERRY = ManimColor(\"#CF0234\")\nCHERRYRED = ManimColor(\"#F7022A\")\nCHESTNUT = ManimColor(\"#742802\")\nCHOCOLATE = ManimColor(\"#3D1C02\")\nCHOCOLATEBROWN = ManimColor(\"#411900\")\nCINNAMON = ManimColor(\"#AC4F06\")\nCLARET = ManimColor(\"#680018\")\nCLAY = ManimColor(\"#B66A50\")\nCLAYBROWN = ManimColor(\"#B2713D\")\nCLEARBLUE = ManimColor(\"#247AFD\")\nCOBALT = ManimColor(\"#1E488F\")\nCOBALTBLUE = ManimColor(\"#030AA7\")\nCOCOA = ManimColor(\"#875F42\")\nCOFFEE = ManimColor(\"#A6814C\")\nCOOLBLUE = ManimColor(\"#4984B8\")\nCOOLGREEN = ManimColor(\"#33B864\")\nCOOLGREY = ManimColor(\"#95A3A6\")\nCOPPER = ManimColor(\"#B66325\")\nCORAL = ManimColor(\"#FC5A50\")\nCORALPINK = ManimColor(\"#FF6163\")\nCORNFLOWER = ManimColor(\"#6A79F7\")\nCORNFLOWERBLUE = ManimColor(\"#5170D7\")\nCRANBERRY = ManimColor(\"#9E003A\")\nCREAM = ManimColor(\"#FFFFC2\")\nCREME = ManimColor(\"#FFFFB6\")\nCRIMSON = ManimColor(\"#8C000F\")\nCUSTARD = ManimColor(\"#FFFD78\")\nCYAN = ManimColor(\"#00FFFF\")\nDANDELION = ManimColor(\"#FEDF08\")\nDARK = ManimColor(\"#1B2431\")\nDARKAQUA = ManimColor(\"#05696B\")\nDARKAQUAMARINE = ManimColor(\"#017371\")\nDARKBEIGE = ManimColor(\"#AC9362\")\nDARKBLUE = ManimColor(\"#030764\")\nDARKBLUEGREEN = ManimColor(\"#005249\")\nDARKBLUEGREY = ManimColor(\"#1F3B4D\")\nDARKBROWN = ManimColor(\"#341C02\")\nDARKCORAL = ManimColor(\"#CF524E\")\nDARKCREAM = ManimColor(\"#FFF39A\")\nDARKCYAN = ManimColor(\"#0A888A\")\nDARKFORESTGREEN = ManimColor(\"#002D04\")\nDARKFUCHSIA = ManimColor(\"#9D0759\")\nDARKGOLD = ManimColor(\"#B59410\")\nDARKGRASSGREEN = ManimColor(\"#388004\")\nDARKGREEN = ManimColor(\"#054907\")\nDARKGREENBLUE = ManimColor(\"#1F6357\")\nDARKGREY = ManimColor(\"#363737\")\nDARKGREYBLUE = ManimColor(\"#29465B\")\nDARKHOTPINK = ManimColor(\"#D90166\")\nDARKINDIGO = ManimColor(\"#1F0954\")\nDARKISHBLUE = ManimColor(\"#014182\")\nDARKISHGREEN = ManimColor(\"#287C37\")\nDARKISHPINK = ManimColor(\"#DA467D\")\nDARKISHPURPLE = ManimColor(\"#751973\")\nDARKISHRED = ManimColor(\"#A90308\")\nDARKKHAKI = ManimColor(\"#9B8F55\")\nDARKLAVENDER = ManimColor(\"#856798\")\nDARKLILAC = ManimColor(\"#9C6DA5\")\nDARKLIME = ManimColor(\"#84B701\")\nDARKLIMEGREEN = ManimColor(\"#7EBD01\")\nDARKMAGENTA = ManimColor(\"#960056\")\nDARKMAROON = ManimColor(\"#3C0008\")\nDARKMAUVE = ManimColor(\"#874C62\")\nDARKMINT = ManimColor(\"#48C072\")\nDARKMINTGREEN = ManimColor(\"#20C073\")\nDARKMUSTARD = ManimColor(\"#A88905\")\nDARKNAVY = ManimColor(\"#000435\")\nDARKNAVYBLUE = ManimColor(\"#00022E\")\nDARKOLIVE = ManimColor(\"#373E02\")\nDARKOLIVEGREEN = ManimColor(\"#3C4D03\")\nDARKORANGE = ManimColor(\"#C65102\")\nDARKPASTELGREEN = ManimColor(\"#56AE57\")\nDARKPEACH = ManimColor(\"#DE7E5D\")\nDARKPERIWINKLE = ManimColor(\"#665FD1\")\nDARKPINK = ManimColor(\"#CB416B\")\nDARKPLUM = ManimColor(\"#3F012C\")\nDARKPURPLE = ManimColor(\"#35063E\")\nDARKRED = ManimColor(\"#840000\")\nDARKROSE = ManimColor(\"#B5485D\")\nDARKROYALBLUE = ManimColor(\"#02066F\")\nDARKSAGE = ManimColor(\"#598556\")\nDARKSALMON = ManimColor(\"#C85A53\")\nDARKSAND = ManimColor(\"#A88F59\")\nDARKSEAFOAM = ManimColor(\"#1FB57A\")\nDARKSEAFOAMGREEN = ManimColor(\"#3EAF76\")\nDARKSEAGREEN = ManimColor(\"#11875D\")\nDARKSKYBLUE = ManimColor(\"#448EE4\")\nDARKSLATEBLUE = ManimColor(\"#214761\")\nDARKTAN = ManimColor(\"#AF884A\")\nDARKTAUPE = ManimColor(\"#7F684E\")\nDARKTEAL = ManimColor(\"#014D4E\")\nDARKTURQUOISE = ManimColor(\"#045C5A\")\nDARKVIOLET = ManimColor(\"#34013F\")\nDARKYELLOW = ManimColor(\"#D5B60A\")\nDARKYELLOWGREEN = ManimColor(\"#728F02\")\nDEEPAQUA = ManimColor(\"#08787F\")\nDEEPBLUE = ManimColor(\"#040273\")\nDEEPBROWN = ManimColor(\"#410200\")\nDEEPGREEN = ManimColor(\"#02590F\")\nDEEPLAVENDER = ManimColor(\"#8D5EB7\")\nDEEPLILAC = ManimColor(\"#966EBD\")\nDEEPMAGENTA = ManimColor(\"#A0025C\")\nDEEPORANGE = ManimColor(\"#DC4D01\")\nDEEPPINK = ManimColor(\"#CB0162\")\nDEEPPURPLE = ManimColor(\"#36013F\")\nDEEPRED = ManimColor(\"#9A0200\")\nDEEPROSE = ManimColor(\"#C74767\")\nDEEPSEABLUE = ManimColor(\"#015482\")\nDEEPSKYBLUE = ManimColor(\"#0D75F8\")\nDEEPTEAL = ManimColor(\"#00555A\")\nDEEPTURQUOISE = ManimColor(\"#017374\")\nDEEPVIOLET = ManimColor(\"#490648\")\nDENIM = ManimColor(\"#3B638C\")\nDENIMBLUE = ManimColor(\"#3B5B92\")\nDESERT = ManimColor(\"#CCAD60\")\nDIARRHEA = ManimColor(\"#9F8303\")\nDIRT = ManimColor(\"#8A6E45\")\nDIRTBROWN = ManimColor(\"#836539\")\nDIRTYBLUE = ManimColor(\"#3F829D\")\nDIRTYGREEN = ManimColor(\"#667E2C\")\nDIRTYORANGE = ManimColor(\"#C87606\")\nDIRTYPINK = ManimColor(\"#CA7B80\")\nDIRTYPURPLE = ManimColor(\"#734A65\")\nDIRTYYELLOW = ManimColor(\"#CDC50A\")\nDODGERBLUE = ManimColor(\"#3E82FC\")\nDRAB = ManimColor(\"#828344\")\nDRABGREEN = ManimColor(\"#749551\")\nDRIEDBLOOD = ManimColor(\"#4B0101\")\nDUCKEGGBLUE = ManimColor(\"#C3FBF4\")\nDULLBLUE = ManimColor(\"#49759C\")\nDULLBROWN = ManimColor(\"#876E4B\")\nDULLGREEN = ManimColor(\"#74A662\")\nDULLORANGE = ManimColor(\"#D8863B\")\nDULLPINK = ManimColor(\"#D5869D\")\nDULLPURPLE = ManimColor(\"#84597E\")\nDULLRED = ManimColor(\"#BB3F3F\")\nDULLTEAL = ManimColor(\"#5F9E8F\")\nDULLYELLOW = ManimColor(\"#EEDC5B\")\nDUSK = ManimColor(\"#4E5481\")\nDUSKBLUE = ManimColor(\"#26538D\")\nDUSKYBLUE = ManimColor(\"#475F94\")\nDUSKYPINK = ManimColor(\"#CC7A8B\")\nDUSKYPURPLE = ManimColor(\"#895B7B\")\nDUSKYROSE = ManimColor(\"#BA6873\")\nDUST = ManimColor(\"#B2996E\")\nDUSTYBLUE = ManimColor(\"#5A86AD\")\nDUSTYGREEN = ManimColor(\"#76A973\")\nDUSTYLAVENDER = ManimColor(\"#AC86A8\")\nDUSTYORANGE = ManimColor(\"#F0833A\")\nDUSTYPINK = ManimColor(\"#D58A94\")\nDUSTYPURPLE = ManimColor(\"#825F87\")\nDUSTYRED = ManimColor(\"#B9484E\")\nDUSTYROSE = ManimColor(\"#C0737A\")\nDUSTYTEAL = ManimColor(\"#4C9085\")\nEARTH = ManimColor(\"#A2653E\")\nEASTERGREEN = ManimColor(\"#8CFD7E\")\nEASTERPURPLE = ManimColor(\"#C071FE\")\nECRU = ManimColor(\"#FEFFCA\")\nEGGPLANT = ManimColor(\"#380835\")\nEGGPLANTPURPLE = ManimColor(\"#430541\")\nEGGSHELL = ManimColor(\"#FFFCC4\")\nEGGSHELLBLUE = ManimColor(\"#C4FFF7\")\nELECTRICBLUE = ManimColor(\"#0652FF\")\nELECTRICGREEN = ManimColor(\"#21FC0D\")\nELECTRICLIME = ManimColor(\"#A8FF04\")\nELECTRICPINK = ManimColor(\"#FF0490\")\nELECTRICPURPLE = ManimColor(\"#AA23FF\")\nEMERALD = ManimColor(\"#01A049\")\nEMERALDGREEN = ManimColor(\"#028F1E\")\nEVERGREEN = ManimColor(\"#05472A\")\nFADEDBLUE = ManimColor(\"#658CBB\")\nFADEDGREEN = ManimColor(\"#7BB274\")\nFADEDORANGE = ManimColor(\"#F0944D\")\nFADEDPINK = ManimColor(\"#DE9DAC\")\nFADEDPURPLE = ManimColor(\"#916E99\")\nFADEDRED = ManimColor(\"#D3494E\")\nFADEDYELLOW = ManimColor(\"#FEFF7F\")\nFAWN = ManimColor(\"#CFAF7B\")\nFERN = ManimColor(\"#63A950\")\nFERNGREEN = ManimColor(\"#548D44\")\nFIREENGINERED = ManimColor(\"#FE0002\")\nFLATBLUE = ManimColor(\"#3C73A8\")\nFLATGREEN = ManimColor(\"#699D4C\")\nFLUORESCENTGREEN = ManimColor(\"#08FF08\")\nFLUROGREEN = ManimColor(\"#0AFF02\")\nFOAMGREEN = ManimColor(\"#90FDA9\")\nFOREST = ManimColor(\"#0B5509\")\nFORESTGREEN = ManimColor(\"#06470C\")\nFORRESTGREEN = ManimColor(\"#154406\")\nFRENCHBLUE = ManimColor(\"#436BAD\")\nFRESHGREEN = ManimColor(\"#69D84F\")\nFROGGREEN = ManimColor(\"#58BC08\")\nFUCHSIA = ManimColor(\"#ED0DD9\")\nGOLD = ManimColor(\"#DBB40C\")\nGOLDEN = ManimColor(\"#F5BF03\")\nGOLDENBROWN = ManimColor(\"#B27A01\")\nGOLDENROD = ManimColor(\"#F9BC08\")\nGOLDENYELLOW = ManimColor(\"#FEC615\")\nGRAPE = ManimColor(\"#6C3461\")\nGRAPEFRUIT = ManimColor(\"#FD5956\")\nGRAPEPURPLE = ManimColor(\"#5D1451\")\nGRASS = ManimColor(\"#5CAC2D\")\nGRASSGREEN = ManimColor(\"#3F9B0B\")\nGRASSYGREEN = ManimColor(\"#419C03\")\nGREEN = ManimColor(\"#15B01A\")\nGREENAPPLE = ManimColor(\"#5EDC1F\")\nGREENBLUE = ManimColor(\"#01C08D\")\nGREENBROWN = ManimColor(\"#544E03\")\nGREENGREY = ManimColor(\"#77926F\")\nGREENISH = ManimColor(\"#40A368\")\nGREENISHBEIGE = ManimColor(\"#C9D179\")\nGREENISHBLUE = ManimColor(\"#0B8B87\")\nGREENISHBROWN = ManimColor(\"#696112\")\nGREENISHCYAN = ManimColor(\"#2AFEB7\")\nGREENISHGREY = ManimColor(\"#96AE8D\")\nGREENISHTAN = ManimColor(\"#BCCB7A\")\nGREENISHTEAL = ManimColor(\"#32BF84\")\nGREENISHTURQUOISE = ManimColor(\"#00FBB0\")\nGREENISHYELLOW = ManimColor(\"#CDFD02\")\nGREENTEAL = ManimColor(\"#0CB577\")\nGREENYBLUE = ManimColor(\"#42B395\")\nGREENYBROWN = ManimColor(\"#696006\")\nGREENYELLOW = ManimColor(\"#B5CE08\")\nGREENYGREY = ManimColor(\"#7EA07A\")\nGREENYYELLOW = ManimColor(\"#C6F808\")\nGREY = ManimColor(\"#929591\")\nGREYBLUE = ManimColor(\"#647D8E\")\nGREYBROWN = ManimColor(\"#7F7053\")\nGREYGREEN = ManimColor(\"#86A17D\")\nGREYISH = ManimColor(\"#A8A495\")\nGREYISHBLUE = ManimColor(\"#5E819D\")\nGREYISHBROWN = ManimColor(\"#7A6A4F\")\nGREYISHGREEN = ManimColor(\"#82A67D\")\nGREYISHPINK = ManimColor(\"#C88D94\")\nGREYISHPURPLE = ManimColor(\"#887191\")\nGREYISHTEAL = ManimColor(\"#719F91\")\nGREYPINK = ManimColor(\"#C3909B\")\nGREYPURPLE = ManimColor(\"#826D8C\")\nGREYTEAL = ManimColor(\"#5E9B8A\")\nGROSSGREEN = ManimColor(\"#A0BF16\")\nGUNMETAL = ManimColor(\"#536267\")\nHAZEL = ManimColor(\"#8E7618\")\nHEATHER = ManimColor(\"#A484AC\")\nHELIOTROPE = ManimColor(\"#D94FF5\")\nHIGHLIGHTERGREEN = ManimColor(\"#1BFC06\")\nHOSPITALGREEN = ManimColor(\"#9BE5AA\")\nHOTGREEN = ManimColor(\"#25FF29\")\nHOTMAGENTA = ManimColor(\"#F504C9\")\nHOTPINK = ManimColor(\"#FF028D\")\nHOTPURPLE = ManimColor(\"#CB00F5\")\nHUNTERGREEN = ManimColor(\"#0B4008\")\nICE = ManimColor(\"#D6FFFA\")\nICEBLUE = ManimColor(\"#D7FFFE\")\nICKYGREEN = ManimColor(\"#8FAE22\")\nINDIANRED = ManimColor(\"#850E04\")\nINDIGO = ManimColor(\"#380282\")\nINDIGOBLUE = ManimColor(\"#3A18B1\")\nIRIS = ManimColor(\"#6258C4\")\nIRISHGREEN = ManimColor(\"#019529\")\nIVORY = ManimColor(\"#FFFFCB\")\nJADE = ManimColor(\"#1FA774\")\nJADEGREEN = ManimColor(\"#2BAF6A\")\nJUNGLEGREEN = ManimColor(\"#048243\")\nKELLEYGREEN = ManimColor(\"#009337\")\nKELLYGREEN = ManimColor(\"#02AB2E\")\nKERMITGREEN = ManimColor(\"#5CB200\")\nKEYLIME = ManimColor(\"#AEFF6E\")\nKHAKI = ManimColor(\"#AAA662\")\nKHAKIGREEN = ManimColor(\"#728639\")\nKIWI = ManimColor(\"#9CEF43\")\nKIWIGREEN = ManimColor(\"#8EE53F\")\nLAVENDER = ManimColor(\"#C79FEF\")\nLAVENDERBLUE = ManimColor(\"#8B88F8\")\nLAVENDERPINK = ManimColor(\"#DD85D7\")\nLAWNGREEN = ManimColor(\"#4DA409\")\nLEAF = ManimColor(\"#71AA34\")\nLEAFGREEN = ManimColor(\"#5CA904\")\nLEAFYGREEN = ManimColor(\"#51B73B\")\nLEATHER = ManimColor(\"#AC7434\")\nLEMON = ManimColor(\"#FDFF52\")\nLEMONGREEN = ManimColor(\"#ADF802\")\nLEMONLIME = ManimColor(\"#BFFE28\")\nLEMONYELLOW = ManimColor(\"#FDFF38\")\nLICHEN = ManimColor(\"#8FB67B\")\nLIGHTAQUA = ManimColor(\"#8CFFDB\")\nLIGHTAQUAMARINE = ManimColor(\"#7BFDC7\")\nLIGHTBEIGE = ManimColor(\"#FFFEB6\")\nLIGHTBLUE = ManimColor(\"#7BC8F6\")\nLIGHTBLUEGREEN = ManimColor(\"#7EFBB3\")\nLIGHTBLUEGREY = ManimColor(\"#B7C9E2\")\nLIGHTBLUISHGREEN = ManimColor(\"#76FDA8\")\nLIGHTBRIGHTGREEN = ManimColor(\"#53FE5C\")\nLIGHTBROWN = ManimColor(\"#AD8150\")\nLIGHTBURGUNDY = ManimColor(\"#A8415B\")\nLIGHTCYAN = ManimColor(\"#ACFFFC\")\nLIGHTEGGPLANT = ManimColor(\"#894585\")\nLIGHTERGREEN = ManimColor(\"#75FD63\")\nLIGHTERPURPLE = ManimColor(\"#A55AF4\")\nLIGHTFORESTGREEN = ManimColor(\"#4F9153\")\nLIGHTGOLD = ManimColor(\"#FDDC5C\")\nLIGHTGRASSGREEN = ManimColor(\"#9AF764\")\nLIGHTGREEN = ManimColor(\"#76FF7B\")\nLIGHTGREENBLUE = ManimColor(\"#56FCA2\")\nLIGHTGREENISHBLUE = ManimColor(\"#63F7B4\")\nLIGHTGREY = ManimColor(\"#D8DCD6\")\nLIGHTGREYBLUE = ManimColor(\"#9DBCD4\")\nLIGHTGREYGREEN = ManimColor(\"#B7E1A1\")\nLIGHTINDIGO = ManimColor(\"#6D5ACF\")\nLIGHTISHBLUE = ManimColor(\"#3D7AFD\")\nLIGHTISHGREEN = ManimColor(\"#61E160\")\nLIGHTISHPURPLE = ManimColor(\"#A552E6\")\nLIGHTISHRED = ManimColor(\"#FE2F4A\")\nLIGHTKHAKI = ManimColor(\"#E6F2A2\")\nLIGHTLAVENDAR = ManimColor(\"#EFC0FE\")\nLIGHTLAVENDER = ManimColor(\"#DFC5FE\")\nLIGHTLIGHTBLUE = ManimColor(\"#CAFFFB\")\nLIGHTLIGHTGREEN = ManimColor(\"#C8FFB0\")\nLIGHTLILAC = ManimColor(\"#EDC8FF\")\nLIGHTLIME = ManimColor(\"#AEFD6C\")\nLIGHTLIMEGREEN = ManimColor(\"#B9FF66\")\nLIGHTMAGENTA = ManimColor(\"#FA5FF7\")\nLIGHTMAROON = ManimColor(\"#A24857\")\nLIGHTMAUVE = ManimColor(\"#C292A1\")\nLIGHTMINT = ManimColor(\"#B6FFBB\")\nLIGHTMINTGREEN = ManimColor(\"#A6FBB2\")\nLIGHTMOSSGREEN = ManimColor(\"#A6C875\")\nLIGHTMUSTARD = ManimColor(\"#F7D560\")\nLIGHTNAVY = ManimColor(\"#155084\")\nLIGHTNAVYBLUE = ManimColor(\"#2E5A88\")\nLIGHTNEONGREEN = ManimColor(\"#4EFD54\")\nLIGHTOLIVE = ManimColor(\"#ACBF69\")\nLIGHTOLIVEGREEN = ManimColor(\"#A4BE5C\")\nLIGHTORANGE = ManimColor(\"#FDAA48\")\nLIGHTPASTELGREEN = ManimColor(\"#B2FBA5\")\nLIGHTPEACH = ManimColor(\"#FFD8B1\")\nLIGHTPEAGREEN = ManimColor(\"#C4FE82\")\nLIGHTPERIWINKLE = ManimColor(\"#C1C6FC\")\nLIGHTPINK = ManimColor(\"#FFD1DF\")\nLIGHTPLUM = ManimColor(\"#9D5783\")\nLIGHTPURPLE = ManimColor(\"#BF77F6\")\nLIGHTRED = ManimColor(\"#FF474C\")\nLIGHTROSE = ManimColor(\"#FFC5CB\")\nLIGHTROYALBLUE = ManimColor(\"#3A2EFE\")\nLIGHTSAGE = ManimColor(\"#BCECAC\")\nLIGHTSALMON = ManimColor(\"#FEA993\")\nLIGHTSEAFOAM = ManimColor(\"#A0FEBF\")\nLIGHTSEAFOAMGREEN = ManimColor(\"#a7ffb5\")\nLIGHTSEAGREEN = ManimColor(\"#98F6B0\")\nLIGHTSKYBLUE = ManimColor(\"#C6FCFF\")\nLIGHTTAN = ManimColor(\"#FBEEAC\")\nLIGHTTEAL = ManimColor(\"#90E4C1\")\nLIGHTTURQUOISE = ManimColor(\"#7EF4CC\")\nLIGHTURPLE = ManimColor(\"#B36FF6\")\nLIGHTVIOLET = ManimColor(\"#D6B4FC\")\nLIGHTYELLOW = ManimColor(\"#FFFE7A\")\nLIGHTYELLOWGREEN = ManimColor(\"#CCFD7F\")\nLIGHTYELLOWISHGREEN = ManimColor(\"#C2FF89\")\nLILAC = ManimColor(\"#CEA2FD\")\nLILIAC = ManimColor(\"#C48EFD\")\nLIME = ManimColor(\"#AAFF32\")\nLIMEGREEN = ManimColor(\"#89FE05\")\nLIMEYELLOW = ManimColor(\"#D0FE1D\")\nLIPSTICK = ManimColor(\"#D5174E\")\nLIPSTICKRED = ManimColor(\"#C0022F\")\nMACARONIANDCHEESE = ManimColor(\"#EFB435\")\nMAGENTA = ManimColor(\"#C20078\")\nMAHOGANY = ManimColor(\"#4A0100\")\nMAIZE = ManimColor(\"#F4D054\")\nMANGO = ManimColor(\"#FFA62B\")\nMANILLA = ManimColor(\"#FFFA86\")\nMARIGOLD = ManimColor(\"#FCC006\")\nMARINE = ManimColor(\"#042E60\")\nMARINEBLUE = ManimColor(\"#01386A\")\nMAROON = ManimColor(\"#650021\")\nMAUVE = ManimColor(\"#AE7181\")\nMEDIUMBLUE = ManimColor(\"#2C6FBB\")\nMEDIUMBROWN = ManimColor(\"#7F5112\")\nMEDIUMGREEN = ManimColor(\"#39AD48\")\nMEDIUMGREY = ManimColor(\"#7D7F7C\")\nMEDIUMPINK = ManimColor(\"#F36196\")\nMEDIUMPURPLE = ManimColor(\"#9E43A2\")\nMELON = ManimColor(\"#FF7855\")\nMERLOT = ManimColor(\"#730039\")\nMETALLICBLUE = ManimColor(\"#4F738E\")\nMIDBLUE = ManimColor(\"#276AB3\")\nMIDGREEN = ManimColor(\"#50A747\")\nMIDNIGHT = ManimColor(\"#03012D\")\nMIDNIGHTBLUE = ManimColor(\"#020035\")\nMIDNIGHTPURPLE = ManimColor(\"#280137\")\nMILITARYGREEN = ManimColor(\"#667C3E\")\nMILKCHOCOLATE = ManimColor(\"#7F4E1E\")\nMINT = ManimColor(\"#9FFEB0\")\nMINTGREEN = ManimColor(\"#8FFF9F\")\nMINTYGREEN = ManimColor(\"#0BF77D\")\nMOCHA = ManimColor(\"#9D7651\")\nMOSS = ManimColor(\"#769958\")\nMOSSGREEN = ManimColor(\"#658B38\")\nMOSSYGREEN = ManimColor(\"#638B27\")\nMUD = ManimColor(\"#735C12\")\nMUDBROWN = ManimColor(\"#60460F\")\nMUDDYBROWN = ManimColor(\"#886806\")\nMUDDYGREEN = ManimColor(\"#657432\")\nMUDDYYELLOW = ManimColor(\"#BFAC05\")\nMUDGREEN = ManimColor(\"#606602\")\nMULBERRY = ManimColor(\"#920A4E\")\nMURKYGREEN = ManimColor(\"#6C7A0E\")\nMUSHROOM = ManimColor(\"#BA9E88\")\nMUSTARD = ManimColor(\"#CEB301\")\nMUSTARDBROWN = ManimColor(\"#AC7E04\")\nMUSTARDGREEN = ManimColor(\"#A8B504\")\nMUSTARDYELLOW = ManimColor(\"#D2BD0A\")\nMUTEDBLUE = ManimColor(\"#3B719F\")\nMUTEDGREEN = ManimColor(\"#5FA052\")\nMUTEDPINK = ManimColor(\"#D1768F\")\nMUTEDPURPLE = ManimColor(\"#805B87\")\nNASTYGREEN = ManimColor(\"#70B23F\")\nNAVY = ManimColor(\"#01153E\")\nNAVYBLUE = ManimColor(\"#001146\")\nNAVYGREEN = ManimColor(\"#35530A\")\nNEONBLUE = ManimColor(\"#04D9FF\")\nNEONGREEN = ManimColor(\"#0CFF0C\")\nNEONPINK = ManimColor(\"#FE019A\")\nNEONPURPLE = ManimColor(\"#BC13FE\")\nNEONRED = ManimColor(\"#FF073A\")\nNEONYELLOW = ManimColor(\"#CFFF04\")\nNICEBLUE = ManimColor(\"#107AB0\")\nNIGHTBLUE = ManimColor(\"#040348\")\nOCEAN = ManimColor(\"#017B92\")\nOCEANBLUE = ManimColor(\"#03719C\")\nOCEANGREEN = ManimColor(\"#3D9973\")\nOCHER = ManimColor(\"#BF9B0C\")\nOCHRE = ManimColor(\"#BF9005\")\nOCRE = ManimColor(\"#C69C04\")\nOFFBLUE = ManimColor(\"#5684AE\")\nOFFGREEN = ManimColor(\"#6BA353\")\nOFFWHITE = ManimColor(\"#FFFFE4\")\nOFFYELLOW = ManimColor(\"#F1F33F\")\nOLDPINK = ManimColor(\"#C77986\")\nOLDROSE = ManimColor(\"#C87F89\")\nOLIVE = ManimColor(\"#6E750E\")\nOLIVEBROWN = ManimColor(\"#645403\")\nOLIVEDRAB = ManimColor(\"#6F7632\")\nOLIVEGREEN = ManimColor(\"#677A04\")\nOLIVEYELLOW = ManimColor(\"#C2B709\")\nORANGE = ManimColor(\"#F97306\")\nORANGEBROWN = ManimColor(\"#BE6400\")\nORANGEISH = ManimColor(\"#FD8D49\")\nORANGEPINK = ManimColor(\"#FF6F52\")\nORANGERED = ManimColor(\"#FE420F\")\nORANGEYBROWN = ManimColor(\"#B16002\")\nORANGEYELLOW = ManimColor(\"#FFAD01\")\nORANGEYRED = ManimColor(\"#FA4224\")\nORANGEYYELLOW = ManimColor(\"#FDB915\")\nORANGISH = ManimColor(\"#FC824A\")\nORANGISHBROWN = ManimColor(\"#B25F03\")\nORANGISHRED = ManimColor(\"#F43605\")\nORCHID = ManimColor(\"#C875C4\")\nPALE = ManimColor(\"#FFF9D0\")\nPALEAQUA = ManimColor(\"#B8FFEB\")\nPALEBLUE = ManimColor(\"#D0FEFE\")\nPALEBROWN = ManimColor(\"#B1916E\")\nPALECYAN = ManimColor(\"#B7FFFA\")\nPALEGOLD = ManimColor(\"#FDDE6C\")\nPALEGREEN = ManimColor(\"#C7FDB5\")\nPALEGREY = ManimColor(\"#FDFDFE\")\nPALELAVENDER = ManimColor(\"#EECFFE\")\nPALELIGHTGREEN = ManimColor(\"#B1FC99\")\nPALELILAC = ManimColor(\"#E4CBFF\")\nPALELIME = ManimColor(\"#BEFD73\")\nPALELIMEGREEN = ManimColor(\"#B1FF65\")\nPALEMAGENTA = ManimColor(\"#D767AD\")\nPALEMAUVE = ManimColor(\"#FED0FC\")\nPALEOLIVE = ManimColor(\"#B9CC81\")\nPALEOLIVEGREEN = ManimColor(\"#B1D27B\")\nPALEORANGE = ManimColor(\"#FFA756\")\nPALEPEACH = ManimColor(\"#FFE5AD\")\nPALEPINK = ManimColor(\"#FFCFDC\")\nPALEPURPLE = ManimColor(\"#B790D4\")\nPALERED = ManimColor(\"#D9544D\")\nPALEROSE = ManimColor(\"#FDC1C5\")\nPALESALMON = ManimColor(\"#FFB19A\")\nPALESKYBLUE = ManimColor(\"#BDF6FE\")\nPALETEAL = ManimColor(\"#82CBB2\")\nPALETURQUOISE = ManimColor(\"#A5FBD5\")\nPALEVIOLET = ManimColor(\"#CEAEFA\")\nPALEYELLOW = ManimColor(\"#FFFF84\")\nPARCHMENT = ManimColor(\"#FEFCAF\")\nPASTELBLUE = ManimColor(\"#A2BFFE\")\nPASTELGREEN = ManimColor(\"#B0FF9D\")\nPASTELORANGE = ManimColor(\"#FF964F\")\nPASTELPINK = ManimColor(\"#FFBACD\")\nPASTELPURPLE = ManimColor(\"#CAA0FF\")\nPASTELRED = ManimColor(\"#DB5856\")\nPASTELYELLOW = ManimColor(\"#FFFE71\")\nPEA = ManimColor(\"#A4BF20\")\nPEACH = ManimColor(\"#FFB07C\")\nPEACHYPINK = ManimColor(\"#FF9A8A\")\nPEACOCKBLUE = ManimColor(\"#016795\")\nPEAGREEN = ManimColor(\"#8EAB12\")\nPEAR = ManimColor(\"#CBF85F\")\nPEASOUP = ManimColor(\"#929901\")\nPEASOUPGREEN = ManimColor(\"#94A617\")\nPERIWINKLE = ManimColor(\"#8E82FE\")\nPERIWINKLEBLUE = ManimColor(\"#8F99FB\")\nPERRYWINKLE = ManimColor(\"#8F8CE7\")\nPETROL = ManimColor(\"#005F6A\")\nPIGPINK = ManimColor(\"#E78EA5\")\nPINE = ManimColor(\"#2B5D34\")\nPINEGREEN = ManimColor(\"#0A481E\")\nPINK = ManimColor(\"#FF81C0\")\nPINKISH = ManimColor(\"#D46A7E\")\nPINKISHBROWN = ManimColor(\"#B17261\")\nPINKISHGREY = ManimColor(\"#C8ACA9\")\nPINKISHORANGE = ManimColor(\"#FF724C\")\nPINKISHPURPLE = ManimColor(\"#D648D7\")\nPINKISHRED = ManimColor(\"#F10C45\")\nPINKISHTAN = ManimColor(\"#D99B82\")\nPINKPURPLE = ManimColor(\"#EF1DE7\")\nPINKRED = ManimColor(\"#F5054F\")\nPINKY = ManimColor(\"#FC86AA\")\nPINKYPURPLE = ManimColor(\"#C94CBE\")\nPINKYRED = ManimColor(\"#FC2647\")\nPISSYELLOW = ManimColor(\"#DDD618\")\nPISTACHIO = ManimColor(\"#C0FA8B\")\nPLUM = ManimColor(\"#580F41\")\nPLUMPURPLE = ManimColor(\"#4E0550\")\nPOISONGREEN = ManimColor(\"#40FD14\")\nPOO = ManimColor(\"#8F7303\")\nPOOBROWN = ManimColor(\"#885F01\")\nPOOP = ManimColor(\"#7F5E00\")\nPOOPBROWN = ManimColor(\"#7A5901\")\nPOOPGREEN = ManimColor(\"#6F7C00\")\nPOWDERBLUE = ManimColor(\"#B1D1FC\")\nPOWDERPINK = ManimColor(\"#FFB2D0\")\nPRIMARYBLUE = ManimColor(\"#0804F9\")\nPRUSSIANBLUE = ManimColor(\"#004577\")\nPUCE = ManimColor(\"#A57E52\")\nPUKE = ManimColor(\"#A5A502\")\nPUKEBROWN = ManimColor(\"#947706\")\nPUKEGREEN = ManimColor(\"#9AAE07\")\nPUKEYELLOW = ManimColor(\"#C2BE0E\")\nPUMPKIN = ManimColor(\"#E17701\")\nPUMPKINORANGE = ManimColor(\"#FB7D07\")\nPUREBLUE = ManimColor(\"#0203E2\")\nPURPLE = ManimColor(\"#7E1E9C\")\nPURPLEBLUE = ManimColor(\"#5D21D0\")\nPURPLEBROWN = ManimColor(\"#673A3F\")\nPURPLEGREY = ManimColor(\"#866F85\")\nPURPLEISH = ManimColor(\"#98568D\")\nPURPLEISHBLUE = ManimColor(\"#6140EF\")\nPURPLEISHPINK = ManimColor(\"#DF4EC8\")\nPURPLEPINK = ManimColor(\"#D725DE\")\nPURPLERED = ManimColor(\"#990147\")\nPURPLEY = ManimColor(\"#8756E4\")\nPURPLEYBLUE = ManimColor(\"#5F34E7\")\nPURPLEYGREY = ManimColor(\"#947E94\")\nPURPLEYPINK = ManimColor(\"#C83CB9\")\nPURPLISH = ManimColor(\"#94568C\")\nPURPLISHBLUE = ManimColor(\"#601EF9\")\nPURPLISHBROWN = ManimColor(\"#6B4247\")\nPURPLISHGREY = ManimColor(\"#7A687F\")\nPURPLISHPINK = ManimColor(\"#CE5DAE\")\nPURPLISHRED = ManimColor(\"#B0054B\")\nPURPLY = ManimColor(\"#983FB2\")\nPURPLYBLUE = ManimColor(\"#661AEE\")\nPURPLYPINK = ManimColor(\"#F075E6\")\nPUTTY = ManimColor(\"#BEAE8A\")\nRACINGGREEN = ManimColor(\"#014600\")\nRADIOACTIVEGREEN = ManimColor(\"#2CFA1F\")\nRASPBERRY = ManimColor(\"#B00149\")\nRAWSIENNA = ManimColor(\"#9A6200\")\nRAWUMBER = ManimColor(\"#A75E09\")\nREALLYLIGHTBLUE = ManimColor(\"#D4FFFF\")\nRED = ManimColor(\"#E50000\")\nREDBROWN = ManimColor(\"#8B2E16\")\nREDDISH = ManimColor(\"#C44240\")\nREDDISHBROWN = ManimColor(\"#7F2B0A\")\nREDDISHGREY = ManimColor(\"#997570\")\nREDDISHORANGE = ManimColor(\"#F8481C\")\nREDDISHPINK = ManimColor(\"#FE2C54\")\nREDDISHPURPLE = ManimColor(\"#910951\")\nREDDYBROWN = ManimColor(\"#6E1005\")\nREDORANGE = ManimColor(\"#FD3C06\")\nREDPINK = ManimColor(\"#FA2A55\")\nREDPURPLE = ManimColor(\"#820747\")\nREDVIOLET = ManimColor(\"#9E0168\")\nREDWINE = ManimColor(\"#8C0034\")\nRICHBLUE = ManimColor(\"#021BF9\")\nRICHPURPLE = ManimColor(\"#720058\")\nROBINEGGBLUE = ManimColor(\"#8AF1FE\")\nROBINSEGG = ManimColor(\"#6DEDFD\")\nROBINSEGGBLUE = ManimColor(\"#98EFF9\")\nROSA = ManimColor(\"#FE86A4\")\nROSE = ManimColor(\"#CF6275\")\nROSEPINK = ManimColor(\"#F7879A\")\nROSERED = ManimColor(\"#BE013C\")\nROSYPINK = ManimColor(\"#F6688E\")\nROGUE = ManimColor(\"#AB1239\")\nROYAL = ManimColor(\"#0C1793\")\nROYALBLUE = ManimColor(\"#0504AA\")\nROYALPURPLE = ManimColor(\"#4B006E\")\nRUBY = ManimColor(\"#CA0147\")\nRUSSET = ManimColor(\"#A13905\")\nRUST = ManimColor(\"#A83C09\")\nRUSTBROWN = ManimColor(\"#8B3103\")\nRUSTORANGE = ManimColor(\"#C45508\")\nRUSTRED = ManimColor(\"#AA2704\")\nRUSTYORANGE = ManimColor(\"#CD5909\")\nRUSTYRED = ManimColor(\"#AF2F0D\")\nSAFFRON = ManimColor(\"#FEB209\")\nSAGE = ManimColor(\"#87AE73\")\nSAGEGREEN = ManimColor(\"#88B378\")\nSALMON = ManimColor(\"#FF796C\")\nSALMONPINK = ManimColor(\"#FE7B7C\")\nSAND = ManimColor(\"#E2CA76\")\nSANDBROWN = ManimColor(\"#CBA560\")\nSANDSTONE = ManimColor(\"#C9AE74\")\nSANDY = ManimColor(\"#F1DA7A\")\nSANDYBROWN = ManimColor(\"#C4A661\")\nSANDYELLOW = ManimColor(\"#FCE166\")\nSANDYYELLOW = ManimColor(\"#FDEE73\")\nSAPGREEN = ManimColor(\"#5C8B15\")\nSAPPHIRE = ManimColor(\"#2138AB\")\nSCARLET = ManimColor(\"#BE0119\")\nSEA = ManimColor(\"#3C9992\")\nSEABLUE = ManimColor(\"#047495\")\nSEAFOAM = ManimColor(\"#80F9AD\")\nSEAFOAMBLUE = ManimColor(\"#78D1B6\")\nSEAFOAMGREEN = ManimColor(\"#7AF9AB\")\nSEAGREEN = ManimColor(\"#53FCA1\")\nSEAWEED = ManimColor(\"#18D17B\")\nSEAWEEDGREEN = ManimColor(\"#35AD6B\")\nSEPIA = ManimColor(\"#985E2B\")\nSHAMROCK = ManimColor(\"#01B44C\")\nSHAMROCKGREEN = ManimColor(\"#02C14D\")\nSHIT = ManimColor(\"#7F5F00\")\nSHITBROWN = ManimColor(\"#7B5804\")\nSHITGREEN = ManimColor(\"#758000\")\nSHOCKINGPINK = ManimColor(\"#FE02A2\")\nSICKGREEN = ManimColor(\"#9DB92C\")\nSICKLYGREEN = ManimColor(\"#94B21C\")\nSICKLYYELLOW = ManimColor(\"#D0E429\")\nSIENNA = ManimColor(\"#A9561E\")\nSILVER = ManimColor(\"#C5C9C7\")\nSKY = ManimColor(\"#82CAFC\")\nSKYBLUE = ManimColor(\"#75BBFD\")\nSLATE = ManimColor(\"#516572\")\nSLATEBLUE = ManimColor(\"#5B7C99\")\nSLATEGREEN = ManimColor(\"#658D6D\")\nSLATEGREY = ManimColor(\"#59656D\")\nSLIMEGREEN = ManimColor(\"#99CC04\")\nSNOT = ManimColor(\"#ACBB0D\")\nSNOTGREEN = ManimColor(\"#9DC100\")\nSOFTBLUE = ManimColor(\"#6488EA\")\nSOFTGREEN = ManimColor(\"#6FC276\")\nSOFTPINK = ManimColor(\"#FDB0C0\")\nSOFTPURPLE = ManimColor(\"#A66FB5\")\nSPEARMINT = ManimColor(\"#1EF876\")\nSPRINGGREEN = ManimColor(\"#A9F971\")\nSPRUCE = ManimColor(\"#0A5F38\")\nSQUASH = ManimColor(\"#F2AB15\")\nSTEEL = ManimColor(\"#738595\")\nSTEELBLUE = ManimColor(\"#5A7D9A\")\nSTEELGREY = ManimColor(\"#6F828A\")\nSTONE = ManimColor(\"#ADA587\")\nSTORMYBLUE = ManimColor(\"#507B9C\")\nSTRAW = ManimColor(\"#FCF679\")\nSTRAWBERRY = ManimColor(\"#FB2943\")\nSTRONGBLUE = ManimColor(\"#0C06F7\")\nSTRONGPINK = ManimColor(\"#FF0789\")\nSUNFLOWER = ManimColor(\"#FFC512\")\nSUNFLOWERYELLOW = ManimColor(\"#FFDA03\")\nSUNNYYELLOW = ManimColor(\"#FFF917\")\nSUNSHINEYELLOW = ManimColor(\"#FFFD37\")\nSUNYELLOW = ManimColor(\"#FFDF22\")\nSWAMP = ManimColor(\"#698339\")\nSWAMPGREEN = ManimColor(\"#748500\")\nTAN = ManimColor(\"#D1B26F\")\nTANBROWN = ManimColor(\"#AB7E4C\")\nTANGERINE = ManimColor(\"#FF9408\")\nTANGREEN = ManimColor(\"#A9BE70\")\nTAUPE = ManimColor(\"#B9A281\")\nTEA = ManimColor(\"#65AB7C\")\nTEAGREEN = ManimColor(\"#BDF8A3\")\nTEAL = ManimColor(\"#029386\")\nTEALBLUE = ManimColor(\"#01889F\")\nTEALGREEN = ManimColor(\"#25A36F\")\nTEALISH = ManimColor(\"#24BCA8\")\nTEALISHGREEN = ManimColor(\"#0CDC73\")\nTERRACOTA = ManimColor(\"#CB6843\")\nTERRACOTTA = ManimColor(\"#C9643B\")\nTIFFANYBLUE = ManimColor(\"#7BF2DA\")\nTOMATO = ManimColor(\"#EF4026\")\nTOMATORED = ManimColor(\"#EC2D01\")\nTOPAZ = ManimColor(\"#13BBAF\")\nTOUPE = ManimColor(\"#C7AC7D\")\nTOXICGREEN = ManimColor(\"#61DE2A\")\nTREEGREEN = ManimColor(\"#2A7E19\")\nTRUEBLUE = ManimColor(\"#010FCC\")\nTRUEGREEN = ManimColor(\"#089404\")\nTURQUOISE = ManimColor(\"#06C2AC\")\nTURQUOISEBLUE = ManimColor(\"#06B1C4\")\nTURQUOISEGREEN = ManimColor(\"#04F489\")\nTURTLEGREEN = ManimColor(\"#75B84F\")\nTWILIGHT = ManimColor(\"#4E518B\")\nTWILIGHTBLUE = ManimColor(\"#0A437A\")\nUGLYBLUE = ManimColor(\"#31668A\")\nUGLYBROWN = ManimColor(\"#7D7103\")\nUGLYGREEN = ManimColor(\"#7A9703\")\nUGLYPINK = ManimColor(\"#CD7584\")\nUGLYPURPLE = ManimColor(\"#A442A0\")\nUGLYYELLOW = ManimColor(\"#D0C101\")\nULTRAMARINE = ManimColor(\"#2000B1\")\nULTRAMARINEBLUE = ManimColor(\"#1805DB\")\nUMBER = ManimColor(\"#B26400\")\nVELVET = ManimColor(\"#750851\")\nVERMILION = ManimColor(\"#F4320C\")\nVERYDARKBLUE = ManimColor(\"#000133\")\nVERYDARKBROWN = ManimColor(\"#1D0200\")\nVERYDARKGREEN = ManimColor(\"#062E03\")\nVERYDARKPURPLE = ManimColor(\"#2A0134\")\nVERYLIGHTBLUE = ManimColor(\"#D5FFFF\")\nVERYLIGHTBROWN = ManimColor(\"#D3B683\")\nVERYLIGHTGREEN = ManimColor(\"#D1FFBD\")\nVERYLIGHTPINK = ManimColor(\"#FFF4F2\")\nVERYLIGHTPURPLE = ManimColor(\"#F6CEFC\")\nVERYPALEBLUE = ManimColor(\"#D6FFFE\")\nVERYPALEGREEN = ManimColor(\"#CFFDBC\")\nVIBRANTBLUE = ManimColor(\"#0339F8\")\nVIBRANTGREEN = ManimColor(\"#0ADD08\")\nVIBRANTPURPLE = ManimColor(\"#AD03DE\")\nVIOLET = ManimColor(\"#9A0EEA\")\nVIOLETBLUE = ManimColor(\"#510AC9\")\nVIOLETPINK = ManimColor(\"#FB5FFC\")\nVIOLETRED = ManimColor(\"#A50055\")\nVIRIDIAN = ManimColor(\"#1E9167\")\nVIVIDBLUE = ManimColor(\"#152EFF\")\nVIVIDGREEN = ManimColor(\"#2FEF10\")\nVIVIDPURPLE = ManimColor(\"#9900FA\")\nVOMIT = ManimColor(\"#A2A415\")\nVOMITGREEN = ManimColor(\"#89A203\")\nVOMITYELLOW = ManimColor(\"#C7C10C\")\nWARMBLUE = ManimColor(\"#4B57DB\")\nWARMBROWN = ManimColor(\"#964E02\")\nWARMGREY = ManimColor(\"#978A84\")\nWARMPINK = ManimColor(\"#FB5581\")\nWARMPURPLE = ManimColor(\"#952E8F\")\nWASHEDOUTGREEN = ManimColor(\"#BCF5A6\")\nWATERBLUE = ManimColor(\"#0E87CC\")\nWATERMELON = ManimColor(\"#FD4659\")\nWEIRDGREEN = ManimColor(\"#3AE57F\")\nWHEAT = ManimColor(\"#FBDD7E\")\nWHITE = ManimColor(\"#FFFFFF\")\nWINDOWSBLUE = ManimColor(\"#3778BF\")\nWINE = ManimColor(\"#80013F\")\nWINERED = ManimColor(\"#7B0323\")\nWINTERGREEN = ManimColor(\"#20F986\")\nWISTERIA = ManimColor(\"#A87DC2\")\nYELLOW = ManimColor(\"#FFFF14\")\nYELLOWBROWN = ManimColor(\"#B79400\")\nYELLOWGREEN = ManimColor(\"#BBF90F\")\nYELLOWISH = ManimColor(\"#FAEE66\")\nYELLOWISHBROWN = ManimColor(\"#9B7A01\")\nYELLOWISHGREEN = ManimColor(\"#B0DD16\")\nYELLOWISHORANGE = ManimColor(\"#FFAB0F\")\nYELLOWISHTAN = ManimColor(\"#FCFC81\")\nYELLOWOCHRE = ManimColor(\"#CB9D06\")\nYELLOWORANGE = ManimColor(\"#FCB001\")\nYELLOWTAN = ManimColor(\"#FFE36E\")\nYELLOWYBROWN = ManimColor(\"#AE8B0C\")\nYELLOWYGREEN = ManimColor(\"#BFF128\")\n"
  },
  {
    "path": "manim/utils/color/__init__.py",
    "content": "\"\"\"Utilities for working with colors and predefined color constants.\n\nColor data structure\n--------------------\n\n.. autosummary::\n   :toctree: ../reference\n\n   core\n\n\nPredefined colors\n-----------------\n\nThere are several predefined colors available in Manim:\n\n- The colors listed in :mod:`.color.manim_colors` are loaded into\n  Manim's global name space.\n- The colors in :mod:`.color.AS2700`, :mod:`.color.BS381`,\n  :mod:`.color.DVIPSNAMES`, :mod:`.color.SVGNAMES`, :mod:`.color.X11` and\n  :mod:`.color.XKCD` need to be accessed via their module (which are available\n  in Manim's global name space), or imported separately. For example:\n\n  .. code:: pycon\n\n     >>> from manim import XKCD\n     >>> XKCD.AVOCADO\n     ManimColor('#90B134')\n\n  Or, alternatively:\n\n  .. code:: pycon\n\n     >>> from manim.utils.color.XKCD import AVOCADO\n     >>> AVOCADO\n     ManimColor('#90B134')\n\nThe following modules contain the predefined color constants:\n\n.. autosummary::\n   :toctree: ../reference\n\n   manim_colors\n   AS2700\n   BS381\n   DVIPSNAMES\n   SVGNAMES\n   XKCD\n   X11\n\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom . import AS2700, BS381, DVIPSNAMES, SVGNAMES, X11, XKCD\nfrom .core import *\nfrom .manim_colors import *\n\n_all_color_dict: dict[str, ManimColor] = {\n    k: v for k, v in globals().items() if isinstance(v, ManimColor)\n}\n"
  },
  {
    "path": "manim/utils/color/core.py",
    "content": "\"\"\"Manim's (internal) color data structure and some utilities for color conversion.\n\nThis module contains the implementation of :class:`.ManimColor`, the data structure\ninternally used to represent colors.\n\nThe preferred way of using these colors is by importing their constants from Manim:\n\n.. code-block:: pycon\n\n    >>> from manim import RED, GREEN, BLUE\n    >>> print(RED)\n    #FC6255\n\nNote that this way uses the name of the colors in UPPERCASE.\n\n.. note::\n\n    The colors with a ``_C`` suffix have an alias equal to the colorname without a\n    letter. For example, ``GREEN = GREEN_C``.\n\n===================\nCustom Color Spaces\n===================\n\nHello, dear visitor. You seem to be interested in implementing a custom color class for\na color space we don't currently support.\n\nThe current system is using a few indirections for ensuring a consistent behavior with\nall other color types in Manim.\n\nTo implement a custom color space, you must subclass :class:`ManimColor` and implement\nthree important methods:\n\n- :attr:`~.ManimColor._internal_value`: a ``@property`` implemented on\n  :class:`ManimColor` with the goal of keeping a consistent internal representation\n  which can be referenced by other functions in :class:`ManimColor`. This property acts\n  as a proxy to whatever representation you need in your class.\n\n  - The getter should always return a NumPy array in the format ``[r,g,b,a]``, in\n    accordance with the type :class:`ManimColorInternal`.\n\n  - The setter should always accept a value in the format ``[r,g,b,a]`` which can be\n    converted to whatever attributes you need.\n\n- :attr:`~ManimColor._internal_space`: a read-only ``@property`` implemented on\n  :class:`ManimColor` with the goal of providing a useful representation which can be\n  used by operators, interpolation and color transform functions.\n\n  The only constraints on this value are:\n\n  - It must be a NumPy array.\n\n  - The last value must be the opacity in a range ``0.0`` to ``1.0``.\n\n  Additionally, your ``__init__`` must support this format as an initialization value\n  without additional parameters to ensure correct functionality of all other methods in\n  :class:`ManimColor`.\n\n- :meth:`~ManimColor._from_internal`: a ``@classmethod`` which converts an\n  ``[r,g,b,a]`` value into suitable parameters for your ``__init__`` method and calls\n  the ``cls`` parameter.\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport colorsys\n\n# logger = _config.logger\nimport random\nimport re\nfrom collections.abc import Iterable, Sequence\nfrom typing import Self, TypeAlias, TypeVar, overload\n\nimport numpy as np\nimport numpy.typing as npt\nfrom typing_extensions import TypeIs, override\n\nfrom manim.typing import (\n    FloatHSL,\n    FloatHSLLike,\n    FloatHSV,\n    FloatHSVA,\n    FloatHSVALike,\n    FloatHSVLike,\n    FloatRGB,\n    FloatRGBA,\n    FloatRGBALike,\n    FloatRGBLike,\n    IntRGB,\n    IntRGBA,\n    IntRGBALike,\n    IntRGBLike,\n    ManimColorDType,\n    ManimColorInternal,\n    ManimFloat,\n    Point3D,\n    Vector3D,\n)\n\nfrom ...utils.space_ops import normalize\n\n# import manim._config as _config\n\nre_hex = re.compile(\"((?<=#)|(?<=0x))[A-F0-9]{3,8}\", re.IGNORECASE)\n\n\nclass ManimColor:\n    \"\"\"Internal representation of a color.\n\n    The :class:`ManimColor` class is the main class for the representation of a color.\n    Its internal representation is an array of 4 floats corresponding to a ``[r,g,b,a]``\n    value where ``r,g,b,a`` can be between 0.0 and 1.0.\n\n    This is done in order to reduce the amount of color inconsistencies by constantly\n    casting between integers and floats which introduces errors.\n\n    The class can accept any value of type :class:`ParsableManimColor` i.e.\n\n    ``ManimColor, int, str, RGB_Tuple_Int, RGB_Tuple_Float, RGBA_Tuple_Int, RGBA_Tuple_Float, RGB_Array_Int,\n    RGB_Array_Float, RGBA_Array_Int, RGBA_Array_Float``\n\n    :class:`ManimColor` itself only accepts singular values and will directly interpret\n    them into a single color if possible. Be careful when passing strings to\n    :class:`ManimColor`: it can create a big overhead for the color processing.\n\n    If you want to parse a list of colors, use the :meth:`parse` method, which assumes\n    that you're going to pass a list of colors so that arrays will not be interpreted as\n    a single color.\n\n    .. warning::\n        If you pass an array of numbers to :meth:`parse`, it will interpret the\n        ``r,g,b,a`` numbers in that array as colors: Instead of the expected\n        singular color, you will get an array with 4 colors.\n\n    For conversion behaviors, see the ``_internal`` functions for further documentation.\n\n    You can create a :class:`ManimColor` instance via its classmethods. See the\n    respective methods for more info.\n\n    .. code-block:: python\n\n        mycolor = ManimColor.from_rgb((0, 1, 0.4, 0.5))\n        myothercolor = ManimColor.from_rgb((153, 255, 255))\n\n    You can also convert between different color spaces:\n\n    .. code-block:: python\n\n        mycolor_hex = mycolor.to_hex()\n        myoriginalcolor = ManimColor.from_hex(mycolor_hex).to_hsv()\n\n    Parameters\n    ----------\n    value\n        Some representation of a color (e.g., a string or\n        a suitable tuple). The default ``None`` is ``BLACK``.\n    alpha\n        The opacity of the color. By default, colors are\n        fully opaque (value 1.0).\n    \"\"\"\n\n    def __init__(\n        self,\n        value: ParsableManimColor | None,\n        alpha: float = 1.0,\n    ) -> None:\n        if value is None:\n            self._internal_value = np.array((0, 0, 0, alpha), dtype=ManimColorDType)\n        elif isinstance(value, ManimColor):\n            # logger.info(\n            #     \"ManimColor was passed another ManimColor. This is probably not what \"\n            #     \"you want. Created a copy of the passed ManimColor instead.\"\n            # )\n            self._internal_value = value._internal_value\n        elif isinstance(value, int):\n            self._internal_value = ManimColor._internal_from_integer(value, alpha)\n        elif isinstance(value, str):\n            result = re_hex.search(value)\n            if result is not None:\n                self._internal_value = ManimColor._internal_from_hex_string(\n                    result.group(), alpha\n                )\n            else:\n                # This is not expected to be called on module initialization time\n                # It can be horribly slow to convert a string to a color because\n                # it has to access the dictionary of colors and find the right color\n                self._internal_value = ManimColor._internal_from_string(value, alpha)\n        elif isinstance(value, (list, tuple, np.ndarray)):\n            length = len(value)\n            if all(isinstance(x, float) for x in value):\n                if length == 3:\n                    self._internal_value = ManimColor._internal_from_rgb(value, alpha)\n                elif length == 4:\n                    self._internal_value = ManimColor._internal_from_rgba(value)\n                else:\n                    raise ValueError(\n                        f\"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}\"\n                    )\n            else:\n                if length == 3:\n                    self._internal_value = ManimColor._internal_from_int_rgb(\n                        value, alpha\n                    )\n                elif length == 4:\n                    self._internal_value = ManimColor._internal_from_int_rgba(value)\n                else:\n                    raise ValueError(\n                        f\"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}\"\n                    )\n        elif hasattr(value, \"get_hex\") and callable(value.get_hex):\n            result = re_hex.search(value.get_hex())\n            if result is None:\n                raise ValueError(f\"Failed to parse a color from {value}\")\n            self._internal_value = ManimColor._internal_from_hex_string(\n                result.group(), alpha\n            )\n        else:\n            # logger.error(f\"Invalid color value: {value}\")\n            raise TypeError(\n                \"ManimColor only accepts int, str, list[int, int, int], \"\n                \"list[int, int, int, int], list[float, float, float], \"\n                f\"list[float, float, float, float], not {type(value)}\"\n            )\n\n    @property\n    def _internal_space(self) -> npt.NDArray[ManimFloat]:\n        \"\"\"This is a readonly property which is a custom representation for color space\n        operations. It is used for operators and can be used when implementing a custom\n        color space.\n        \"\"\"\n        return self._internal_value\n\n    @property\n    def _internal_value(self) -> ManimColorInternal:\n        \"\"\"Return the internal value of the current Manim color ``[r,g,b,a]`` float\n        array.\n\n        Returns\n        -------\n        ManimColorInternal\n            Internal color representation.\n        \"\"\"\n        return self.__value\n\n    @_internal_value.setter\n    def _internal_value(self, value: ManimColorInternal) -> None:\n        \"\"\"Overwrite the internal color value of this :class:`ManimColor`.\n\n        Parameters\n        ----------\n        value\n            The value which will overwrite the current color.\n\n        Raises\n        ------\n        TypeError\n            If an invalid array is passed.\n        \"\"\"\n        if not isinstance(value, np.ndarray):\n            raise TypeError(\"Value must be a NumPy array.\")\n        if value.shape[0] != 4:\n            raise TypeError(\"Array must have exactly 4 values.\")\n        self.__value: ManimColorInternal = value\n\n    @classmethod\n    def _construct_from_space(\n        cls,\n        _space: npt.NDArray[ManimFloat]\n        | tuple[float, float, float]\n        | tuple[float, float, float, float],\n    ) -> Self:\n        \"\"\"This function is used as a proxy for constructing a color with an internal\n        value. This can be used by subclasses to hook into the construction of new\n        objects using the internal value format.\n        \"\"\"\n        return cls(_space)\n\n    @staticmethod\n    def _internal_from_integer(value: int, alpha: float) -> ManimColorInternal:\n        return np.asarray(\n            (\n                ((value >> 16) & 0xFF) / 255,\n                ((value >> 8) & 0xFF) / 255,\n                ((value >> 0) & 0xFF) / 255,\n                alpha,\n            ),\n            dtype=ManimColorDType,\n        )\n\n    @staticmethod\n    def _internal_from_hex_string(hex_: str, alpha: float) -> ManimColorInternal:\n        \"\"\"Internal function for converting a hex string into the internal representation\n        of a :class:`ManimColor`.\n\n        .. warning::\n            This does not accept any prefixes like # or similar in front of the hex string.\n            This is just intended for the raw hex part.\n\n        *For internal use only*\n\n        Parameters\n        ----------\n        hex\n            Hex string to be parsed.\n        alpha\n            Alpha value used for the color, if the color is only 3 bytes long. Otherwise,\n            if the color is 4 bytes long, this parameter will not be used.\n\n        Returns\n        -------\n        ManimColorInternal\n            Internal color representation\n        \"\"\"\n        if len(hex_) in (3, 4):\n            hex_ = \"\".join([x * 2 for x in hex_])\n        if len(hex_) == 6:\n            hex_ += \"FF\"\n        elif len(hex_) == 8:\n            alpha = (int(hex_, 16) & 0xFF) / 255\n        else:\n            raise ValueError(\n                \"Hex colors must be specified with either 0x or # as prefix and contain 6 or 8 hexadecimal numbers\"\n            )\n        tmp = int(hex_, 16)\n        return np.asarray(\n            (\n                ((tmp >> 24) & 0xFF) / 255,\n                ((tmp >> 16) & 0xFF) / 255,\n                ((tmp >> 8) & 0xFF) / 255,\n                alpha,\n            ),\n            dtype=ManimColorDType,\n        )\n\n    @staticmethod\n    def _internal_from_int_rgb(\n        rgb: IntRGBLike, alpha: float = 1.0\n    ) -> ManimColorInternal:\n        \"\"\"Internal function for converting an RGB tuple of integers into the internal\n        representation of a :class:`ManimColor`.\n\n        *For internal use only*\n\n        Parameters\n        ----------\n        rgb\n            Integer RGB tuple to be parsed\n        alpha\n            Optional alpha value. Default is 1.0.\n\n        Returns\n        -------\n        ManimColorInternal\n            Internal color representation.\n        \"\"\"\n        value: np.ndarray = np.asarray(rgb, dtype=ManimColorDType).copy() / 255\n        value.resize(4, refcheck=False)\n        value[3] = alpha\n        return value\n\n    @staticmethod\n    def _internal_from_rgb(rgb: FloatRGBLike, alpha: float = 1.0) -> ManimColorInternal:\n        \"\"\"Internal function for converting a rgb tuple of floats into the internal\n        representation of a :class:`ManimColor`.\n\n        *For internal use only*\n\n        Parameters\n        ----------\n        rgb\n            Float RGB tuple to be parsed.\n        alpha\n            Optional alpha value. Default is 1.0.\n\n        Returns\n        -------\n        ManimColorInternal\n            Internal color representation.\n        \"\"\"\n        value: np.ndarray = np.asarray(rgb, dtype=ManimColorDType).copy()\n        value.resize(4, refcheck=False)\n        value[3] = alpha\n        return value\n\n    @staticmethod\n    def _internal_from_int_rgba(rgba: IntRGBALike) -> ManimColorInternal:\n        \"\"\"Internal function for converting an RGBA tuple of integers into the internal\n        representation of a :class:`ManimColor`.\n\n        *For internal use only*\n\n        Parameters\n        ----------\n        rgba\n            Int RGBA tuple to be parsed.\n\n        Returns\n        -------\n        ManimColorInternal\n            Internal color representation.\n        \"\"\"\n        return np.asarray(rgba, dtype=ManimColorDType) / 255\n\n    @staticmethod\n    def _internal_from_rgba(rgba: FloatRGBALike) -> ManimColorInternal:\n        \"\"\"Internal function for converting an RGBA tuple of floats into the internal\n        representation of a :class:`ManimColor`.\n\n        *For internal use only*\n\n        Parameters\n        ----------\n        rgba\n            Int RGBA tuple to be parsed.\n\n        Returns\n        -------\n        ManimColorInternal\n            Internal color representation.\n        \"\"\"\n        return np.asarray(rgba, dtype=ManimColorDType)\n\n    @staticmethod\n    def _internal_from_string(name: str, alpha: float) -> ManimColorInternal:\n        \"\"\"Internal function for converting a string into the internal representation of\n        a :class:`ManimColor`. This is not used for hex strings: please refer to\n        :meth:`_internal_from_hex` for this functionality.\n\n        *For internal use only*\n\n        Parameters\n        ----------\n        name\n            The color name to be parsed into a color. Refer to the different color\n            modules in the documentation page to find the corresponding color names.\n\n        Returns\n        -------\n        ManimColorInternal\n            Internal color representation.\n\n        Raises\n        ------\n        ValueError\n            If the color name is not present in Manim.\n        \"\"\"\n        from . import _all_color_dict\n\n        if tmp := _all_color_dict.get(name.upper()):\n            tmp._internal_value[3] = alpha\n            return tmp._internal_value.copy()\n        else:\n            raise ValueError(f\"Color {name} not found\")\n\n    def to_integer(self) -> int:\n        \"\"\"Convert the current :class:`ManimColor` into an integer.\n\n        .. warning::\n            This will return only the RGB part of the color.\n\n        Returns\n        -------\n        int\n            Integer representation of the color.\n        \"\"\"\n        tmp = (self._internal_value[:3] * 255).astype(dtype=np.byte).tobytes()\n        return int.from_bytes(tmp, \"big\")\n\n    def to_rgb(self) -> FloatRGB:\n        \"\"\"Convert the current :class:`ManimColor` into an RGB array of floats.\n\n        Returns\n        -------\n        RGB_Array_Float\n            RGB array of 3 floats from 0.0 to 1.0.\n        \"\"\"\n        return self._internal_value[:3]\n\n    def to_int_rgb(self) -> IntRGB:\n        \"\"\"Convert the current :class:`ManimColor` into an RGB array of integers.\n\n        Returns\n        -------\n        RGB_Array_Int\n            RGB array of 3 integers from 0 to 255.\n        \"\"\"\n        return (self._internal_value[:3] * 255).astype(int)\n\n    def to_rgba(self) -> FloatRGBA:\n        \"\"\"Convert the current :class:`ManimColor` into an RGBA array of floats.\n\n        Returns\n        -------\n        RGBA_Array_Float\n            RGBA array of 4 floats from 0.0 to 1.0.\n        \"\"\"\n        return self._internal_value\n\n    def to_int_rgba(self) -> IntRGBA:\n        \"\"\"Convert the current ManimColor into an RGBA array of integers.\n\n\n        Returns\n        -------\n        RGBA_Array_Int\n            RGBA array of 4 integers from 0 to 255.\n        \"\"\"\n        return (self._internal_value * 255).astype(int)\n\n    def to_rgba_with_alpha(self, alpha: float) -> FloatRGBA:\n        \"\"\"Convert the current :class:`ManimColor` into an RGBA array of floats. This is\n        similar to :meth:`to_rgba`, but you can change the alpha value.\n\n        Parameters\n        ----------\n        alpha\n            Alpha value to be used in the return value.\n\n        Returns\n        -------\n        RGBA_Array_Float\n            RGBA array of 4 floats from 0.0 to 1.0.\n        \"\"\"\n        return np.fromiter((*self._internal_value[:3], alpha), dtype=ManimColorDType)\n\n    def to_int_rgba_with_alpha(self, alpha: float) -> IntRGBA:\n        \"\"\"Convert the current :class:`ManimColor` into an RGBA array of integers. This\n        is similar to :meth:`to_int_rgba`, but you can change the alpha value.\n\n        Parameters\n        ----------\n        alpha\n            Alpha value to be used for the return value. Pass a float between 0.0 and\n            1.0: it will automatically be scaled to an integer between 0 and 255.\n\n        Returns\n        -------\n        RGBA_Array_Int\n            RGBA array of 4 integers from 0 to 255.\n        \"\"\"\n        tmp = self._internal_value * 255\n        tmp[3] = alpha * 255\n        return tmp.astype(int)\n\n    def to_hex(self, with_alpha: bool = False) -> str:\n        \"\"\"Convert the :class:`ManimColor` to a hexadecimal representation of the color.\n\n        Parameters\n        ----------\n        with_alpha\n            If ``True``, append 2 extra characters to the hex string which represent the\n            alpha value of the color between 0 and 255. Default is ``False``.\n\n        Returns\n        -------\n        str\n            A hex string starting with a ``#``, with either 6 or 8 nibbles depending on\n            the ``with_alpha`` parameter. By default, it has 6 nibbles, i.e. ``#XXXXXX``.\n        \"\"\"\n        tmp = (\n            f\"#{int(self._internal_value[0] * 255):02X}\"\n            f\"{int(self._internal_value[1] * 255):02X}\"\n            f\"{int(self._internal_value[2] * 255):02X}\"\n        )\n        if with_alpha:\n            tmp += f\"{int(self._internal_value[3] * 255):02X}\"\n        return tmp\n\n    def to_hsv(self) -> FloatHSV:\n        \"\"\"Convert the :class:`ManimColor` to an HSV array.\n\n        .. note::\n           Be careful: this returns an array in the form ``[h, s, v]``, where the\n           elements are floats. This might be confusing, because RGB can also be an array\n           of floats. You might want to annotate the usage of this function in your code\n           by typing your HSV array variables as :class:`HSV_Array_Float` in order to\n           differentiate them from RGB arrays.\n\n        Returns\n        -------\n        HSV_Array_Float\n            An HSV array of 3 floats from 0.0 to 1.0.\n        \"\"\"\n        return np.array(colorsys.rgb_to_hsv(*self.to_rgb()))\n\n    def to_hsl(self) -> FloatHSL:\n        \"\"\"Convert the :class:`ManimColor` to an HSL array.\n\n        .. note::\n           Be careful: this returns an array in the form ``[h, s, l]``, where the\n           elements are floats. This might be confusing, because RGB can also be an array\n           of floats. You might want to annotate the usage of this function in your code\n           by typing your HSL array variables as :class:`HSL_Array_Float` in order to\n           differentiate them from RGB arrays.\n\n        Returns\n        -------\n        HSL_Array_Float\n            An HSL array of 3 floats from 0.0 to 1.0.\n        \"\"\"\n        hls = colorsys.rgb_to_hls(*self.to_rgb())\n        return np.array([hls[0], hls[2], hls[1]])\n\n    def invert(self, with_alpha: bool = False) -> Self:\n        \"\"\"Return a new, linearly inverted version of this :class:`ManimColor` (no\n        inplace changes).\n\n        Parameters\n        ----------\n        with_alpha\n            If ``True``, the alpha value will be inverted too. Default is ``False``.\n\n            .. note::\n                Setting ``with_alpha=True`` can result in unintended behavior where\n                objects are not displayed because their new alpha value is suddenly 0 or\n                very low.\n\n        Returns\n        -------\n        ManimColor\n            The linearly inverted :class:`ManimColor`.\n        \"\"\"\n        if with_alpha:\n            return self._construct_from_space(1.0 - self._internal_space)\n        else:\n            alpha = self._internal_space[3]\n            new = 1.0 - self._internal_space\n            new[-1] = alpha\n            return self._construct_from_space(new)\n\n    def interpolate(self, other: Self, alpha: float) -> Self:\n        \"\"\"Interpolate between the current and the given :class:`ManimColor`, and return\n        the result.\n\n        Parameters\n        ----------\n        other\n            The other :class:`ManimColor` to be used for interpolation.\n        alpha\n            A point on the line in RGBA colorspace connecting the two colors, i.e. the\n            interpolation point. 0.0 corresponds to the current :class:`ManimColor` and\n            1.0 corresponds to the other :class:`ManimColor`.\n\n        Returns\n        -------\n        ManimColor\n            The interpolated :class:`ManimColor`.\n        \"\"\"\n        return self._construct_from_space(\n            self._internal_space * (1 - alpha) + other._internal_space * alpha\n        )\n\n    def darker(self, blend: float = 0.2) -> Self:\n        \"\"\"Return a new color that is darker than the current color, i.e.\n        interpolated with ``BLACK``. The opacity is unchanged.\n\n        Parameters\n        ----------\n        blend\n            The blend ratio for the interpolation, from 0.0 (the current color\n            unchanged) to 1.0 (pure black). Default is 0.2, which results in a\n            slightly darker color.\n\n        Returns\n        -------\n        ManimColor\n            The darker :class:`ManimColor`.\n\n        See Also\n        --------\n        :meth:`lighter`\n        \"\"\"\n        from manim.utils.color.manim_colors import BLACK\n\n        alpha = self._internal_space[3]\n        black = self._from_internal(BLACK._internal_value)\n        return self.interpolate(black, blend).opacity(alpha)\n\n    def lighter(self, blend: float = 0.2) -> Self:\n        \"\"\"Return a new color that is lighter than the current color, i.e.\n        interpolated with ``WHITE``. The opacity is unchanged.\n\n        Parameters\n        ----------\n        blend\n            The blend ratio for the interpolation, from 0.0 (the current color\n            unchanged) to 1.0 (pure white). Default is 0.2, which results in a\n            slightly lighter color.\n\n        Returns\n        -------\n        ManimColor\n            The lighter :class:`ManimColor`.\n\n        See Also\n        --------\n        :meth:`darker`\n        \"\"\"\n        from manim.utils.color.manim_colors import WHITE\n\n        alpha = self._internal_space[3]\n        white = self._from_internal(WHITE._internal_value)\n        return self.interpolate(white, blend).opacity(alpha)\n\n    def contrasting(\n        self,\n        threshold: float = 0.5,\n        light: Self | None = None,\n        dark: Self | None = None,\n    ) -> Self:\n        \"\"\"Return one of two colors, light or dark (by default white or black),\n        that contrasts with the current color (depending on its luminance).\n        This is typically used to set text in a contrasting color that ensures\n        it is readable against a background of the current color.\n\n        Parameters\n        ----------\n        threshold\n            The luminance threshold which dictates whether the current color is\n            considered light or dark (and thus whether to return the dark or\n            light color, respectively). Default is 0.5.\n        light\n            The light color to return if the current color is considered dark.\n            Default is ``None``: in this case, pure ``WHITE`` will be returned.\n        dark\n            The dark color to return if the current color is considered light,\n            Default is ``None``: in this case, pure ``BLACK`` will be returned.\n\n        Returns\n        -------\n        ManimColor\n            The contrasting :class:`ManimColor`.\n        \"\"\"\n        from manim.utils.color.manim_colors import BLACK, WHITE\n\n        luminance, _, _ = colorsys.rgb_to_yiq(*self.to_rgb())\n        if luminance < threshold:\n            if light is not None:\n                return light\n            return self._from_internal(WHITE._internal_value)\n        else:\n            if dark is not None:\n                return dark\n            return self._from_internal(BLACK._internal_value)\n\n    def opacity(self, opacity: float) -> Self:\n        \"\"\"Create a new :class:`ManimColor` with the given opacity and the same color\n        values as before.\n\n        Parameters\n        ----------\n        opacity\n            The new opacity value to be used.\n\n        Returns\n        -------\n        ManimColor\n            The new :class:`ManimColor` with the same color values and the new opacity.\n        \"\"\"\n        tmp = self._internal_space.copy()\n        tmp[-1] = opacity\n        return self._construct_from_space(tmp)\n\n    def into(self, class_type: type[ManimColorT]) -> ManimColorT:\n        \"\"\"Convert the current color into a different colorspace given by ``class_type``,\n        without changing the :attr:`_internal_value`.\n\n        Parameters\n        ----------\n        class_type\n            The class that is used for conversion. It must be a subclass of\n            :class:`ManimColor` which respects the specification HSV, RGBA, ...\n\n        Returns\n        -------\n        ManimColorT\n            A new color object of type ``class_type`` and the same\n            :attr:`_internal_value` as the original color.\n        \"\"\"\n        return class_type._from_internal(self._internal_value)\n\n    @classmethod\n    def _from_internal(cls, value: ManimColorInternal) -> Self:\n        \"\"\"This method is intended to be overwritten by custom color space classes\n        which are subtypes of :class:`ManimColor`.\n\n        The method constructs a new object of the given class by transforming the value\n        in the internal format ``[r,g,b,a]`` into a format which the constructor of the\n        custom class can understand. Look at :class:`.HSV` for an example.\n        \"\"\"\n        return cls(value)\n\n    @classmethod\n    def from_rgb(\n        cls,\n        rgb: FloatRGBLike | IntRGBLike,\n        alpha: float = 1.0,\n    ) -> Self:\n        \"\"\"Create a ManimColor from an RGB array. Automagically decides which type it\n        is: ``int`` or ``float``.\n\n        .. warning::\n            Please make sure that your elements are not floats if you want integers. A\n            ``5.0`` will result in the input being interpreted as if it was an RGB float\n            array with the value ``5.0`` and not the integer ``5``.\n\n\n        Parameters\n        ----------\n        rgb\n            Any iterable of 3 floats or 3 integers.\n        alpha\n            Alpha value to be used in the color. Default is 1.0.\n\n        Returns\n        -------\n        ManimColor\n            The :class:`ManimColor` which corresponds to the given ``rgb``.\n        \"\"\"\n        return cls._from_internal(ManimColor(rgb, alpha)._internal_value)\n\n    @classmethod\n    def from_rgba(cls, rgba: FloatRGBALike | IntRGBALike) -> Self:\n        \"\"\"Create a ManimColor from an RGBA Array. Automagically decides which type it\n        is: ``int`` or ``float``.\n\n        .. warning::\n            Please make sure that your elements are not floats if you want integers. A\n            ``5.0`` will result in the input being interpreted as if it was a float RGB\n            array with the float ``5.0`` and not the integer ``5``.\n\n        Parameters\n        ----------\n        rgba\n            Any iterable of 4 floats or 4 integers.\n\n        Returns\n        -------\n        ManimColor\n            The :class:`ManimColor` corresponding to the given ``rgba``.\n        \"\"\"\n        return cls(rgba)\n\n    @classmethod\n    def from_hex(cls, hex_str: str, alpha: float = 1.0) -> Self:\n        \"\"\"Create a :class:`ManimColor` from a hex string.\n\n        Parameters\n        ----------\n        hex_str\n            The hex string to be converted.  The allowed prefixes for this string are\n            ``#`` and ``0x``. Currently, this method only supports 6 nibbles, i.e. only\n            strings in the format ``#XXXXXX`` or ``0xXXXXXX``.\n        alpha\n            Alpha value to be used for the hex string. Default is 1.0.\n\n        Returns\n        -------\n        ManimColor\n            The :class:`ManimColor` represented by the hex string.\n        \"\"\"\n        return cls._from_internal(ManimColor(hex_str, alpha)._internal_value)\n\n    @classmethod\n    def from_hsv(cls, hsv: FloatHSVLike, alpha: float = 1.0) -> Self:\n        \"\"\"Create a :class:`ManimColor` from an HSV array.\n\n        Parameters\n        ----------\n        hsv\n            Any iterable containing 3 floats from 0.0 to 1.0.\n        alpha\n            The alpha value to be used. Default is 1.0.\n\n        Returns\n        -------\n        ManimColor\n            The :class:`ManimColor` with the corresponding RGB values to the given HSV\n            array.\n        \"\"\"\n        rgb = colorsys.hsv_to_rgb(*hsv)\n        return cls._from_internal(ManimColor(rgb, alpha)._internal_value)\n\n    @classmethod\n    def from_hsl(cls, hsl: FloatHSLLike, alpha: float = 1.0) -> Self:\n        \"\"\"Create a :class:`ManimColor` from an HSL array.\n\n        Parameters\n        ----------\n        hsl\n            Any iterable containing 3 floats from 0.0 to 1.0.\n        alpha\n            The alpha value to be used. Default is 1.0.\n\n        Returns\n        -------\n        ManimColor\n            The :class:`ManimColor` with the corresponding RGB values to the given HSL\n            array.\n        \"\"\"\n        rgb = colorsys.hls_to_rgb(hsl[0], hsl[2], hsl[1])\n        return cls._from_internal(ManimColor(rgb, alpha)._internal_value)\n\n    @overload\n    @classmethod\n    def parse(\n        cls,\n        color: ParsableManimColor | None,\n        alpha: float = ...,\n    ) -> Self: ...\n\n    @overload\n    @classmethod\n    def parse(\n        cls,\n        color: Sequence[ParsableManimColor],\n        alpha: float = ...,\n    ) -> list[Self]: ...\n\n    @classmethod\n    def parse(\n        cls,\n        color: ParsableManimColor | Sequence[ParsableManimColor] | None,\n        alpha: float = 1.0,\n    ) -> Self | list[Self]:\n        \"\"\"Parse one color as a :class:`ManimColor` or a sequence of colors as a list of\n        :class:`ManimColor`'s.\n\n        Parameters\n        ----------\n        color\n            The color or list of colors to parse. Note that this function can not accept\n            tuples: it will assume that you mean ``Sequence[ParsableManimColor]`` and will\n            return a ``list[ManimColor]``.\n        alpha\n            The alpha (opacity) value to use for the passed color(s).\n\n        Returns\n        -------\n        ManimColor | list[ManimColor]\n            Either a list of colors or a singular color, depending on the input.\n        \"\"\"\n\n        def is_sequence(\n            color: ParsableManimColor | Sequence[ParsableManimColor] | None,\n        ) -> TypeIs[Sequence[ParsableManimColor]]:\n            return isinstance(color, (list, tuple))\n\n        if is_sequence(color):\n            return [\n                cls._from_internal(ManimColor(c, alpha)._internal_value) for c in color\n            ]\n        else:\n            return cls._from_internal(ManimColor(color, alpha)._internal_value)\n\n    @staticmethod\n    def gradient(\n        colors: list[ManimColor], length: int\n    ) -> ManimColor | list[ManimColor]:\n        \"\"\"This method is currently not implemented. Refer to :func:`color_gradient` for\n        a working implementation for now.\n        \"\"\"\n        # TODO: implement proper gradient, research good implementation for this or look at 3b1b implementation\n        raise NotImplementedError\n\n    def __repr__(self) -> str:\n        return f\"{self.__class__.__name__}('{self.to_hex()}')\"\n\n    def __str__(self) -> str:\n        return f\"{self.to_hex()}\"\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, ManimColor):\n            raise TypeError(\n                f\"Cannot compare {self.__class__.__name__} with {other.__class__.__name__}\"\n            )\n        are_equal: bool = np.allclose(self._internal_value, other._internal_value)\n        return are_equal\n\n    def __add__(self, other: int | float | Self) -> Self:\n        if isinstance(other, (int, float)):\n            return self._construct_from_space(self._internal_space + other)\n        else:\n            return self._construct_from_space(\n                self._internal_space + other._internal_space\n            )\n\n    def __radd__(self, other: int | float | Self) -> Self:\n        return self + other\n\n    def __sub__(self, other: int | float | Self) -> Self:\n        if isinstance(other, (int, float)):\n            return self._construct_from_space(self._internal_space - other)\n        else:\n            return self._construct_from_space(\n                self._internal_space - other._internal_space\n            )\n\n    def __rsub__(self, other: int | float | Self) -> Self:\n        return self - other\n\n    def __mul__(self, other: int | float | Self) -> Self:\n        if isinstance(other, (int, float)):\n            return self._construct_from_space(self._internal_space * other)\n        else:\n            return self._construct_from_space(\n                self._internal_space * other._internal_space\n            )\n\n    def __rmul__(self, other: int | float | Self) -> Self:\n        return self * other\n\n    def __truediv__(self, other: int | float | Self) -> Self:\n        if isinstance(other, (int, float)):\n            return self._construct_from_space(self._internal_space / other)\n        else:\n            return self._construct_from_space(\n                self._internal_space / other._internal_space\n            )\n\n    def __rtruediv__(self, other: int | float | Self) -> Self:\n        return self / other\n\n    def __floordiv__(self, other: int | float | Self) -> Self:\n        if isinstance(other, (int, float)):\n            return self._construct_from_space(self._internal_space // other)\n        else:\n            return self._construct_from_space(\n                self._internal_space // other._internal_space\n            )\n\n    def __rfloordiv__(self, other: int | float | Self) -> Self:\n        return self // other\n\n    def __mod__(self, other: int | float | Self) -> Self:\n        if isinstance(other, (int, float)):\n            return self._construct_from_space(self._internal_space % other)\n        else:\n            return self._construct_from_space(\n                self._internal_space % other._internal_space\n            )\n\n    def __rmod__(self, other: int | float | Self) -> Self:\n        return self % other\n\n    def __pow__(self, other: int | float | Self) -> Self:\n        if isinstance(other, (int, float)):\n            return self._construct_from_space(self._internal_space**other)\n        else:\n            return self._construct_from_space(\n                self._internal_space**other._internal_space\n            )\n\n    def __rpow__(self, other: int | float | Self) -> Self:\n        return self**other\n\n    def __invert__(self) -> Self:\n        return self.invert()\n\n    def __int__(self) -> int:\n        return self.to_integer()\n\n    def __getitem__(self, index: int) -> float:\n        item: float = self._internal_space[index]\n        return item\n\n    def __and__(self, other: Self) -> Self:\n        return self._construct_from_space(\n            self._internal_from_integer(self.to_integer() & int(other), 1.0)\n        )\n\n    def __or__(self, other: Self) -> Self:\n        return self._construct_from_space(\n            self._internal_from_integer(self.to_integer() | int(other), 1.0)\n        )\n\n    def __xor__(self, other: Self) -> Self:\n        return self._construct_from_space(\n            self._internal_from_integer(self.to_integer() ^ int(other), 1.0)\n        )\n\n    def __hash__(self) -> int:\n        return hash(self.to_hex(with_alpha=True))\n\n\nRGBA = ManimColor\n\"\"\"RGBA Color Space\"\"\"\n\n\nclass HSV(ManimColor):\n    \"\"\"HSV Color Space\"\"\"\n\n    def __init__(\n        self,\n        hsv: FloatHSVLike | FloatHSVALike,\n        alpha: float = 1.0,\n    ) -> None:\n        super().__init__(None)\n        self.__hsv: FloatHSVA\n        if len(hsv) == 3:\n            self.__hsv = np.asarray((*hsv, alpha))\n        elif len(hsv) == 4:\n            self.__hsv = np.asarray(hsv)\n        else:\n            raise ValueError(\"HSV Color must be an array of 3 values\")\n\n    @classmethod\n    @override\n    def _from_internal(cls, value: ManimColorInternal) -> Self:\n        hsv = colorsys.rgb_to_hsv(*value[:3])\n        hsva = [*hsv, value[-1]]\n        return cls(np.array(hsva))\n\n    @property\n    def hue(self) -> float:\n        hue: float = self.__hsv[0]\n        return hue\n\n    @hue.setter\n    def hue(self, hue: float) -> None:\n        self.__hsv[0] = hue\n\n    @property\n    def saturation(self) -> float:\n        saturation: float = self.__hsv[1]\n        return saturation\n\n    @saturation.setter\n    def saturation(self, saturation: float) -> None:\n        self.__hsv[1] = saturation\n\n    @property\n    def value(self) -> float:\n        value: float = self.__hsv[2]\n        return value\n\n    @value.setter\n    def value(self, value: float) -> None:\n        self.__hsv[2] = value\n\n    @property\n    def h(self) -> float:\n        hue: float = self.__hsv[0]\n        return hue\n\n    @h.setter\n    def h(self, hue: float) -> None:\n        self.__hsv[0] = hue\n\n    @property\n    def s(self) -> float:\n        saturation: float = self.__hsv[1]\n        return saturation\n\n    @s.setter\n    def s(self, saturation: float) -> None:\n        self.__hsv[1] = saturation\n\n    @property\n    def v(self) -> float:\n        value: float = self.__hsv[2]\n        return value\n\n    @v.setter\n    def v(self, value: float) -> None:\n        self.__hsv[2] = value\n\n    @property\n    def _internal_space(self) -> npt.NDArray:\n        return self.__hsv\n\n    @property\n    def _internal_value(self) -> ManimColorInternal:\n        \"\"\"Return the internal value of the current :class:`ManimColor` as an\n        ``[r,g,b,a]`` float array.\n\n        Returns\n        -------\n        ManimColorInternal\n            Internal color representation.\n        \"\"\"\n        return np.array(\n            [\n                *colorsys.hsv_to_rgb(self.__hsv[0], self.__hsv[1], self.__hsv[2]),\n                self.__alpha,\n            ],\n            dtype=ManimColorDType,\n        )\n\n    @_internal_value.setter\n    def _internal_value(self, value: ManimColorInternal) -> None:\n        \"\"\"Overwrite the internal color value of this :class:`ManimColor`.\n\n        Parameters\n        ----------\n        value\n            The value which will overwrite the current color.\n\n        Raises\n        ------\n        TypeError\n            If an invalid array is passed.\n        \"\"\"\n        if not isinstance(value, np.ndarray):\n            raise TypeError(\"Value must be a NumPy array.\")\n        if value.shape[0] != 4:\n            raise TypeError(\"Array must have exactly 4 values.\")\n        tmp = colorsys.rgb_to_hsv(value[0], value[1], value[2])\n        self.__hsv = np.array(tmp)\n        self.__alpha = value[3]\n\n\nParsableManimColor: TypeAlias = (\n    ManimColor | int | str | IntRGBLike | FloatRGBLike | IntRGBALike | FloatRGBALike\n)\n\"\"\"`ParsableManimColor` represents all the types which can be parsed\nto a :class:`ManimColor` in Manim.\n\"\"\"\n\n\nManimColorT = TypeVar(\"ManimColorT\", bound=ManimColor)\n\n\ndef color_to_rgb(color: ParsableManimColor) -> FloatRGB:\n    \"\"\"Helper function for use in functional style programming.\n    Refer to :meth:`ManimColor.to_rgb`.\n\n    Parameters\n    ----------\n    color\n        A color to convert to an RGB float array.\n\n    Returns\n    -------\n    RGB_Array_Float\n        The corresponding RGB float array.\n    \"\"\"\n    return ManimColor(color).to_rgb()\n\n\ndef color_to_rgba(color: ParsableManimColor, alpha: float = 1.0) -> FloatRGBA:\n    \"\"\"Helper function for use in functional style programming. Refer to\n    :meth:`ManimColor.to_rgba_with_alpha`.\n\n    Parameters\n    ----------\n    color\n        A color to convert to an RGBA float array.\n    alpha\n        An alpha value between 0.0 and 1.0 to be used as opacity in the color. Default is\n        1.0.\n\n    Returns\n    -------\n    RGBA_Array_Float\n        The corresponding RGBA float array.\n    \"\"\"\n    return ManimColor(color).to_rgba_with_alpha(alpha)\n\n\ndef color_to_int_rgb(color: ParsableManimColor) -> IntRGB:\n    \"\"\"Helper function for use in functional style programming. Refer to\n    :meth:`ManimColor.to_int_rgb`.\n\n    Parameters\n    ----------\n    color\n        A color to convert to an RGB integer array.\n\n    Returns\n    -------\n    RGB_Array_Int\n        The corresponding RGB integer array.\n    \"\"\"\n    return ManimColor(color).to_int_rgb()\n\n\ndef color_to_int_rgba(color: ParsableManimColor, alpha: float = 1.0) -> IntRGBA:\n    \"\"\"Helper function for use in functional style programming. Refer to\n    :meth:`ManimColor.to_int_rgba_with_alpha`.\n\n    Parameters\n    ----------\n    color\n        A color to convert to an RGBA integer array.\n    alpha\n        An alpha value between 0.0 and 1.0 to be used as opacity in the color. Default is\n        1.0.\n\n    Returns\n    -------\n    RGBA_Array_Int\n        The corresponding RGBA integer array.\n    \"\"\"\n    return ManimColor(color).to_int_rgba_with_alpha(alpha)\n\n\ndef rgb_to_color(rgb: FloatRGBLike | IntRGBLike) -> ManimColor:\n    \"\"\"Helper function for use in functional style programming. Refer to\n    :meth:`ManimColor.from_rgb`.\n\n    Parameters\n    ----------\n    rgb\n        A 3 element iterable.\n\n    Returns\n    -------\n    ManimColor\n        A ManimColor with the corresponding value.\n    \"\"\"\n    return ManimColor.from_rgb(rgb)\n\n\ndef rgba_to_color(rgba: FloatRGBALike | IntRGBALike) -> ManimColor:\n    \"\"\"Helper function for use in functional style programming. Refer to\n    :meth:`ManimColor.from_rgba`.\n\n    Parameters\n    ----------\n    rgba\n        A 4 element iterable.\n\n    Returns\n    -------\n    ManimColor\n        A ManimColor with the corresponding value\n    \"\"\"\n    return ManimColor.from_rgba(rgba)\n\n\ndef rgb_to_hex(rgb: FloatRGBLike | IntRGBLike) -> str:\n    \"\"\"Helper function for use in functional style programming. Refer to\n    :meth:`ManimColor.from_rgb` and :meth:`ManimColor.to_hex`.\n\n    Parameters\n    ----------\n    rgb\n        A 3 element iterable.\n\n    Returns\n    -------\n    str\n        A hex representation of the color.\n    \"\"\"\n    return ManimColor.from_rgb(rgb).to_hex()\n\n\ndef hex_to_rgb(hex_code: str) -> FloatRGB:\n    \"\"\"Helper function for use in functional style programming. Refer to\n    :meth:`ManimColor.to_rgb`.\n\n    Parameters\n    ----------\n    hex_code\n        A hex string representing a color.\n\n    Returns\n    -------\n    RGB_Array_Float\n        An RGB array representing the color.\n    \"\"\"\n    return ManimColor(hex_code).to_rgb()\n\n\ndef invert_color(color: ManimColorT) -> ManimColorT:\n    \"\"\"Helper function for use in functional style programming. Refer to\n    :meth:`ManimColor.invert`\n\n    Parameters\n    ----------\n    color\n        The :class:`ManimColor` to invert.\n\n    Returns\n    -------\n    ManimColor\n        The linearly inverted :class:`ManimColor`.\n    \"\"\"\n    return color.invert()\n\n\ndef color_gradient(\n    reference_colors: Iterable[ParsableManimColor],\n    length_of_output: int,\n) -> list[ManimColor]:\n    \"\"\"Create a list of colors interpolated between the input array of colors with a\n    specific number of colors.\n\n    Parameters\n    ----------\n    reference_colors\n        The colors to be interpolated between or spread apart.\n    length_of_output\n        The number of colors that the output should have, ideally more than the input.\n\n    Returns\n    -------\n    list[ManimColor]\n        A list of interpolated :class:`ManimColor`'s.\n    \"\"\"\n    if length_of_output == 0:\n        return []\n    parsed_colors = [ManimColor(color) for color in reference_colors]\n    num_colors = len(parsed_colors)\n    if num_colors == 0:\n        raise ValueError(\"Expected 1 or more reference colors. Got 0 colors.\")\n    if num_colors == 1:\n        return parsed_colors * length_of_output\n\n    rgbs = [color.to_rgb() for color in parsed_colors]\n    alphas = np.linspace(0, (num_colors - 1), length_of_output)\n    floors = alphas.astype(\"int\")\n    alphas_mod1 = alphas % 1\n    # End edge case\n    alphas_mod1[-1] = 1\n    floors[-1] = num_colors - 2\n    return [\n        rgb_to_color((rgbs[i] * (1 - alpha)) + (rgbs[i + 1] * alpha))\n        for i, alpha in zip(floors, alphas_mod1, strict=True)\n    ]\n\n\ndef interpolate_color(\n    color1: ManimColorT, color2: ManimColorT, alpha: float\n) -> ManimColorT:\n    \"\"\"Standalone function to interpolate two ManimColors and get the result. Refer to\n    :meth:`ManimColor.interpolate`.\n\n    Parameters\n    ----------\n    color1\n        The first :class:`ManimColor`.\n    color2\n        The second :class:`ManimColor`.\n    alpha\n        The alpha value determining the point of interpolation between the colors.\n\n    Returns\n    -------\n    ManimColor\n        The interpolated ManimColor.\n    \"\"\"\n    return color1.interpolate(color2, alpha)\n\n\ndef average_color(*colors: ParsableManimColor) -> ManimColor:\n    \"\"\"Determine the average color between the given parameters.\n\n    .. note::\n        This operation does not consider the alphas (opacities) of the colors. The\n        generated color has an alpha or opacity of 1.0.\n\n    Returns\n    -------\n    ManimColor\n        The average color of the input.\n    \"\"\"\n    rgbs = np.array([color_to_rgb(color) for color in colors])\n    mean_rgb = np.apply_along_axis(np.mean, 0, rgbs)\n    return rgb_to_color(mean_rgb)\n\n\ndef random_bright_color() -> ManimColor:\n    \"\"\"Return a random bright color: a random color averaged with ``WHITE``.\n\n    .. warning::\n        This operation is very expensive. Please keep in mind the performance loss.\n\n    Returns\n    -------\n    ManimColor\n        A random bright :class:`ManimColor`.\n    \"\"\"\n    curr_rgb = color_to_rgb(random_color())\n    new_rgb = 0.5 * (curr_rgb + np.ones(3))\n    return ManimColor(new_rgb)\n\n\ndef random_color() -> ManimColor:\n    \"\"\"Return a random :class:`ManimColor`.\n\n    Returns\n    -------\n    ManimColor\n        A random :class:`ManimColor`.\n    \"\"\"\n    return RandomColorGenerator._random_color()\n\n\nclass RandomColorGenerator:\n    \"\"\"A generator for producing random colors from a given list of Manim colors,\n    optionally in a reproducible sequence using a seed value.\n\n    When initialized with a specific seed, this class produces a deterministic\n    sequence of :class:`.ManimColor` instances. If no seed is provided, the selection is\n    non-deterministic using Python’s global random state.\n\n    Parameters\n    ----------\n    seed\n        A seed value to initialize the internal random number generator.\n        If ``None`` (the default), colors are chosen using the global random state.\n\n    sample_colors\n        A custom list of Manim colors to sample from. Defaults to the full Manim\n        color palette.\n\n    Examples\n    --------\n    Without a seed (non-deterministic)::\n\n        >>> from manim import RandomColorGenerator, ManimColor, RED, GREEN, BLUE\n        >>> rnd = RandomColorGenerator()\n        >>> isinstance(rnd.next(), ManimColor)\n        True\n\n    With a seed (deterministic sequence)::\n\n        >>> rnd = RandomColorGenerator(42)\n        >>> rnd.next()\n        ManimColor('#8B4513')\n        >>> rnd.next()\n        ManimColor('#BBBBBB')\n        >>> rnd.next()\n        ManimColor('#BBBBBB')\n\n    Re-initializing with the same seed gives the same sequence::\n\n        >>> rnd2 = RandomColorGenerator(42)\n        >>> rnd2.next()\n        ManimColor('#8B4513')\n        >>> rnd2.next()\n        ManimColor('#BBBBBB')\n        >>> rnd2.next()\n        ManimColor('#BBBBBB')\n\n    Using a custom color list::\n\n        >>> custom_palette = [RED, GREEN, BLUE]\n        >>> rnd_custom = RandomColorGenerator(1, sample_colors=custom_palette)\n        >>> rnd_custom.next() in custom_palette\n        True\n        >>> rnd_custom.next() in custom_palette\n        True\n\n    Without a seed and custom palette (non-deterministic)::\n\n        >>> rnd_nodet = RandomColorGenerator(sample_colors=[RED])\n        >>> rnd_nodet.next()\n        ManimColor('#FC6255')\n    \"\"\"\n\n    _singleton: RandomColorGenerator | None = None\n\n    def __init__(\n        self,\n        seed: int | None = None,\n        sample_colors: list[ManimColor] | None = None,\n    ) -> None:\n        from manim.utils.color.manim_colors import _all_manim_colors\n\n        self.choice = random.choice if seed is None else random.Random(seed).choice\n        self.colors = _all_manim_colors if sample_colors is None else sample_colors\n\n    def next(self) -> ManimColor:\n        \"\"\"Returns the next color from the configured color list.\n\n        Returns\n        -------\n        ManimColor\n            A randomly selected color from the specified color list.\n\n        Examples\n        --------\n        Usage::\n\n            >>> from manim import RandomColorGenerator, RED\n            >>> rnd = RandomColorGenerator(sample_colors=[RED])\n            >>> rnd.next()\n            ManimColor('#FC6255')\n        \"\"\"\n        return self.choice(self.colors)\n\n    @classmethod\n    def _random_color(cls) -> ManimColor:\n        \"\"\"Internal method to generate a random color using the singleton instance of\n        `RandomColorGenerator`.\n        It will be used by proxy method `random_color` publicly available\n        and makes it backwards compatible.\n\n        Returns\n        -------\n        ManimColor:\n            A randomly selected color from the configured color list of\n            the singleton instance.\n        \"\"\"\n        if cls._singleton is None:\n            cls._singleton = cls()\n        return cls._singleton.next()\n\n\ndef get_shaded_rgb(\n    rgb: FloatRGB,\n    point: Point3D,\n    unit_normal_vect: Vector3D,\n    light_source: Point3D,\n) -> FloatRGB:\n    \"\"\"Add light or shadow to the ``rgb`` color of some surface which is located at a\n    given ``point`` in space and facing in the direction of ``unit_normal_vect``,\n    depending on whether the surface is facing a ``light_source`` or away from it.\n\n    Parameters\n    ----------\n    rgb\n        An RGB array of floats.\n    point\n        The location of the colored surface.\n    unit_normal_vect\n        The direction in which the colored surface is facing.\n    light_source\n        The location of a light source which might illuminate the surface.\n\n    Returns\n    -------\n    RGB_Array_Float\n        The color with added light or shadow, depending on the direction of the colored\n        surface.\n    \"\"\"\n    to_sun = normalize(light_source - point)\n    light = 0.5 * np.dot(unit_normal_vect, to_sun) ** 3\n    if light < 0:\n        light *= 0.5\n    shaded_rgb: FloatRGB = rgb + light\n    return shaded_rgb\n\n\n__all__ = [\n    \"ManimColor\",\n    \"ManimColorDType\",\n    \"ParsableManimColor\",\n    \"color_to_rgb\",\n    \"color_to_rgba\",\n    \"color_to_int_rgb\",\n    \"color_to_int_rgba\",\n    \"rgb_to_color\",\n    \"rgba_to_color\",\n    \"rgb_to_hex\",\n    \"hex_to_rgb\",\n    \"invert_color\",\n    \"color_gradient\",\n    \"interpolate_color\",\n    \"average_color\",\n    \"random_bright_color\",\n    \"random_color\",\n    \"RandomColorGenerator\",\n    \"get_shaded_rgb\",\n    \"HSV\",\n    \"RGBA\",\n]\n"
  },
  {
    "path": "manim/utils/color/manim_colors.py",
    "content": "\"\"\"Colors included in the global name space.\n\nThese colors form Manim's default color space.\n\n.. manim:: ColorsOverview\n    :save_last_frame:\n    :hide_source:\n\n    import manim.utils.color.manim_colors as Colors\n\n    class ColorsOverview(Scene):\n        def construct(self):\n            def color_group(color):\n                group = VGroup(\n                    *[\n                        Line(ORIGIN, RIGHT * 1.5, stroke_width=35, color=getattr(Colors, name.upper()))\n                        for name in subnames(color)\n                    ]\n                ).arrange_submobjects(buff=0.4, direction=DOWN)\n\n                name = Text(color).scale(0.6).next_to(group, UP, buff=0.3)\n                if any(decender in color for decender in \"gjpqy\"):\n                    name.shift(DOWN * 0.08)\n                group.add(name)\n                return group\n\n            def subnames(name):\n                return [name + \"_\" + char for char in \"abcde\"]\n\n            color_groups = VGroup(\n                *[\n                    color_group(color)\n                    for color in [\n                        \"blue\",\n                        \"teal\",\n                        \"green\",\n                        \"yellow\",\n                        \"gold\",\n                        \"red\",\n                        \"maroon\",\n                        \"purple\",\n                    ]\n                ]\n            ).arrange_submobjects(buff=0.2, aligned_edge=DOWN)\n\n            for line, char in zip(color_groups[0], \"abcde\"):\n                color_groups.add(Text(char).scale(0.6).next_to(line, LEFT, buff=0.2))\n\n            def named_lines_group(length, color_names, labels, align_to_block):\n                colors = [getattr(Colors, color.upper()) for color in color_names]\n                lines = VGroup(\n                    *[\n                        Line(\n                            ORIGIN,\n                            RIGHT * length,\n                            stroke_width=55,\n                            color=color,\n                        )\n                        for color in colors\n                    ]\n                ).arrange_submobjects(buff=0.6, direction=DOWN)\n\n                for line, name, color in zip(lines, labels, colors):\n                    line.add(Text(name, color=color.contrasting()).scale(0.6).move_to(line))\n                lines.next_to(color_groups, DOWN, buff=0.5).align_to(\n                    color_groups[align_to_block], LEFT\n                )\n                return lines\n\n            other_colors = (\n                \"pink\",\n                \"light_pink\",\n                \"orange\",\n                \"light_brown\",\n                \"dark_brown\",\n                \"gray_brown\",\n            )\n\n            other_lines = named_lines_group(\n                3.2,\n                other_colors,\n                other_colors,\n                0,\n            )\n\n            gray_lines = named_lines_group(\n                6.6,\n                [\"white\"] + subnames(\"gray\") + [\"black\"],\n                [\n                    \"white\",\n                    \"lighter_gray / gray_a\",\n                    \"light_gray / gray_b\",\n                    \"gray / gray_c\",\n                    \"dark_gray / gray_d\",\n                    \"darker_gray / gray_e\",\n                    \"black\",\n                ],\n                2,\n            )\n\n            pure_colors = (\n                \"pure_red\",\n                \"pure_green\",\n                \"pure_blue\",\n                \"pure_cyan\",\n                \"pure_magenta\",\n                \"pure_yellow\",\n            )\n\n            pure_lines = named_lines_group(\n                3.2,\n                pure_colors,\n                pure_colors,\n                6,\n            )\n\n            self.add(color_groups, other_lines, gray_lines, pure_lines)\n\n            VGroup(*self.mobjects).move_to(ORIGIN)\n\n.. automanimcolormodule:: manim.utils.color.manim_colors\n\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom .core import ManimColor\n\nWHITE = ManimColor(\"#FFFFFF\")\nGRAY_A = ManimColor(\"#DDDDDD\")\nGREY_A = ManimColor(\"#DDDDDD\")\nGRAY_B = ManimColor(\"#BBBBBB\")\nGREY_B = ManimColor(\"#BBBBBB\")\nGRAY_C = ManimColor(\"#888888\")\nGREY_C = ManimColor(\"#888888\")\nGRAY_D = ManimColor(\"#444444\")\nGREY_D = ManimColor(\"#444444\")\nGRAY_E = ManimColor(\"#222222\")\nGREY_E = ManimColor(\"#222222\")\nBLACK = ManimColor(\"#000000\")\nLIGHTER_GRAY = ManimColor(\"#DDDDDD\")\nLIGHTER_GREY = ManimColor(\"#DDDDDD\")\nLIGHT_GRAY = ManimColor(\"#BBBBBB\")\nLIGHT_GREY = ManimColor(\"#BBBBBB\")\nGRAY = ManimColor(\"#888888\")\nGREY = ManimColor(\"#888888\")\nDARK_GRAY = ManimColor(\"#444444\")\nDARK_GREY = ManimColor(\"#444444\")\nDARKER_GRAY = ManimColor(\"#222222\")\nDARKER_GREY = ManimColor(\"#222222\")\nPURE_RED = ManimColor(\"#FF0000\")\nPURE_GREEN = ManimColor(\"#00FF00\")\nPURE_BLUE = ManimColor(\"#0000FF\")\nPURE_CYAN = ManimColor(\"#00FFFF\")\nPURE_MAGENTA = ManimColor(\"#FF00FF\")\nPURE_YELLOW = ManimColor(\"#FFFF00\")\nBLUE_A = ManimColor(\"#C7E9F1\")\nBLUE_B = ManimColor(\"#9CDCEB\")\nBLUE_C = ManimColor(\"#58C4DD\")\nBLUE_D = ManimColor(\"#29ABCA\")\nBLUE_E = ManimColor(\"#236B8E\")\nBLUE = ManimColor(\"#58C4DD\")\nDARK_BLUE = ManimColor(\"#236B8E\")\nTEAL_A = ManimColor(\"#ACEAD7\")\nTEAL_B = ManimColor(\"#76DDC0\")\nTEAL_C = ManimColor(\"#5CD0B3\")\nTEAL_D = ManimColor(\"#55C1A7\")\nTEAL_E = ManimColor(\"#49A88F\")\nTEAL = ManimColor(\"#5CD0B3\")\nGREEN_A = ManimColor(\"#C9E2AE\")\nGREEN_B = ManimColor(\"#A6CF8C\")\nGREEN_C = ManimColor(\"#83C167\")\nGREEN_D = ManimColor(\"#77B05D\")\nGREEN_E = ManimColor(\"#699C52\")\nGREEN = ManimColor(\"#83C167\")\nYELLOW_A = ManimColor(\"#FFF1B6\")\nYELLOW_B = ManimColor(\"#FFEA94\")\nYELLOW_C = ManimColor(\"#F7D96F\")\nYELLOW_D = ManimColor(\"#F4D345\")\nYELLOW_E = ManimColor(\"#E8C11C\")\nYELLOW = ManimColor(\"#F7D96F\")\nGOLD_A = ManimColor(\"#F7C797\")\nGOLD_B = ManimColor(\"#F9B775\")\nGOLD_C = ManimColor(\"#F0AC5F\")\nGOLD_D = ManimColor(\"#E1A158\")\nGOLD_E = ManimColor(\"#C78D46\")\nGOLD = ManimColor(\"#F0AC5F\")\nRED_A = ManimColor(\"#F7A1A3\")\nRED_B = ManimColor(\"#FF8080\")\nRED_C = ManimColor(\"#FC6255\")\nRED_D = ManimColor(\"#E65A4C\")\nRED_E = ManimColor(\"#CF5044\")\nRED = ManimColor(\"#FC6255\")\nMAROON_A = ManimColor(\"#ECABC1\")\nMAROON_B = ManimColor(\"#EC92AB\")\nMAROON_C = ManimColor(\"#C55F73\")\nMAROON_D = ManimColor(\"#A24D61\")\nMAROON_E = ManimColor(\"#94424F\")\nMAROON = ManimColor(\"#C55F73\")\nPURPLE_A = ManimColor(\"#CAA3E8\")\nPURPLE_B = ManimColor(\"#B189C6\")\nPURPLE_C = ManimColor(\"#9A72AC\")\nPURPLE_D = ManimColor(\"#715582\")\nPURPLE_E = ManimColor(\"#644172\")\nPURPLE = ManimColor(\"#9A72AC\")\nPINK = ManimColor(\"#D147BD\")\nLIGHT_PINK = ManimColor(\"#DC75CD\")\nORANGE = ManimColor(\"#FF862F\")\nLIGHT_BROWN = ManimColor(\"#CD853F\")\nDARK_BROWN = ManimColor(\"#8B4513\")\nGRAY_BROWN = ManimColor(\"#736357\")\nGREY_BROWN = ManimColor(\"#736357\")\n\n# Colors used for Manim Community's logo and banner\n\nLOGO_WHITE = ManimColor(\"#ECE7E2\")\nLOGO_GREEN = ManimColor(\"#87C2A5\")\nLOGO_BLUE = ManimColor(\"#525893\")\nLOGO_RED = ManimColor(\"#E07A5F\")\nLOGO_BLACK = ManimColor(\"#343434\")\n\n_all_manim_colors: list[ManimColor] = [\n    x for x in globals().values() if isinstance(x, ManimColor)\n]\n"
  },
  {
    "path": "manim/utils/commands.py",
    "content": "from __future__ import annotations\n\nimport os\nfrom collections.abc import Generator\nfrom pathlib import Path\nfrom subprocess import run\nfrom typing import TypedDict\n\nimport av\n\nfrom manim.typing import StrOrBytesPath\n\n__all__ = [\n    \"capture\",\n    \"get_video_metadata\",\n    \"get_dir_layout\",\n]\n\n\ndef capture(\n    command: str | list[str],\n    cwd: StrOrBytesPath | None = None,\n    command_input: str | None = None,\n) -> tuple[str, str, int]:\n    p = run(\n        command,\n        cwd=cwd,\n        input=command_input,\n        capture_output=True,\n        text=True,\n        encoding=\"utf-8\",\n    )\n    out, err = p.stdout, p.stderr\n    return out, err, p.returncode\n\n\nclass VideoMetadata(TypedDict):\n    width: int\n    height: int\n    nb_frames: str\n    duration: str\n    avg_frame_rate: str\n    codec_name: str\n    pix_fmt: str\n\n\ndef get_video_metadata(path_to_video: str | os.PathLike) -> VideoMetadata:\n    with av.open(str(path_to_video)) as container:\n        stream = container.streams.video[0]\n        ctxt = stream.codec_context\n        rate = stream.average_rate\n        if stream.duration is not None:\n            duration = float(stream.duration * stream.time_base)\n            num_frames = stream.frames\n        else:\n            num_frames = sum(1 for _ in container.decode(video=0))\n            duration = float(num_frames / stream.base_rate)\n\n        return {\n            \"width\": ctxt.width,\n            \"height\": ctxt.height,\n            \"nb_frames\": str(num_frames),\n            \"duration\": f\"{duration:.6f}\",\n            \"avg_frame_rate\": f\"{rate.numerator}/{rate.denominator}\",  # Can be a Fraction\n            \"codec_name\": stream.codec_context.name,\n            \"pix_fmt\": stream.codec_context.pix_fmt,\n        }\n\n\ndef get_dir_layout(dirpath: Path) -> Generator[str, None, None]:\n    \"\"\"Get list of paths relative to dirpath of all files in dir and subdirs recursively.\"\"\"\n    for p in dirpath.iterdir():\n        if p.is_dir():\n            yield from get_dir_layout(p)\n            continue\n        yield str(p.relative_to(dirpath))\n"
  },
  {
    "path": "manim/utils/config_ops.py",
    "content": "\"\"\"Utilities that might be useful for configuration dictionaries.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"merge_dicts_recursively\",\n    \"update_dict_recursively\",\n    \"DictAsObject\",\n]\n\n\nimport itertools as it\nfrom typing import Any, Generic, Protocol, cast\n\nimport numpy.typing as npt\nfrom typing_extensions import TypeVar\n\n\ndef merge_dicts_recursively(*dicts: dict[Any, Any]) -> dict[Any, Any]:\n    \"\"\"\n    Creates a dict whose keyset is the union of all the\n    input dictionaries.  The value for each key is based\n    on the first dict in the list with that key.\n\n    dicts later in the list have higher priority\n\n    When values are dictionaries, it is applied recursively\n    \"\"\"\n    result: dict = {}\n    all_items = it.chain(*(d.items() for d in dicts))\n    for key, value in all_items:\n        if key in result and isinstance(result[key], dict) and isinstance(value, dict):\n            result[key] = merge_dicts_recursively(result[key], value)\n        else:\n            result[key] = value\n    return result\n\n\ndef update_dict_recursively(\n    current_dict: dict[Any, Any], *others: dict[Any, Any]\n) -> None:\n    updated_dict = merge_dicts_recursively(current_dict, *others)\n    current_dict.update(updated_dict)\n\n\n# Occasionally convenient in order to write dict.x instead of more laborious\n# (and less in keeping with all other attr accesses) dict[\"x\"]\n\n\nclass DictAsObject:\n    def __init__(self, dictin: dict[str, Any]):\n        self.__dict__ = dictin\n\n\n_Data_T = TypeVar(\"_Data_T\", bound=\"npt.NDArray[Any]\", default=\"npt.NDArray[Any]\")\n\n\nclass _HasData(Protocol):\n    data: dict[str, npt.NDArray[Any]]\n\n\nclass _Data(Generic[_Data_T]):\n    \"\"\"Descriptor that allows _Data variables to be grouped and accessed from self.data[\"attr\"] via self.attr.\n    self.data attributes must be arrays.\n    \"\"\"\n\n    def __set_name__(self, obj: _HasData, name: str) -> None:\n        self.name: str = name\n\n    def __get__(self, obj: _HasData, owner: Any) -> _Data_T:\n        value = cast(_Data_T, obj.data[self.name])\n        return value\n\n    def __set__(self, obj: _HasData, array: _Data_T) -> None:\n        obj.data[self.name] = array\n\n\n_Uniforms_T = TypeVar(\"_Uniforms_T\", bound=\"float | tuple[float, ...]\", default=float)\n\n\nclass _HasUniforms(Protocol):\n    uniforms: dict[str, float | tuple[float, ...]]\n\n\nclass _Uniforms(Generic[_Uniforms_T]):\n    \"\"\"Descriptor that allows _Uniforms variables to be grouped from self.uniforms[\"attr\"] via self.attr.\n    self.uniforms attributes must be floats or tuples of floats.\n    \"\"\"\n\n    def __set_name__(self, obj: _HasUniforms, name: str) -> None:\n        self.name: str = name\n\n    def __get__(self, obj: _HasUniforms, owner: Any) -> _Uniforms_T:\n        val = cast(_Uniforms_T, obj.uniforms[self.name])\n        return val\n\n    def __set__(self, obj: _HasUniforms, num: _Uniforms_T) -> None:\n        obj.uniforms[self.name] = num\n"
  },
  {
    "path": "manim/utils/debug.py",
    "content": "\"\"\"Debugging utilities.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"print_family\", \"index_labels\"]\n\n\nfrom typing import Any\n\nfrom manim.mobject.mobject import Mobject\nfrom manim.mobject.text.numbers import Integer\nfrom manim.utils.color import ManimColor\n\nfrom ..mobject.types.vectorized_mobject import VGroup\nfrom .color import BLACK\n\n\ndef print_family(mobject: Mobject, n_tabs: int = 0) -> None:\n    \"\"\"For debugging purposes\"\"\"\n    print(\"\\t\" * n_tabs, mobject, id(mobject))\n    for submob in mobject.submobjects:\n        print_family(submob, n_tabs + 1)\n\n\ndef index_labels(\n    mobject: Mobject,\n    label_height: float = 0.15,\n    background_stroke_width: float = 5,\n    background_stroke_color: ManimColor = BLACK,\n    **kwargs: Any,\n) -> VGroup:\n    r\"\"\"Returns a :class:`~.VGroup` of :class:`~.Integer` mobjects\n    that shows the index of each submobject.\n\n    Useful for working with parts of complicated mobjects.\n\n    Parameters\n    ----------\n    mobject\n        The mobject that will have its submobjects labelled.\n    label_height\n        The height of the labels, by default 0.15.\n    background_stroke_width\n        The stroke width of the outline of the labels, by default 5.\n    background_stroke_color\n        The stroke color of the outline of labels.\n    kwargs\n        Additional parameters to be passed into the :class`~.Integer`\n        mobjects used to construct the labels.\n\n    Examples\n    --------\n    .. manim:: IndexLabelsExample\n        :save_last_frame:\n\n        class IndexLabelsExample(Scene):\n            def construct(self):\n                text = MathTex(\n                    \"\\\\frac{d}{dx}f(x)g(x)=\",\n                    \"f(x)\\\\frac{d}{dx}g(x)\",\n                    \"+\",\n                    \"g(x)\\\\frac{d}{dx}f(x)\",\n                )\n\n                #index the fist term in the MathTex mob\n                indices = index_labels(text[0])\n\n                text[0][1].set_color(PURPLE_B)\n                text[0][8:12].set_color(DARK_BLUE)\n\n                self.add(text, indices)\n    \"\"\"\n    labels = VGroup()\n    for n, submob in enumerate(mobject):\n        label = Integer(n, **kwargs)\n        label.set_stroke(\n            background_stroke_color, background_stroke_width, background=True\n        )\n        label.height = label_height\n        label.move_to(submob)\n        labels.add(label)\n    return labels\n"
  },
  {
    "path": "manim/utils/deprecation.py",
    "content": "\"\"\"Decorators for deprecating classes, functions and function parameters.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\"deprecated\", \"deprecated_params\"]\n\n\nimport inspect\nimport logging\nimport re\nfrom collections.abc import Callable, Iterable\nfrom typing import Any, TypeVar, overload\n\nfrom decorator import decorate, decorator\n\nlogger = logging.getLogger(\"manim\")\n\n\ndef _get_callable_info(callable_: Callable[..., Any], /) -> tuple[str, str]:\n    \"\"\"Returns type and name of a callable.\n\n    Parameters\n    ----------\n    callable\n        The callable\n\n    Returns\n    -------\n    Tuple[str, str]\n        The type and name of the callable. Type can can be one of \"class\", \"method\" (for\n        functions defined in classes) or \"function\"). For methods, name is Class.method.\n    \"\"\"\n    what = type(callable_).__name__\n    name = callable_.__qualname__\n    if what == \"function\" and \".\" in name:\n        what = \"method\"\n    elif what != \"function\":\n        what = \"class\"\n    return (what, name)\n\n\ndef _deprecation_text_component(\n    since: str | None = None,\n    until: str | None = None,\n    message: str | None = None,\n) -> str:\n    \"\"\"Generates a text component used in deprecation messages.\n\n    Parameters\n    ----------\n    since\n        The version or date since deprecation\n    until\n        The version or date until removal of the deprecated callable\n    message\n        The reason for why the callable has been deprecated\n\n    Returns\n    -------\n    str\n        The deprecation message text component.\n    \"\"\"\n    since = f\"since {since} \" if since else \"\"\n    until = (\n        f\"is expected to be removed after {until}\"\n        if until\n        else \"may be removed in a later version\"\n    )\n    msg = \" \" + message if message else \"\"\n    return f\"deprecated {since}and {until}.{msg}\"\n\n\n# TODO: Use ParamSpec to type decorated functions when Python 3.9 is out of life\nT = TypeVar(\"T\")\n\n\n@overload\ndef deprecated(\n    func: Callable[..., T],\n    since: str | None = None,\n    until: str | None = None,\n    replacement: str | None = None,\n    message: str | None = \"\",\n) -> Callable[..., T]: ...\n\n\n@overload\ndef deprecated(\n    func: None = None,\n    since: str | None = None,\n    until: str | None = None,\n    replacement: str | None = None,\n    message: str | None = \"\",\n) -> Callable[[Callable[..., T]], Callable[..., T]]: ...\n\n\ndef deprecated(\n    func: Callable[..., T] | None = None,\n    since: str | None = None,\n    until: str | None = None,\n    replacement: str | None = None,\n    message: str | None = \"\",\n) -> Callable[..., T] | Callable[[Callable[..., T]], Callable[..., T]]:\n    \"\"\"Decorator to mark a callable as deprecated.\n\n    The decorated callable will cause a warning when used. The docstring of the\n    deprecated callable is adjusted to indicate that this callable is deprecated.\n\n    Parameters\n    ----------\n    func\n        The function to be decorated. Should not be set by the user.\n    since\n        The version or date since deprecation.\n    until\n        The version or date until removal of the deprecated callable.\n    replacement\n        The identifier of the callable replacing the deprecated one.\n    message\n        The reason for why the callable has been deprecated.\n\n    Returns\n    -------\n    Callable\n        The decorated callable.\n\n    Examples\n    --------\n    Basic usage::\n\n        from manim.utils.deprecation import deprecated\n\n\n        @deprecated\n        def foo(**kwargs):\n            pass\n\n\n        @deprecated\n        class Bar:\n            def __init__(self):\n                pass\n\n            @deprecated\n            def baz(self):\n                pass\n\n\n        foo()\n        # WARNING  The function foo has been deprecated and may be removed in a later version.\n\n        a = Bar()\n        # WARNING  The class Bar has been deprecated and may be removed in a later version.\n\n        a.baz()\n        # WARNING  The method Bar.baz has been deprecated and may be removed in a later version.\n\n    You can specify additional information for a more precise warning::\n\n        from manim.utils.deprecation import deprecated\n\n\n        @deprecated(\n            since=\"v0.2\", until=\"v0.4\", replacement=\"bar\", message=\"It is cooler.\"\n        )\n        def foo():\n            pass\n\n\n        foo()\n        # WARNING  The function foo has been deprecated since v0.2 and is expected to be removed after v0.4. Use bar instead. It is cooler.\n\n    You may also use dates instead of versions::\n\n        from manim.utils.deprecation import deprecated\n\n\n        @deprecated(since=\"05/01/2021\", until=\"06/01/2021\")\n        def foo():\n            pass\n\n\n        foo()\n        # WARNING  The function foo has been deprecated since 05/01/2021 and is expected to be removed after 06/01/2021.\n\n    \"\"\"\n    # If used as factory:\n    if func is None:\n        return lambda func: deprecated(func, since, until, replacement, message)\n\n    what, name = _get_callable_info(func)\n\n    def warning_msg(for_docs: bool = False) -> str:\n        \"\"\"Generate the deprecation warning message.\n\n        Parameters\n        ----------\n        for_docs\n            Whether or not to format the message for use in documentation.\n\n        Returns\n        -------\n        str\n            The deprecation message.\n        \"\"\"\n        msg = message\n        if replacement is not None:\n            repl = replacement\n            if for_docs:\n                mapper = {\"class\": \"class\", \"method\": \"meth\", \"function\": \"func\"}\n                repl = f\":{mapper[what]}:`~.{replacement}`\"\n            msg = f\"Use {repl} instead.{' ' + message if message else ''}\"\n        deprecated = _deprecation_text_component(since, until, msg)\n        return f\"The {what} {name} has been {deprecated}\"\n\n    def deprecate_docs(func: Callable) -> None:\n        \"\"\"Adjust docstring to indicate the deprecation.\n\n        Parameters\n        ----------\n        func\n            The callable whose docstring to adjust.\n        \"\"\"\n        warning = warning_msg(True)\n        doc_string = func.__doc__ or \"\"\n        func.__doc__ = f\"{doc_string}\\n\\n.. attention:: Deprecated\\n  {warning}\"\n\n    def deprecate(func: Callable[..., T], *args: Any, **kwargs: Any) -> T:\n        \"\"\"The actual decorator used to extend the callables behavior.\n\n        Logs a warning message.\n\n        Parameters\n        ----------\n        func\n            The callable to decorate.\n        args\n            The arguments passed to the given callable.\n        kwargs\n            The keyword arguments passed to the given callable.\n\n        Returns\n        -------\n        Any\n            The return value of the given callable when being passed the given\n            arguments.\n        \"\"\"\n        logger.warning(warning_msg())\n        return func(*args, **kwargs)\n\n    if type(func).__name__ != \"function\":\n        deprecate_docs(func)\n        # The following line raises this mypy error:\n        # Accessing \"__init__\" on an instance is unsound, since instance.__init__\n        # could be from an incompatible subclass  [misc]</pre>\n        func.__init__ = decorate(func.__init__, deprecate)\n        return func\n\n    func = decorate(func, deprecate)\n    deprecate_docs(func)\n    return func\n\n\ndef deprecated_params(\n    params: str | Iterable[str] | None = None,\n    since: str | None = None,\n    until: str | None = None,\n    message: str = \"\",\n    redirections: None\n    | (Iterable[tuple[str, str] | Callable[..., dict[str, Any]]]) = None,\n) -> Callable[..., T]:\n    \"\"\"Decorator to mark parameters of a callable as deprecated.\n\n    It can also be used to automatically redirect deprecated parameter values to their\n    replacements.\n\n    Parameters\n    ----------\n    params\n        The parameters to be deprecated. Can consist of:\n\n        * An iterable of strings, with each element representing a parameter to deprecate\n        * A single string, with parameter names separated by commas or spaces.\n    since\n        The version or date since deprecation.\n    until\n        The version or date until removal of the deprecated callable.\n    message\n        The reason for why the callable has been deprecated.\n    redirections\n        A list of parameter redirections. Each redirection can be one of the following:\n\n        * A tuple of two strings. The first string defines the name of the deprecated\n          parameter; the second string defines the name of the parameter to redirect to,\n          when attempting to use the first string.\n\n        * A function performing the mapping operation. The parameter names of the\n          function determine which parameters are used as input. The function must\n          return a dictionary which contains the redirected arguments.\n\n        Redirected parameters are also implicitly deprecated.\n\n    Returns\n    -------\n    Callable\n        The decorated callable.\n\n    Raises\n    ------\n    ValueError\n        If no parameters are defined (neither explicitly nor implicitly).\n    ValueError\n        If defined parameters are invalid python identifiers.\n\n    Examples\n    --------\n    Basic usage::\n\n        from manim.utils.deprecation import deprecated_params\n\n\n        @deprecated_params(params=\"a, b, c\")\n        def foo(**kwargs):\n            pass\n\n\n        foo(x=2, y=3, z=4)\n        # No warning\n\n        foo(a=2, b=3, z=4)\n        # WARNING  The parameters a and b of method foo have been deprecated and may be removed in a later version.\n\n    You can also specify additional information for a more precise warning::\n\n        from manim.utils.deprecation import deprecated_params\n\n\n        @deprecated_params(\n            params=\"a, b, c\",\n            since=\"v0.2\",\n            until=\"v0.4\",\n            message=\"The letters x, y, z are cooler.\",\n        )\n        def foo(**kwargs):\n            pass\n\n\n        foo(a=2)\n        # WARNING  The parameter a of method foo has been deprecated since v0.2 and is expected to be removed after v0.4. The letters x, y, z are cooler.\n\n    Basic parameter redirection::\n\n        from manim.utils.deprecation import deprecated_params\n\n\n        @deprecated_params(\n            redirections=[\n                # Two ways to redirect one parameter to another:\n                (\"old_param\", \"new_param\"),\n                lambda old_param2: {\"new_param22\": old_param2},\n            ]\n        )\n        def foo(**kwargs):\n            return kwargs\n\n\n        foo(x=1, old_param=2)\n        # WARNING  The parameter old_param of method foo has been deprecated and may be removed in a later version.\n        # returns {\"x\": 1, \"new_param\": 2}\n\n    Redirecting using a calculated value::\n\n        from manim.utils.deprecation import deprecated_params\n\n\n        @deprecated_params(\n            redirections=[lambda runtime_in_ms: {\"run_time\": runtime_in_ms / 1000}]\n        )\n        def foo(**kwargs):\n            return kwargs\n\n\n        foo(runtime_in_ms=500)\n        # WARNING  The parameter runtime_in_ms of method foo has been deprecated and may be removed in a later version.\n        # returns {\"run_time\": 0.5}\n\n    Redirecting multiple parameter values to one::\n\n        from manim.utils.deprecation import deprecated_params\n\n\n        @deprecated_params(\n            redirections=[lambda buff_x=1, buff_y=1: {\"buff\": (buff_x, buff_y)}]\n        )\n        def foo(**kwargs):\n            return kwargs\n\n\n        foo(buff_x=2)\n        # WARNING  The parameter buff_x of method foo has been deprecated and may be removed in a later version.\n        # returns {\"buff\": (2, 1)}\n\n    Redirect one parameter to multiple::\n\n        from manim.utils.deprecation import deprecated_params\n\n\n        @deprecated_params(\n            redirections=[\n                lambda buff=1: {\"buff_x\": buff[0], \"buff_y\": buff[1]}\n                if isinstance(buff, tuple)\n                else {\"buff_x\": buff, \"buff_y\": buff}\n            ]\n        )\n        def foo(**kwargs):\n            return kwargs\n\n\n        foo(buff=0)\n        # WARNING  The parameter buff of method foo has been deprecated and may be removed in a later version.\n        # returns {\"buff_x\": 0, buff_y: 0}\n\n        foo(buff=(1, 2))\n        # WARNING  The parameter buff of method foo has been deprecated and may be removed in a later version.\n        # returns {\"buff_x\": 1, buff_y: 2}\n\n\n    \"\"\"\n    # Check if decorator is used without parenthesis\n    if callable(params):\n        raise ValueError(\"deprecate_parameters requires arguments to be specified.\")\n\n    if params is None:\n        params = []\n\n    # Construct params list\n    params = re.split(r\"[,\\s]+\", params) if isinstance(params, str) else list(params)\n\n    # Add params which are only implicitly given via redirections\n    if redirections is None:\n        redirections = []\n    for redirector in redirections:\n        if isinstance(redirector, tuple):\n            params.append(redirector[0])\n        else:\n            params.extend(list(inspect.signature(redirector).parameters))\n    # Keep ordering of params so that warning message is consistently the same\n    # This will also help pass unit testing\n    params = list(dict.fromkeys(params))\n\n    # Make sure params only contains valid identifiers\n    identifier = re.compile(r\"^[^\\d\\W]\\w*\\Z\", re.UNICODE)\n    if not all(re.match(identifier, param) for param in params):\n        raise ValueError(\"Given parameter values are invalid.\")\n\n    redirections = list(redirections)\n\n    def warning_msg(func: Callable[..., T], used: list[str]) -> str:\n        \"\"\"Generate the deprecation warning message.\n\n        Parameters\n        ----------\n        func\n            The callable with deprecated parameters.\n        used\n            The list of deprecated parameters used in a call.\n\n        Returns\n        -------\n        str\n            The deprecation message.\n        \"\"\"\n        what, name = _get_callable_info(func)\n        plural = len(used) > 1\n        parameter_s = \"s\" if plural else \"\"\n        used_ = \", \".join(used[:-1]) + \" and \" + used[-1] if plural else used[0]\n        has_have_been = \"have been\" if plural else \"has been\"\n        deprecated = _deprecation_text_component(since, until, message)\n        return f\"The parameter{parameter_s} {used_} of {what} {name} {has_have_been} {deprecated}\"\n\n    def redirect_params(kwargs: dict[str, Any], used: list[str]) -> None:\n        \"\"\"Adjust the keyword arguments as defined by the redirections.\n\n        Parameters\n        ----------\n        kwargs\n            The keyword argument dictionary to be updated.\n        used\n            The list of deprecated parameters used in a call.\n        \"\"\"\n        for redirector in redirections:\n            if isinstance(redirector, tuple):\n                old_param, new_param = redirector\n                if old_param in used:\n                    kwargs[new_param] = kwargs.pop(old_param)\n            else:\n                redirector_params = list(inspect.signature(redirector).parameters)\n                redirector_args = {}\n                for redirector_param in redirector_params:\n                    if redirector_param in used:\n                        redirector_args[redirector_param] = kwargs.pop(redirector_param)\n                if len(redirector_args) > 0:\n                    kwargs.update(redirector(**redirector_args))\n\n    def deprecate_params(func: Callable[..., T], *args: Any, **kwargs: Any) -> T:\n        \"\"\"The actual decorator function used to extend the callables behavior.\n\n        Logs a warning message when a deprecated parameter is used and redirects it if\n        specified.\n\n        Parameters\n        ----------\n        func\n            The callable to decorate.\n        args\n            The arguments passed to the given callable.\n        kwargs\n            The keyword arguments passed to the given callable.\n\n        Returns\n        -------\n        Any\n            The return value of the given callable when being passed the given\n            arguments.\n\n        \"\"\"\n        used = [param for param in params if param in kwargs]\n\n        if len(used) > 0:\n            logger.warning(warning_msg(func, used))\n            redirect_params(kwargs, used)\n        return func(*args, **kwargs)\n\n    return decorator(deprecate_params)  # type: ignore[return-value]\n"
  },
  {
    "path": "manim/utils/docbuild/__init__.py",
    "content": "\"\"\"Utilities for building the Manim documentation.\n\nFor more information about the Manim documentation building, see:\n\n-   :doc:`/contributing/development`, specifically the ``Documentation``\n    bullet point under :ref:`polishing-changes-and-submitting-a-pull-request`\n-   :doc:`/contributing/docs`\n\n.. autosummary::\n   :toctree: ../reference\n\n   autoaliasattr_directive\n   autocolor_directive\n   manim_directive\n   module_parsing\n\n\"\"\"\n"
  },
  {
    "path": "manim/utils/docbuild/autoaliasattr_directive.py",
    "content": "\"\"\"A directive for documenting type aliases and other module-level attributes.\"\"\"\n\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom docutils import nodes\nfrom docutils.parsers.rst import Directive\nfrom docutils.statemachine import StringList\n\nfrom manim.utils.docbuild.module_parsing import parse_module_attributes\n\nif TYPE_CHECKING:\n    from sphinx.application import Sphinx\n\n__all__ = [\"AliasAttrDocumenter\"]\n\n\nALIAS_DOCS_DICT, DATA_DICT, TYPEVAR_DICT = parse_module_attributes()\nALIAS_LIST = [\n    alias_name\n    for module_dict in ALIAS_DOCS_DICT.values()\n    for category_dict in module_dict.values()\n    for alias_name in category_dict\n]\n\n\ndef smart_replace(base: str, alias: str, substitution: str) -> str:\n    \"\"\"Auxiliary function for substituting type aliases into a base\n    string, when there are overlaps between the aliases themselves.\n\n    Parameters\n    ----------\n    base\n        The string in which the type aliases will be located and\n        replaced.\n    alias\n        The substring to be substituted.\n    substitution\n        The string which will replace every occurrence of ``alias``.\n\n    Returns\n    -------\n    str\n        The new string after the alias substitution.\n    \"\"\"\n    occurrences = []\n    len_alias = len(alias)\n    len_base = len(base)\n\n    def condition(char: str) -> bool:\n        return not char.isalnum() and char != \"_\"\n\n    start = 0\n    i = 0\n    while True:\n        i = base.find(alias, start)\n        if i == -1:\n            break\n        if (i == 0 or condition(base[i - 1])) and (\n            i + len_alias == len_base or condition(base[i + len_alias])\n        ):\n            occurrences.append(i)\n        start = i + len_alias\n\n    for o in occurrences[::-1]:\n        base = base[:o] + substitution + base[o + len_alias :]\n\n    return base\n\n\ndef setup(app: Sphinx) -> None:\n    app.add_directive(\"autoaliasattr\", AliasAttrDocumenter)\n\n\nclass AliasAttrDocumenter(Directive):\n    \"\"\"Directive which replaces Sphinx's Autosummary for module-level\n    attributes: instead, it manually crafts a new \"Type Aliases\"\n    section, where all the module-level attributes which are explicitly\n    annotated as :class:`TypeAlias` are considered as such, for their\n    use all around the Manim docs.\n\n    These type aliases are separated from the \"regular\" module-level\n    attributes, which get their traditional \"Module Attributes\"\n    section autogenerated with Sphinx's Autosummary under \"Type\n    Aliases\".\n\n    See ``docs/source/_templates/autosummary/module.rst`` to watch\n    this directive in action.\n\n    See :func:`~.parse_module_attributes` for more information on how\n    the modules are parsed to obtain the :class:`TypeAlias` information\n    and separate it from the other attributes.\n    \"\"\"\n\n    objtype = \"autoaliasattr\"\n    required_arguments = 1\n    has_content = True\n\n    def run(self) -> list[nodes.Element]:\n        module_name = self.arguments[0]\n        # not present in the keys of the DICTs\n        module_name = module_name.removeprefix(\"manim.\")\n        module_alias_dict = ALIAS_DOCS_DICT.get(module_name, None)\n        module_attrs_list = DATA_DICT.get(module_name, None)\n        module_typevars = TYPEVAR_DICT.get(module_name, None)\n\n        content = nodes.container()\n\n        # Add \"Type Aliases\" section\n        if module_alias_dict is not None:\n            module_alias_section = nodes.section(ids=[f\"{module_name}.alias\"])\n            content += module_alias_section\n\n            # Use a rubric (title-like), just like in `module.rst`\n            module_alias_section += nodes.rubric(text=\"Type Aliases\")\n\n            # category_name: str\n            # category_dict: AliasCategoryDict = dict[str, AliasInfo]\n            for category_name, category_dict in module_alias_dict.items():\n                category_section = nodes.section(\n                    ids=[category_name.lower().replace(\" \", \"_\")]\n                )\n                module_alias_section += category_section\n                # category_name can be possibly \"\" for uncategorized aliases\n                if category_name:\n                    category_section += nodes.title(text=category_name)\n\n                category_alias_container = nodes.container()\n                category_section += category_alias_container\n\n                # alias_name: str\n                # alias_info: AliasInfo = dict[str, str]\n                #   Contains \"definition\": str\n                #   Can possibly contain \"doc\": str\n                for alias_name, alias_info in category_dict.items():\n                    # Replace all occurrences of type aliases in the\n                    # definition for automatic cross-referencing!\n                    alias_def = alias_info[\"definition\"]\n                    for A in ALIAS_LIST:\n                        alias_def = smart_replace(alias_def, A, f\":class:`~.{A}`\")\n\n                    # Using the `.. class::` directive is CRUCIAL, since\n                    # function/method parameters are always annotated via\n                    # classes - therefore Sphinx expects a class\n                    unparsed = StringList(\n                        [\n                            f\".. class:: {alias_name}\",\n                            \"\",\n                            \"    .. parsed-literal::\",\n                            \"\",\n                            f\"        {alias_def}\",\n                            \"\",\n                        ]\n                    )\n\n                    if \"doc\" in alias_info:\n                        # Replace all occurrences of type aliases in\n                        # the docs for automatic cross-referencing!\n                        alias_doc = alias_info[\"doc\"]\n                        for A in ALIAS_LIST:\n                            alias_doc = alias_doc.replace(f\"`{A}`\", f\":class:`~.{A}`\")\n\n                        # also hyperlink the TypeVars from that module\n                        if module_typevars is not None:\n                            for T in module_typevars:\n                                alias_doc = alias_doc.replace(f\"`{T}`\", f\":class:`{T}`\")\n\n                        # Add all the lines with 4 spaces behind, to consider all the\n                        # documentation as a paragraph INSIDE the `.. class::` block\n                        doc_lines = alias_doc.split(\"\\n\")\n                        unparsed.extend(\n                            StringList([f\"    {line}\" for line in doc_lines])\n                        )\n\n                    # Parse the reST text into a fresh container\n                    # https://www.sphinx-doc.org/en/master/extdev/markupapi.html#parsing-directive-content-as-rest\n                    alias_container = nodes.container()\n                    self.state.nested_parse(unparsed, 0, alias_container)\n                    category_alias_container += alias_container\n\n        # then add the module TypeVars section\n        if module_typevars is not None:\n            module_typevars_section = nodes.section(ids=[f\"{module_name}.typevars\"])\n            content += module_typevars_section\n\n            # Use a rubric (title-like), just like in `module.rst`\n            module_typevars_section += nodes.rubric(text=\"TypeVar's\")\n\n            # name: str\n            # definition: TypeVarDict = dict[str, str]\n            for name, definition in module_typevars.items():\n                # Using the `.. class::` directive is CRUCIAL, since\n                # function/method parameters are always annotated via\n                # classes - therefore Sphinx expects a class\n                unparsed = StringList(\n                    [\n                        f\".. class:: {name}\",\n                        \"\",\n                        \"    .. parsed-literal::\",\n                        \"\",\n                        f\"        {definition}\",\n                        \"\",\n                    ]\n                )\n\n                # Parse the reST text into a fresh container\n                # https://www.sphinx-doc.org/en/master/extdev/markupapi.html#parsing-directive-content-as-rest\n                typevar_container = nodes.container()\n                self.state.nested_parse(unparsed, 0, typevar_container)\n                module_typevars_section += typevar_container\n\n        # Then, add the traditional \"Module Attributes\" section\n        if module_attrs_list is not None:\n            module_attrs_section = nodes.section(ids=[f\"{module_name}.data\"])\n            content += module_attrs_section\n\n            # Use the same rubric (title-like) as in `module.rst`\n            module_attrs_section += nodes.rubric(text=\"Module Attributes\")\n            # Let Sphinx Autosummary do its thing as always\n            # Add all the attribute names with 4 spaces behind, so that\n            # they're considered as INSIDE the `.. autosummary::` block\n            unparsed = StringList(\n                [\n                    \".. autosummary::\",\n                    *(f\"    {attr}\" for attr in module_attrs_list),\n                ]\n            )\n\n            # Parse the reST text into a fresh container\n            # https://www.sphinx-doc.org/en/master/extdev/markupapi.html#parsing-directive-content-as-rest\n            data_container = nodes.container()\n            self.state.nested_parse(unparsed, 0, data_container)\n            module_attrs_section += data_container\n\n        return [content]\n"
  },
  {
    "path": "manim/utils/docbuild/autocolor_directive.py",
    "content": "\"\"\"A directive for documenting colors in Manim.\"\"\"\n\nfrom __future__ import annotations\n\nimport inspect\nfrom typing import TYPE_CHECKING\n\nfrom docutils import nodes\nfrom docutils.parsers.rst import Directive\n\nfrom manim import ManimColor\n\nif TYPE_CHECKING:\n    from sphinx.application import Sphinx\n\n__all__ = [\"ManimColorModuleDocumenter\"]\n\n\ndef setup(app: Sphinx) -> None:\n    app.add_directive(\"automanimcolormodule\", ManimColorModuleDocumenter)\n\n\nclass ManimColorModuleDocumenter(Directive):\n    objtype = \"automanimcolormodule\"\n    required_arguments = 1\n    has_content = True\n\n    def add_directive_header(self, sig: str) -> None:\n        # TODO: The Directive class has no method named\n        # add_directive_header.\n        super().add_directive_header(sig)  # type: ignore[misc]\n\n    def run(self) -> list[nodes.Element]:\n        module_name = self.arguments[0]\n        try:\n            import importlib\n\n            module = importlib.import_module(module_name)\n        except ImportError:\n            return [\n                nodes.error(\n                    None,  # type: ignore[arg-type]\n                    nodes.paragraph(text=f\"Failed to import module '{module_name}'\"),\n                )\n            ]\n\n        # Number of Colors displayed in one row\n        num_color_cols = 2\n        table = nodes.table(align=\"center\")\n\n        tgroup = nodes.tgroup(cols=num_color_cols * 2)\n        table += tgroup\n        for _ in range(num_color_cols * 2):\n            tgroup += nodes.colspec(colwidth=1)\n\n        # Create header rows for the table\n        thead = nodes.thead()\n        header_row = nodes.row()\n        for _ in range(num_color_cols):\n            header_col1 = nodes.paragraph(text=\"Color Name\")\n            header_col2 = nodes.paragraph(text=\"RGB Hex Code\")\n            header_row += nodes.entry(\"\", header_col1)\n            header_row += nodes.entry(\"\", header_col2)\n        thead += header_row\n        tgroup += thead\n\n        color_elements = []\n        for member_name, member_obj in inspect.getmembers(module):\n            if isinstance(member_obj, ManimColor):\n                r, g, b = member_obj.to_rgb()\n                luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b\n\n                # Choose the font color based on the background luminance\n                font_color = \"black\" if luminance > 0.5 else \"white\"\n\n                color_elements.append((member_name, member_obj.to_hex(), font_color))\n\n        tbody = nodes.tbody()\n\n        for base_i in range(0, len(color_elements), num_color_cols):\n            row = nodes.row()\n            for idx in range(base_i, base_i + num_color_cols):\n                if idx < len(color_elements):\n                    member_name, hex_code, font_color = color_elements[idx]\n                    col1 = nodes.literal(text=member_name)\n                    col2 = nodes.raw(\n                        \"\",\n                        f'<div style=\"background-color:{hex_code};padding: 0.25rem 0;border-radius:8px;margin: 0.5rem 0.2rem\"><code style=\"color:{font_color};\">{hex_code}</code></div>',\n                        format=\"html\",\n                    )\n                else:\n                    col1 = nodes.literal(text=\"\")\n                    col2 = nodes.raw(\"\", \"\", format=\"html\")\n                row += nodes.entry(\"\", col1)\n                row += nodes.entry(\"\", col2)\n            tbody += row\n        tgroup += tbody\n\n        return [table]\n"
  },
  {
    "path": "manim/utils/docbuild/manim_directive.py",
    "content": "r\"\"\"\nA directive for including Manim videos in a Sphinx document\n===========================================================\n\nWhen rendering the HTML documentation, the ``.. manim::`` directive\nimplemented here allows to include rendered videos.\n\nIts basic usage that allows processing **inline content**\nlooks as follows::\n\n    .. manim:: MyScene\n\n        class MyScene(Scene):\n            def construct(self):\n                ...\n\nIt is required to pass the name of the class representing the\nscene to be rendered to the directive.\n\nAs a second application, the directive can also be used to\nrender scenes that are defined within doctests, for example::\n\n    .. manim:: DirectiveDoctestExample\n        :ref_classes: Dot\n\n        >>> from manim import Create, Dot, RED, Scene\n        >>> dot = Dot(color=RED)\n        >>> dot.color\n        ManimColor('#FC6255')\n        >>> class DirectiveDoctestExample(Scene):\n        ...     def construct(self):\n        ...         self.play(Create(dot))\n\n\nOptions\n-------\n\nOptions can be passed as follows::\n\n    .. manim:: <Class name>\n        :<option name>: <value>\n\nThe following configuration options are supported by the\ndirective:\n\n    hide_source\n        If this flag is present without argument,\n        the source code is not displayed above the rendered video.\n\n    no_autoplay\n        If this flag is present without argument,\n        the video will not autoplay.\n\n    quality : {'low', 'medium', 'high', 'fourk'}\n        Controls render quality of the video, in analogy to\n        the corresponding command line flags.\n\n    save_as_gif\n        If this flag is present without argument,\n        the scene is rendered as a gif.\n\n    save_last_frame\n        If this flag is present without argument,\n        an image representing the last frame of the scene will\n        be rendered and displayed, instead of a video.\n\n    ref_classes\n        A list of classes, separated by spaces, that is\n        rendered in a reference block after the source code.\n\n    ref_functions\n        A list of functions, separated by spaces,\n        that is rendered in a reference block after the source code.\n\n    ref_methods\n        A list of methods, separated by spaces,\n        that is rendered in a reference block after the source code.\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport csv\nimport itertools as it\nimport re\nimport shutil\nimport sys\nimport textwrap\nfrom pathlib import Path\nfrom timeit import timeit\nfrom typing import TYPE_CHECKING, Any, TypedDict\n\nimport jinja2\nfrom docutils import nodes\nfrom docutils.parsers.rst import Directive, directives\nfrom docutils.statemachine import StringList\n\nfrom manim import QUALITIES\nfrom manim import __version__ as manim_version\n\nif TYPE_CHECKING:\n    from sphinx.application import Sphinx\n\n\n__all__ = [\"ManimDirective\"]\n\n\nclassnamedict: dict[str, int] = {}\n\n\nclass SetupMetadata(TypedDict):\n    parallel_read_safe: bool\n    parallel_write_safe: bool\n\n\nclass SkipManimNode(nodes.Admonition, nodes.Element):\n    \"\"\"Auxiliary node class that is used when the ``skip-manim`` tag is present\n    or ``.pot`` files are being built.\n\n    Skips rendering the manim directive and outputs a placeholder instead.\n    \"\"\"\n\n    pass\n\n\ndef visit(self: SkipManimNode, node: nodes.Element, name: str = \"\") -> None:\n    # TODO: Parent classes don't have a visit_admonition() method.\n    self.visit_admonition(node, name)  # type: ignore[attr-defined]\n    if not isinstance(node[0], nodes.title):\n        node.insert(0, nodes.title(\"skip-manim\", \"Example Placeholder\"))\n\n\ndef depart(self: SkipManimNode, node: nodes.Element) -> None:\n    # TODO: Parent classes don't have a depart_admonition() method.\n    self.depart_admonition(node)  # type: ignore[attr-defined]\n\n\ndef process_name_list(option_input: str, reference_type: str) -> list[str]:\n    r\"\"\"Reformats a string of space separated class names\n    as a list of strings containing valid Sphinx references.\n\n    Tests\n    -----\n\n    ::\n\n        >>> process_name_list(\"Tex TexTemplate\", \"class\")\n        [':class:`~.Tex`', ':class:`~.TexTemplate`']\n        >>> process_name_list(\"Scene.play Mobject.rotate\", \"func\")\n        [':func:`~.Scene.play`', ':func:`~.Mobject.rotate`']\n    \"\"\"\n    return [f\":{reference_type}:`~.{name}`\" for name in option_input.split()]\n\n\nclass ManimDirective(Directive):\n    r\"\"\"The manim directive, rendering videos while building\n    the documentation.\n\n    See the module docstring for documentation.\n    \"\"\"\n\n    has_content = True\n    required_arguments = 1\n    optional_arguments = 0\n    option_spec = {\n        \"hide_source\": bool,\n        \"no_autoplay\": bool,\n        \"quality\": lambda arg: directives.choice(\n            arg,\n            (\"low\", \"medium\", \"high\", \"fourk\"),\n        ),\n        \"save_as_gif\": bool,\n        \"save_last_frame\": bool,\n        \"ref_modules\": lambda arg: process_name_list(arg, \"mod\"),\n        \"ref_classes\": lambda arg: process_name_list(arg, \"class\"),\n        \"ref_functions\": lambda arg: process_name_list(arg, \"func\"),\n        \"ref_methods\": lambda arg: process_name_list(arg, \"meth\"),\n    }\n    final_argument_whitespace = True\n\n    def run(self) -> list[nodes.Element]:\n        # Rendering is skipped if the tag skip-manim is present,\n        # or if we are making the pot-files\n        should_skip = (\n            \"skip-manim\" in self.state.document.settings.env.app.builder.tags\n            or self.state.document.settings.env.app.builder.name == \"gettext\"\n        )\n        if should_skip:\n            clsname = self.arguments[0]\n            node = SkipManimNode()\n            self.state.nested_parse(\n                StringList(\n                    [\n                        f\"Placeholder block for ``{clsname}``.\",\n                        \"\",\n                        \".. code-block:: python\",\n                        \"\",\n                    ]\n                    + [\"    \" + line for line in self.content]\n                    + [\n                        \"\",\n                        \".. raw:: html\",\n                        \"\",\n                        f'    <pre data-manim-binder data-manim-classname=\"{clsname}\">',\n                    ]\n                    + [\"    \" + line for line in self.content]\n                    + [\"    </pre>\"],\n                ),\n                self.content_offset,\n                node,\n            )\n            return [node]\n\n        from manim import config, tempconfig\n\n        global classnamedict\n\n        clsname = self.arguments[0]\n        if clsname not in classnamedict:\n            classnamedict[clsname] = 1\n        else:\n            classnamedict[clsname] += 1\n\n        hide_source = \"hide_source\" in self.options\n        no_autoplay = \"no_autoplay\" in self.options\n        save_as_gif = \"save_as_gif\" in self.options\n        save_last_frame = \"save_last_frame\" in self.options\n        assert not (save_as_gif and save_last_frame)\n\n        ref_content = (\n            self.options.get(\"ref_modules\", [])\n            + self.options.get(\"ref_classes\", [])\n            + self.options.get(\"ref_functions\", [])\n            + self.options.get(\"ref_methods\", [])\n        )\n        ref_block = \"References: \" + \" \".join(ref_content) if ref_content else \"\"\n\n        if \"quality\" in self.options:\n            quality = f\"{self.options['quality']}_quality\"\n        else:\n            quality = \"example_quality\"\n        frame_rate = QUALITIES[quality][\"frame_rate\"]\n        pixel_height = QUALITIES[quality][\"pixel_height\"]\n        pixel_width = QUALITIES[quality][\"pixel_width\"]\n\n        state_machine = self.state_machine\n        document = state_machine.document\n\n        source_file_name = Path(document.attributes[\"source\"])\n        source_rel_name = source_file_name.relative_to(setup.confdir)  # type: ignore[attr-defined]\n        source_rel_dir = source_rel_name.parents[0]\n        dest_dir = Path(setup.app.builder.outdir, source_rel_dir).absolute()  # type: ignore[attr-defined]\n        if not dest_dir.exists():\n            dest_dir.mkdir(parents=True, exist_ok=True)\n\n        source_block_in = [\n            \".. code-block:: python\",\n            \"\",\n            \"    from manim import *\\n\",\n            *(\"    \" + line for line in self.content),\n            \"\",\n            \".. raw:: html\",\n            \"\",\n            f'    <pre data-manim-binder data-manim-classname=\"{clsname}\">',\n            *(\"    \" + line for line in self.content),\n            \"\",\n            \"    </pre>\",\n        ]\n        source_block = \"\\n\".join(source_block_in)\n\n        config.media_dir = (Path(setup.confdir) / \"media\").absolute()  # type: ignore[attr-defined]\n        config.images_dir = \"{media_dir}/images\"\n        config.video_dir = \"{media_dir}/videos/{quality}\"\n        output_file = f\"{clsname}-{classnamedict[clsname]}\"\n        config.assets_dir = Path(\"_static\")\n        config.progress_bar = \"none\"\n        config.verbosity = \"WARNING\"\n\n        example_config = {\n            \"frame_rate\": frame_rate,\n            \"no_autoplay\": no_autoplay,\n            \"pixel_height\": pixel_height,\n            \"pixel_width\": pixel_width,\n            \"save_last_frame\": save_last_frame,\n            \"write_to_movie\": not save_last_frame,\n            \"output_file\": output_file,\n        }\n        if save_last_frame:\n            example_config[\"format\"] = None\n        if save_as_gif:\n            example_config[\"format\"] = \"gif\"\n\n        user_code = list(self.content)\n        if user_code[0].startswith(\">>> \"):  # check whether block comes from doctest\n            user_code = [\n                line[4:] for line in user_code if line.startswith((\">>> \", \"... \"))\n            ]\n\n        code = [\n            \"from manim import *\",\n            *user_code,\n            f\"{clsname}().render()\",\n        ]\n\n        try:\n            with tempconfig(example_config):\n                run_time = timeit(lambda: exec(\"\\n\".join(code), globals()), number=1)\n                video_dir = config.get_dir(\"video_dir\")\n                images_dir = config.get_dir(\"images_dir\")\n        except Exception as e:\n            raise RuntimeError(f\"Error while rendering example {clsname}\") from e\n\n        _write_rendering_stats(\n            clsname,\n            run_time,\n            self.state.document.settings.env.docname,\n        )\n\n        # copy video file to output directory\n        if not (save_as_gif or save_last_frame):\n            filename = f\"{output_file}.mp4\"\n            filesrc = video_dir / filename\n            destfile = Path(dest_dir, filename)\n            shutil.copyfile(filesrc, destfile)\n        elif save_as_gif:\n            filename = f\"{output_file}.gif\"\n            filesrc = video_dir / filename\n        elif save_last_frame:\n            filename = f\"{output_file}.png\"\n            filesrc = images_dir / filename\n        else:\n            raise ValueError(\"Invalid combination of render flags received.\")\n        rendered_template = jinja2.Template(TEMPLATE).render(\n            clsname=clsname,\n            clsname_lowercase=clsname.lower(),\n            hide_source=hide_source,\n            filesrc_rel=Path(filesrc).relative_to(setup.confdir).as_posix(),  # type: ignore[attr-defined]\n            no_autoplay=no_autoplay,\n            output_file=output_file,\n            save_last_frame=save_last_frame,\n            save_as_gif=save_as_gif,\n            source_block=source_block,\n            ref_block=ref_block,\n        )\n        state_machine.insert_input(\n            rendered_template.split(\"\\n\"),\n            source=document.attributes[\"source\"],\n        )\n\n        return []\n\n\nrendering_times_file_path = Path(\"../rendering_times.csv\")\n\n\ndef _write_rendering_stats(scene_name: str, run_time: float, file_name: str) -> None:\n    with rendering_times_file_path.open(\"a\") as file:\n        csv.writer(file).writerow(\n            [\n                re.sub(r\"^(reference\\/)|(manim\\.)\", \"\", file_name),\n                scene_name,\n                f\"{run_time:.3f}\",\n            ],\n        )\n\n\ndef _log_rendering_times(*args: tuple[Any]) -> None:\n    if rendering_times_file_path.exists():\n        with rendering_times_file_path.open() as file:\n            data = list(csv.reader(file))\n        if len(data) == 0:\n            sys.exit()\n\n        print(\"\\nRendering Summary\\n-----------------\\n\")\n\n        # filter out empty lists caused by csv reader\n        data = [row for row in data if row]\n\n        max_file_length = max(len(row[0]) for row in data)\n        for key, group_iter in it.groupby(data, key=lambda row: row[0]):\n            key = key.ljust(max_file_length + 1, \".\")\n            group = list(group_iter)\n            if len(group) == 1:\n                row = group[0]\n                print(f\"{key}{row[2].rjust(7, '.')}s {row[1]}\")\n                continue\n            time_sum = sum(float(row[2]) for row in group)\n            print(\n                f\"{key}{f'{time_sum:.3f}'.rjust(7, '.')}s  => {len(group)} EXAMPLES\",\n            )\n            for row in group:\n                print(f\"{' ' * max_file_length} {row[2].rjust(7)}s {row[1]}\")\n        print(\"\")\n\n\ndef _delete_rendering_times(*args: tuple[Any]) -> None:\n    if rendering_times_file_path.exists():\n        rendering_times_file_path.unlink()\n\n\ndef setup(app: Sphinx) -> SetupMetadata:\n    app.add_node(\n        SkipManimNode,\n        html=(visit, depart),\n        latex=(lambda a, b: None, lambda a, b: None),\n    )\n\n    setup.app = app  # type: ignore[attr-defined]\n    setup.config = app.config  # type: ignore[attr-defined]\n    setup.confdir = app.confdir  # type: ignore[attr-defined]\n\n    app.add_directive(\"manim\", ManimDirective)\n\n    app.connect(\"builder-inited\", _delete_rendering_times)\n    app.connect(\"build-finished\", _log_rendering_times)\n\n    app.add_js_file(\"manim-binder.min.js\")\n    app.add_js_file(\n        None,\n        body=textwrap.dedent(\n            f\"\"\"\\\n                window.initManimBinder({{branch: \"v{manim_version}\"}})\n            \"\"\"\n        ).strip(),\n    )\n\n    metadata: SetupMetadata = {\n        \"parallel_read_safe\": False,\n        \"parallel_write_safe\": True,\n    }\n    return metadata\n\n\nTEMPLATE = r\"\"\"\n{% if not hide_source %}\n.. raw:: html\n\n    <div id=\"{{ clsname_lowercase }}\" class=\"admonition admonition-manim-example\">\n    <p class=\"admonition-title\">Example: {{ clsname }} <a class=\"headerlink\" href=\"#{{ clsname_lowercase }}\">¶</a></p>\n\n{% endif %}\n\n{% if not (save_as_gif or save_last_frame) %}\n.. raw:: html\n\n    <video\n        class=\"manim-video\"\n        controls\n        loop\n        {{ '' if no_autoplay else 'autoplay' }}\n        src=\"./{{ output_file }}.mp4\">\n    </video>\n\n{% elif save_as_gif %}\n.. image:: /{{ filesrc_rel }}\n    :align: center\n\n{% elif save_last_frame %}\n.. image:: /{{ filesrc_rel }}\n    :align: center\n\n{% endif %}\n{% if not hide_source %}\n{{ source_block }}\n\n{{ ref_block }}\n\n.. raw:: html\n\n    </div>\n\n{% endif %}\n\"\"\"\n"
  },
  {
    "path": "manim/utils/docbuild/module_parsing.py",
    "content": "\"\"\"Read and parse all the Manim modules and extract documentation from them.\"\"\"\n\nfrom __future__ import annotations\n\nimport ast\nimport sys\nfrom ast import Attribute, Name, Subscript\nfrom pathlib import Path\nfrom typing import Any, TypeAlias\n\n__all__ = [\"parse_module_attributes\"]\n\n\nAliasInfo: TypeAlias = dict[str, str]\n\"\"\"Dictionary with a `definition` key containing the definition of\na :class:`TypeAlias` as a string, and optionally a `doc` key containing\nthe documentation for that alias, if it exists.\n\"\"\"\n\nAliasCategoryDict: TypeAlias = dict[str, AliasInfo]\n\"\"\"Dictionary which holds an `AliasInfo` for every alias name in a same\ncategory.\n\"\"\"\n\nModuleLevelAliasDict: TypeAlias = dict[str, AliasCategoryDict]\n\"\"\"Dictionary containing every :class:`TypeAlias` defined in a module,\nclassified by category in different `AliasCategoryDict` objects.\n\"\"\"\n\nModuleTypeVarDict: TypeAlias = dict[str, str]\n\"\"\"Dictionary containing every :class:`TypeVar` defined in a module.\"\"\"\n\n\nAliasDocsDict: TypeAlias = dict[str, ModuleLevelAliasDict]\n\"\"\"Dictionary which, for every module in Manim, contains documentation\nabout their module-level attributes which are explicitly defined as\n:class:`TypeAlias`, separating them from the rest of attributes.\n\"\"\"\n\nDataDict: TypeAlias = dict[str, list[str]]\n\"\"\"Type for a dictionary which, for every module, contains a list with\nthe names of all their DOCUMENTED module-level attributes (identified\nby Sphinx via the ``data`` role, hence the name) which are NOT\nexplicitly defined as :class:`TypeAlias`.\n\"\"\"\n\nTypeVarDict: TypeAlias = dict[str, ModuleTypeVarDict]\n\"\"\"A dictionary mapping module names to dictionaries of :class:`TypeVar` objects.\"\"\"\n\nALIAS_DOCS_DICT: AliasDocsDict = {}\nDATA_DICT: DataDict = {}\nTYPEVAR_DICT: TypeVarDict = {}\n\nMANIM_ROOT = Path(__file__).resolve().parent.parent.parent\n\n# In the following, we will use ``type(xyz) is xyz_type`` instead of\n# isinstance checks to make sure no subclasses of the type pass the\n# check\n# ruff: noqa: E721\n\n\ndef parse_module_attributes() -> tuple[AliasDocsDict, DataDict, TypeVarDict]:\n    \"\"\"Read all files, generate Abstract Syntax Trees from them, and\n    extract useful information about the type aliases defined in the\n    files: the category they belong to, their definition and their\n    description, separating them from the \"regular\" module attributes.\n\n    Returns\n    -------\n    ALIAS_DOCS_DICT : :class:`AliasDocsDict`\n        A dictionary containing the information from all the type\n        aliases in Manim. See :class:`AliasDocsDict` for more information.\n\n    DATA_DICT : :class:`DataDict`\n        A dictionary containing the names of all DOCUMENTED\n        module-level attributes which are not a :class:`TypeAlias`.\n\n    TYPEVAR_DICT : :class:`TypeVarDict`\n        A dictionary containing the definitions of :class:`TypeVar` objects,\n        organized by modules.\n    \"\"\"\n    global ALIAS_DOCS_DICT\n    global DATA_DICT\n    global TYPEVAR_DICT\n\n    if ALIAS_DOCS_DICT or DATA_DICT or TYPEVAR_DICT:\n        return ALIAS_DOCS_DICT, DATA_DICT, TYPEVAR_DICT\n\n    for module_path in MANIM_ROOT.rglob(\"*.py\"):\n        module_name_t1 = module_path.resolve().relative_to(MANIM_ROOT)\n        module_name_t2 = list(module_name_t1.parts)\n        module_name_t2[-1] = module_name_t2[-1].removesuffix(\".py\")\n        module_name = \".\".join(module_name_t2)\n\n        module_content = module_path.read_text(encoding=\"utf-8\")\n\n        # For storing TypeAliases\n        module_dict: ModuleLevelAliasDict = {}\n        category_dict: AliasCategoryDict | None = None\n        alias_info: AliasInfo | None = None\n\n        # For storing TypeVars\n        module_typevars: ModuleTypeVarDict = {}\n\n        # For storing regular module attributes\n        data_list: list[str] = []\n        data_name: str | None = None\n\n        for node in ast.iter_child_nodes(ast.parse(module_content)):\n            # If we encounter a string:\n            if (\n                type(node) is ast.Expr\n                and type(node.value) is ast.Constant\n                and type(node.value.value) is str\n            ):\n                string = node.value.value.strip()\n                # It can be the start of a category\n                section_str = \"[CATEGORY]\"\n                if string.startswith(section_str):\n                    category_name = string[len(section_str) :].strip()\n                    module_dict[category_name] = {}\n                    category_dict = module_dict[category_name]\n                    alias_info = None\n                # or a docstring of the alias defined before\n                elif alias_info:\n                    alias_info[\"doc\"] = string\n                # or a docstring of the module attribute defined before\n                elif data_name:\n                    data_list.append(data_name)\n                continue\n\n            # if it's defined under if TYPE_CHECKING\n            # go through the body of the if statement\n            if (\n                # NOTE: This logic does not (and cannot)\n                # check if the comparison is against a\n                # variable called TYPE_CHECKING\n                # It also says that you cannot do the following\n                # import typing as foo\n                # if foo.TYPE_CHECKING:\n                #   BAR: TypeAlias = ...\n                type(node) is ast.If\n                and (\n                    (\n                        # if TYPE_CHECKING\n                        type(node.test) is ast.Name and node.test.id == \"TYPE_CHECKING\"\n                    )\n                    or (\n                        # if typing.TYPE_CHECKING\n                        type(node.test) is ast.Attribute\n                        and type(node.test.value) is ast.Name\n                        and node.test.value.id == \"typing\"\n                        and node.test.attr == \"TYPE_CHECKING\"\n                    )\n                )\n            ):\n                inner_nodes: list[Any] = node.body\n            else:\n                inner_nodes = [node]\n\n            for node in inner_nodes:\n                # Check if this node is a TypeAlias (type <name> = <value>)\n                # or an AnnAssign annotated as TypeAlias (<target>: TypeAlias = <value>).\n                is_type_alias = (\n                    sys.version_info >= (3, 12) and type(node) is ast.TypeAlias\n                )\n                is_annotated_assignment_with_value = (\n                    type(node) is ast.AnnAssign\n                    and type(node.annotation) is ast.Name\n                    and node.annotation.id == \"TypeAlias\"\n                    and type(node.target) is ast.Name\n                    and node.value is not None\n                )\n                if is_type_alias or is_annotated_assignment_with_value:\n                    # TODO: ast.TypeAlias does not exist before Python 3.12, and that\n                    # could be the reason why MyPy does not recognize these as\n                    # attributes of node.\n                    alias_name = node.name.id if is_type_alias else node.target.id\n                    definition_node = node.value\n\n                    # If the definition is a Union, replace with vertical bar notation.\n                    # Instead of \"Union[Type1, Type2]\", we'll have \"Type1 | Type2\".\n                    if (\n                        type(definition_node) is ast.Subscript\n                        and type(definition_node.value) is ast.Name\n                        and definition_node.value.id == \"Union\"\n                    ):\n                        union_elements = definition_node.slice.elts  # type: ignore[attr-defined]\n                        definition = \" | \".join(\n                            ast.unparse(elem) for elem in union_elements\n                        )\n                    else:\n                        definition = ast.unparse(definition_node)\n\n                    definition = definition.replace(\"npt.\", \"\")\n                    if category_dict is None:\n                        module_dict[\"\"] = {}\n                        category_dict = module_dict[\"\"]\n                    category_dict[alias_name] = {\"definition\": definition}\n                    alias_info = category_dict[alias_name]\n                    continue\n\n                # Check if it is a typing.TypeVar (<target> = TypeVar(...)).\n                elif (\n                    type(node) is ast.Assign\n                    and type(node.targets[0]) is ast.Name\n                    and type(node.value) is ast.Call\n                    and type(node.value.func) is ast.Name\n                    and node.value.func.id.endswith(\"TypeVar\")\n                ):\n                    module_typevars[node.targets[0].id] = ast.unparse(\n                        node.value\n                    ).replace(\"_\", r\"\\_\")\n                    continue\n\n                # If here, the node is not a TypeAlias definition\n                alias_info = None\n\n                # It could still be a module attribute definition.\n                # Does the assignment have a target of type Name? Then\n                # it could be considered a definition of a module attribute.\n                if type(node) is ast.AnnAssign:\n                    target: Name | Attribute | Subscript | ast.expr | None = node.target\n                elif type(node) is ast.Assign and len(node.targets) == 1:\n                    target = node.targets[0]\n                else:\n                    target = None\n\n                if type(target) is ast.Name and not (\n                    type(node) is ast.Assign and target.id not in module_typevars\n                ):\n                    data_name = target.id\n                else:\n                    data_name = None\n\n        if len(module_dict) > 0:\n            ALIAS_DOCS_DICT[module_name] = module_dict\n        if len(data_list) > 0:\n            DATA_DICT[module_name] = data_list\n        if module_typevars:\n            TYPEVAR_DICT[module_name] = module_typevars\n\n    return ALIAS_DOCS_DICT, DATA_DICT, TYPEVAR_DICT\n"
  },
  {
    "path": "manim/utils/exceptions.py",
    "content": "from __future__ import annotations\n\n__all__ = [\n    \"EndSceneEarlyException\",\n    \"RerunSceneException\",\n    \"MultiAnimationOverrideException\",\n]\n\n\nclass EndSceneEarlyException(Exception):\n    pass\n\n\nclass RerunSceneException(Exception):\n    pass\n\n\nclass MultiAnimationOverrideException(Exception):\n    pass\n"
  },
  {
    "path": "manim/utils/family.py",
    "content": "from __future__ import annotations\n\nimport itertools as it\nfrom collections.abc import Iterable\n\nfrom ..mobject.mobject import Mobject\nfrom ..utils.iterables import remove_list_redundancies\n\n__all__ = [\"extract_mobject_family_members\"]\n\n\ndef extract_mobject_family_members(\n    mobjects: Iterable[Mobject],\n    use_z_index: bool = False,\n    only_those_with_points: bool = False,\n) -> list[Mobject]:\n    \"\"\"Returns a list of the types of mobjects and their family members present.\n    A \"family\" in this context refers to a mobject, its submobjects, and their\n    submobjects, recursively.\n\n    Parameters\n    ----------\n    mobjects\n        The Mobjects currently in the Scene\n    only_those_with_points\n        Whether or not to only do this for\n        those mobjects that have points. By default False\n\n    Returns\n    -------\n    list\n        list of the mobjects and family members.\n    \"\"\"\n    if only_those_with_points:\n        method = Mobject.family_members_with_points\n    else:\n        method = Mobject.get_family\n    extracted_mobjects = remove_list_redundancies(\n        list(it.chain(*(method(m) for m in mobjects))),\n    )\n    if use_z_index:\n        return sorted(extracted_mobjects, key=lambda m: m.z_index)\n    return extracted_mobjects\n"
  },
  {
    "path": "manim/utils/family_ops.py",
    "content": "from __future__ import annotations\n\nimport itertools as it\n\nfrom manim.mobject.mobject import Mobject\n\n__all__ = [\n    \"extract_mobject_family_members\",\n    \"restructure_list_to_exclude_certain_family_members\",\n]\n\n\ndef extract_mobject_family_members(\n    mobject_list: list[Mobject], only_those_with_points: bool = False\n) -> list[Mobject]:\n    result = list(it.chain(*(mob.get_family() for mob in mobject_list)))\n    if only_those_with_points:\n        result = [mob for mob in result if mob.has_points()]\n    return result\n\n\ndef restructure_list_to_exclude_certain_family_members(\n    mobject_list: list[Mobject], to_remove: list[Mobject]\n) -> list[Mobject]:\n    \"\"\"\n    Removes anything in to_remove from mobject_list, but in the event that one of\n    the items to be removed is a member of the family of an item in mobject_list,\n    the other family members are added back into the list.\n\n    This is useful in cases where a scene contains a group, e.g. Group(m1, m2, m3),\n    but one of its submobjects is removed, e.g. scene.remove(m1), it's useful\n    for the list of mobject_list to be edited to contain other submobjects, but not m1.\n    \"\"\"\n    new_list: list[Mobject] = []\n    to_remove = extract_mobject_family_members(to_remove)\n\n    def add_safe_mobjects_from_list(\n        list_to_examine: list[Mobject], set_to_remove: set[Mobject]\n    ) -> None:\n        for mob in list_to_examine:\n            if mob in set_to_remove:\n                continue\n            intersect = set_to_remove.intersection(mob.get_family())\n            if intersect:\n                add_safe_mobjects_from_list(mob.submobjects, intersect)\n            else:\n                new_list.append(mob)\n\n    add_safe_mobjects_from_list(mobject_list, set(to_remove))\n    return new_list\n"
  },
  {
    "path": "manim/utils/file_ops.py",
    "content": "\"\"\"Utility functions for interacting with the file system.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"add_extension_if_not_present\",\n    \"guarantee_existence\",\n    \"guarantee_empty_existence\",\n    \"seek_full_path_from_defaults\",\n    \"modify_atime\",\n    \"open_file\",\n    \"is_mp4_format\",\n    \"is_gif_format\",\n    \"is_png_format\",\n    \"is_webm_format\",\n    \"is_mov_format\",\n    \"write_to_movie\",\n    \"ensure_executable\",\n]\n\nimport os\nimport platform\nimport shutil\nimport subprocess as sp\nimport time\nfrom pathlib import Path\nfrom shutil import copyfile\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from manim.typing import StrPath\n\n    from ..scene.scene_file_writer import SceneFileWriter\n\nfrom manim import __version__, config, logger\n\nfrom .. import console\n\n\ndef is_mp4_format() -> bool:\n    \"\"\"\n    Determines if output format is .mp4\n\n    Returns\n    -------\n    class:`bool`\n        ``True`` if format is set as mp4\n\n    \"\"\"\n    val: bool = config[\"format\"] == \"mp4\"\n    return val\n\n\ndef is_gif_format() -> bool:\n    \"\"\"\n    Determines if output format is .gif\n\n    Returns\n    -------\n    class:`bool`\n        ``True`` if format is set as gif\n\n    \"\"\"\n    val: bool = config[\"format\"] == \"gif\"\n    return val\n\n\ndef is_webm_format() -> bool:\n    \"\"\"\n    Determines if output format is .webm\n\n    Returns\n    -------\n    class:`bool`\n        ``True`` if format is set as webm\n\n    \"\"\"\n    val: bool = config[\"format\"] == \"webm\"\n    return val\n\n\ndef is_mov_format() -> bool:\n    \"\"\"\n    Determines if output format is .mov\n\n    Returns\n    -------\n    class:`bool`\n        ``True`` if format is set as mov\n\n    \"\"\"\n    val: bool = config[\"format\"] == \"mov\"\n    return val\n\n\ndef is_png_format() -> bool:\n    \"\"\"\n    Determines if output format is .png\n\n    Returns\n    -------\n    class:`bool`\n        ``True`` if format is set as png\n\n    \"\"\"\n    val: bool = config[\"format\"] == \"png\"\n    return val\n\n\ndef write_to_movie() -> bool:\n    \"\"\"\n    Determines from config if the output is a video format such as mp4 or gif, if the --format is set as 'png'\n    then it will take precedence event if the write_to_movie flag is set\n\n    Returns\n    -------\n    class:`bool`\n        ``True`` if the output should be written in a movie format\n\n    \"\"\"\n    if is_png_format():\n        return False\n    return (\n        config[\"write_to_movie\"]\n        or is_mp4_format()\n        or is_gif_format()\n        or is_webm_format()\n        or is_mov_format()\n    )\n\n\ndef ensure_executable(path_to_exe: Path) -> bool:\n    if path_to_exe.parent == Path(\".\"):\n        executable: StrPath | None = shutil.which(path_to_exe.stem)\n        if executable is None:\n            return False\n    else:\n        executable = path_to_exe\n    return os.access(executable, os.X_OK)\n\n\ndef add_extension_if_not_present(file_name: Path, extension: str) -> Path:\n    if file_name.suffix != extension:\n        return file_name.with_suffix(file_name.suffix + extension)\n    else:\n        return file_name\n\n\ndef add_version_before_extension(file_name: Path) -> Path:\n    return file_name.with_name(\n        f\"{file_name.stem}_ManimCE_v{__version__}{file_name.suffix}\"\n    )\n\n\ndef guarantee_existence(path: Path) -> Path:\n    path.mkdir(parents=True, exist_ok=True)\n    return path.resolve(strict=True)\n\n\ndef guarantee_empty_existence(path: Path) -> Path:\n    if path.exists():\n        shutil.rmtree(str(path))\n    path.mkdir(parents=True, exist_ok=True)\n    return path.resolve(strict=True)\n\n\ndef seek_full_path_from_defaults(\n    file_name: StrPath, default_dir: Path, extensions: list[str]\n) -> Path:\n    possible_paths = [Path(file_name).expanduser()]\n    possible_paths += [\n        Path(default_dir) / f\"{file_name}{extension}\" for extension in [\"\", *extensions]\n    ]\n    for path in possible_paths:\n        if path.exists():\n            return path\n    error = (\n        f\"From: {Path.cwd()}, could not find {file_name} at either \"\n        f\"of these locations: {list(map(str, possible_paths))}\"\n    )\n    raise OSError(error)\n\n\ndef modify_atime(file_path: str) -> None:\n    \"\"\"Will manually change the accessed time (called `atime`) of the file, as on a lot of OS the accessed time refresh is disabled by default.\n\n    Parameters\n    ----------\n    file_path\n        The path of the file.\n    \"\"\"\n    os.utime(file_path, times=(time.time(), Path(file_path).stat().st_mtime))\n\n\ndef open_file(file_path: Path, in_browser: bool = False) -> None:\n    current_os = platform.system()\n    if current_os == \"Windows\":\n        # The method os.startfile is only available in Windows,\n        # ignoring type error caused by this.\n        os.startfile(file_path if not in_browser else file_path.parent)  # type: ignore[attr-defined]\n    else:\n        if current_os == \"Linux\":\n            commands = [\"xdg-open\"]\n            file_path = file_path if not in_browser else file_path.parent\n        elif current_os.startswith(\"CYGWIN\"):\n            commands = [\"cygstart\"]\n            file_path = file_path if not in_browser else file_path.parent\n        elif current_os == \"Darwin\":\n            commands = [\"open\"] if not in_browser else [\"open\", \"-R\"]\n        else:\n            raise OSError(\"Unable to identify your operating system...\")\n\n        # check after so that file path is set correctly\n        if config.preview_command:\n            commands = [config.preview_command]\n        commands.append(str(file_path))\n        sp.run(commands)\n\n\ndef open_media_file(file_writer: SceneFileWriter) -> None:\n    file_paths = []\n\n    if config[\"save_last_frame\"]:\n        file_paths.append(file_writer.image_file_path)\n    if write_to_movie() and not is_gif_format():\n        file_paths.append(file_writer.movie_file_path)\n    if write_to_movie() and is_gif_format():\n        file_paths.append(file_writer.gif_file_path)\n\n    for file_path in file_paths:\n        if config[\"show_in_file_browser\"]:\n            open_file(file_path, True)\n        if config[\"preview\"]:\n            open_file(file_path, False)\n\n            logger.info(f\"Previewed File at: '{file_path}'\")\n\n\ndef get_template_names() -> list[str]:\n    \"\"\"Returns template names from the templates directory.\n\n    Returns\n    -------\n        :class:`list`\n    \"\"\"\n    template_path = Path.resolve(Path(__file__).parent.parent / \"templates\")\n    return [template_name.stem for template_name in template_path.glob(\"*.mtp\")]\n\n\ndef get_template_path() -> Path:\n    \"\"\"Returns the Path of templates directory.\n\n    Returns\n    -------\n        :class:`Path`\n    \"\"\"\n    return Path.resolve(Path(__file__).parent.parent / \"templates\")\n\n\ndef add_import_statement(file: Path) -> None:\n    \"\"\"Prepends an import statement in a file\n\n    Parameters\n    ----------\n        file\n    \"\"\"\n    with file.open(\"r+\") as f:\n        import_line = \"from manim import *\"\n        content = f.read()\n        f.seek(0)\n        f.write(import_line + \"\\n\" + content)\n\n\ndef copy_template_files(\n    project_dir: Path = Path(\".\"), template_name: str = \"Default\"\n) -> None:\n    \"\"\"Copies template files from templates dir to project_dir.\n\n    Parameters\n    ----------\n        project_dir\n            Path to project directory.\n        template_name\n            Name of template.\n    \"\"\"\n    template_cfg_path = Path.resolve(\n        Path(__file__).parent.parent / \"templates/template.cfg\",\n    )\n    template_scene_path = Path.resolve(\n        Path(__file__).parent.parent / f\"templates/{template_name}.mtp\",\n    )\n\n    if not template_cfg_path.exists():\n        raise FileNotFoundError(f\"{template_cfg_path} : file does not exist\")\n    if not template_scene_path.exists():\n        raise FileNotFoundError(f\"{template_scene_path} : file does not exist\")\n\n    copyfile(template_cfg_path, Path.resolve(project_dir / \"manim.cfg\"))\n    console.print(\"\\n\\t[green]copied[/green] [blue]manim.cfg[/blue]\\n\")\n    copyfile(template_scene_path, Path.resolve(project_dir / \"main.py\"))\n    console.print(\"\\n\\t[green]copied[/green] [blue]main.py[/blue]\\n\")\n    add_import_statement(Path.resolve(project_dir / \"main.py\"))\n"
  },
  {
    "path": "manim/utils/hashing.py",
    "content": "\"\"\"Utilities for scene caching.\"\"\"\n\nfrom __future__ import annotations\n\nimport copy\nimport inspect\nimport json\nimport zlib\nfrom collections.abc import Callable, Hashable, Iterable, Sequence\nfrom time import perf_counter\nfrom types import FunctionType, MappingProxyType, MethodType, ModuleType\nfrom typing import TYPE_CHECKING, Any, overload\n\nimport numpy as np\n\nfrom manim._config import config, logger\n\nif TYPE_CHECKING:\n    from manim.animation.animation import Animation\n    from manim.camera.camera import Camera\n    from manim.mobject.mobject import Mobject\n    from manim.renderer.opengl_renderer import OpenGLCamera\n    from manim.scene.scene import Scene\n\n__all__ = [\"KEYS_TO_FILTER_OUT\", \"get_hash_from_play_call\", \"get_json\"]\n\n# Sometimes there are elements that are not suitable for hashing (too long or\n# run-dependent).  This is used to filter them out.\nKEYS_TO_FILTER_OUT = {\n    \"original_id\",\n    \"background\",\n    \"pixel_array\",\n    \"pixel_array_to_cairo_context\",\n}\n\n\nclass _Memoizer:\n    \"\"\"Implements the memoization logic to optimize the hashing procedure and prevent\n    the circular references within iterable processed.\n\n    Keeps a record of all the processed objects, and handle the logic to return a place\n    holder instead of the original object if the object has already been processed\n    by the hashing logic (i.e, recursively checked, converted to JSON, etc..).\n\n    This class uses two signatures functions to keep a track of processed objects :\n    hash or id. Whenever possible, hash is used to ensure a broader object\n    content-equality detection.\n    \"\"\"\n\n    _already_processed = set()\n\n    # Can be changed to whatever string to help debugging the JSon generation.\n    ALREADY_PROCESSED_PLACEHOLDER = \"AP\"\n    THRESHOLD_WARNING = 170_000\n\n    @classmethod\n    def reset_already_processed(cls: type[_Memoizer]) -> None:\n        cls._already_processed.clear()\n\n    @classmethod\n    def check_already_processed_decorator(\n        cls: type[_Memoizer], is_method: bool = False\n    ) -> Callable:\n        \"\"\"Decorator to handle the arguments that goes through the decorated function.\n        Returns the value of ALREADY_PROCESSED_PLACEHOLDER if the obj has been processed,\n        or lets the decorated function call go ahead.\n\n        Parameters\n        ----------\n        is_method\n            Whether the function passed is a method, by default False.\n        \"\"\"\n\n        def layer(func: Callable[[Any], Any]) -> Callable:\n            # NOTE : There is probably a better way to separate both case when func is\n            # a method or a function.\n            if is_method:\n                return lambda self, obj: cls._handle_already_processed(\n                    obj,\n                    default_function=lambda obj: func(self, obj),\n                )\n            return lambda obj: cls._handle_already_processed(obj, default_function=func)\n\n        return layer\n\n    @classmethod\n    def check_already_processed(cls: type[_Memoizer], obj: Any) -> Any:\n        \"\"\"Checks if obj has been already processed. Returns itself if it has not been,\n        or the value of ALREADY_PROCESSED_PLACEHOLDER if it has.\n        Marks the object as processed in the second case.\n\n        Parameters\n        ----------\n        obj\n            The object to check.\n\n        Returns\n        -------\n        Any\n            Either the object itself or the placeholder.\n        \"\"\"\n        # When the object is not memoized, we return the object itself.\n        return cls._handle_already_processed(obj, lambda x: x)\n\n    @classmethod\n    def mark_as_processed(cls: type[_Memoizer], obj: Any) -> None:\n        \"\"\"Marks an object as processed.\n\n        Parameters\n        ----------\n        obj\n            The object to mark as processed.\n        \"\"\"\n        cls._handle_already_processed(obj, lambda x: x)\n        return cls._return(obj, id, lambda x: x, memoizing=False)\n\n    @classmethod\n    def _handle_already_processed(\n        cls: type[_Memoizer],\n        obj: Any,\n        default_function: Callable[[Any], Any],\n    ) -> str | Any:\n        if isinstance(\n            obj,\n            (\n                int,\n                float,\n                str,\n                complex,\n            ),\n        ) and obj not in [None, cls.ALREADY_PROCESSED_PLACEHOLDER]:\n            # It makes no sense (and it'd slower) to memoize objects of these primitive\n            # types.  Hence, we simply return the object.\n            return obj\n        if isinstance(obj, Hashable):\n            try:\n                return cls._return(obj, hash, default_function)\n            except TypeError:\n                # In case of an error with the hash (eg an object is marked as hashable\n                # but contains a non hashable within it)\n                # Fallback to use the built-in function id instead.\n                pass\n        return cls._return(obj, id, default_function)\n\n    @classmethod\n    def _return(\n        cls: type[_Memoizer],\n        obj: Any,\n        obj_to_membership_sign: Callable[[Any], int],\n        default_func: Callable[[Any], Any],\n        memoizing: bool = True,\n    ) -> str | Any:\n        obj_membership_sign = obj_to_membership_sign(obj)\n        if obj_membership_sign in cls._already_processed:\n            return cls.ALREADY_PROCESSED_PLACEHOLDER\n        if memoizing:\n            if (\n                not config.disable_caching_warning\n                and len(cls._already_processed) == cls.THRESHOLD_WARNING\n            ):\n                logger.warning(\n                    \"It looks like the scene contains a lot of sub-mobjects. Caching \"\n                    \"is sometimes not suited to handle such large scenes, you might \"\n                    \"consider disabling caching with --disable_caching to potentially \"\n                    \"speed up the rendering process.\",\n                )\n                logger.warning(\n                    \"You can disable this warning by setting disable_caching_warning \"\n                    \"to True in your config file.\",\n                )\n\n            cls._already_processed.add(obj_membership_sign)\n        return default_func(obj)\n\n\nclass _CustomEncoder(json.JSONEncoder):\n    def default(self, obj: Any) -> Any:\n        \"\"\"This method is used to serialize objects to JSON format.\n\n        If obj is a function, then it will return a dict with two keys : 'code', for\n        the code source, and 'nonlocals' for all nonlocalsvalues. (including nonlocals\n        functions, that will be serialized as this is recursive.)\n        if obj is a np.darray, it converts it into a list.\n        if obj is an object with __dict__ attribute, it returns its __dict__.\n        Else, will let the JSONEncoder do the stuff, and throw an error if the type is\n        not suitable for JSONEncoder.\n\n        Parameters\n        ----------\n        obj\n            Arbitrary object to convert\n\n        Returns\n        -------\n        Any\n            Python object that JSON encoder will recognize\n\n        \"\"\"\n        if not (isinstance(obj, ModuleType)) and isinstance(\n            obj,\n            (MethodType, FunctionType),\n        ):\n            cvars = inspect.getclosurevars(obj)\n            cvardict = {**copy.copy(cvars.globals), **copy.copy(cvars.nonlocals)}\n            for i in list(cvardict):\n                # NOTE : All module types objects are removed, because otherwise it\n                # throws ValueError: Circular reference detected if not. TODO\n                if isinstance(cvardict[i], ModuleType):\n                    del cvardict[i]\n            try:\n                code = inspect.getsource(obj)\n            except (OSError, TypeError):\n                # This happens when rendering videos included in the documentation\n                # within doctests and should be replaced by a solution avoiding\n                # hash collision (due to the same, empty, code strings) at some point.\n                # See https://github.com/ManimCommunity/manim/pull/402.\n                code = \"\"\n            return self._cleaned_iterable({\"code\": code, \"nonlocals\": cvardict})\n        elif isinstance(obj, np.ndarray):\n            if obj.size > 1000:\n                obj = np.resize(obj, (100, 100))\n                return f\"TRUNCATED ARRAY: {repr(obj)}\"\n            # We return the repr and not a list to avoid the JSONEncoder to iterate over it.\n            return repr(obj)\n        elif hasattr(obj, \"__dict__\"):\n            temp = obj.__dict__\n            # MappingProxy is scene-caching nightmare. It contains all of the object methods and attributes. We skip it as the mechanism will at some point process the object, but instantiated.\n            # Indeed, there is certainly no case where scene-caching will receive only a non instancied object, as this is never used in the library or encouraged to be used user-side.\n            if isinstance(temp, MappingProxyType):\n                return \"MappingProxy\"\n            return self._cleaned_iterable(temp)\n        elif isinstance(obj, np.uint8):\n            return int(obj)\n        # Serialize it with only the type of the object. You can change this to whatever string when debugging the serialization process.\n        return str(type(obj))\n\n    @overload\n    def _cleaned_iterable(self, iterable: Sequence[Any]) -> list[Any]: ...\n\n    @overload\n    def _cleaned_iterable(self, iterable: dict[Any, Any]) -> dict[Any, Any]: ...\n\n    def _cleaned_iterable(self, iterable):\n        \"\"\"Check for circular reference at each iterable that will go through the JSONEncoder, as well as key of the wrong format.\n\n        If a key with a bad format is found (i.e not a int, string, or float), it gets replaced by its hash using the same process implemented here.\n        If a circular reference is found within the iterable, it will be replaced by the value of ALREADY_PROCESSED_PLACEHOLDER.\n\n        Parameters\n        ----------\n        iterable\n            The iterable to check.\n        \"\"\"\n\n        def _key_to_hash(key: Any) -> int:\n            return zlib.crc32(json.dumps(key, cls=_CustomEncoder).encode())\n\n        def _iter_check_list(lst: Sequence[Any]) -> list[Any]:\n            processed_list = [None] * len(lst)\n            for i, el in enumerate(lst):\n                el = _Memoizer.check_already_processed(el)\n                if isinstance(el, (list, tuple)):\n                    new_value = _iter_check_list(el)\n                elif isinstance(el, dict):\n                    new_value = _iter_check_dict(el)\n                else:\n                    new_value = el\n                processed_list[i] = new_value\n            return processed_list\n\n        def _iter_check_dict(dct: dict[Any, Any]) -> dict[Any, Any]:\n            processed_dict = {}\n            for k, v in dct.items():\n                v = _Memoizer.check_already_processed(v)\n                if k in KEYS_TO_FILTER_OUT:\n                    continue\n                # We check if the k is of the right format (supported by JSON)\n                if not isinstance(k, (str, int, float, bool)) and k is not None:\n                    k_new = _key_to_hash(k)\n                else:\n                    k_new = k\n                if isinstance(v, dict):\n                    new_value = _iter_check_dict(v)\n                elif isinstance(v, (list, tuple)):\n                    new_value = _iter_check_list(v)\n                else:\n                    new_value = v\n                processed_dict[k_new] = new_value\n            return processed_dict\n\n        if isinstance(iterable, (list, tuple)):\n            return _iter_check_list(iterable)\n        elif isinstance(iterable, dict):\n            return _iter_check_dict(iterable)\n        else:\n            raise TypeError(\"'iterable' is neither an iterable nor a dictionary.\")\n\n    def encode(self, obj: Any) -> str:\n        \"\"\"Overriding of :meth:`JSONEncoder.encode`, to make our own process.\n\n        Parameters\n        ----------\n        obj\n            The object to encode in JSON.\n\n        Returns\n        -------\n        :class:`str`\n           The object encoder with the standard json process.\n        \"\"\"\n        _Memoizer.mark_as_processed(obj)\n        if isinstance(obj, (dict, list, tuple)):\n            return super().encode(self._cleaned_iterable(obj))\n        return super().encode(obj)\n\n\ndef get_json(obj: Any) -> str:\n    \"\"\"Recursively serialize `object` to JSON using the :class:`CustomEncoder` class.\n\n    Parameters\n    ----------\n    obj\n        The dict to flatten\n\n    Returns\n    -------\n    :class:`str`\n        The flattened object\n    \"\"\"\n    return json.dumps(obj, cls=_CustomEncoder)\n\n\ndef get_hash_from_play_call(\n    scene_object: Scene,\n    camera_object: Camera | OpenGLCamera,\n    animations_list: Iterable[Animation],\n    current_mobjects_list: Iterable[Mobject],\n) -> str:\n    \"\"\"Take the list of animations and a list of mobjects and output their hashes. This is meant to be used for `scene.play` function.\n\n    Parameters\n    -----------\n    scene_object\n        The scene object.\n\n    camera_object\n        The camera object used in the scene.\n\n    animations_list\n        The list of animations.\n\n    current_mobjects_list\n        The list of mobjects.\n\n    Returns\n    -------\n    :class:`str`\n        A string concatenation of the respective hashes of `camera_object`, `animations_list` and `current_mobjects_list`, separated by `_`.\n    \"\"\"\n    logger.debug(\"Hashing ...\")\n    t_start = perf_counter()\n    _Memoizer.mark_as_processed(scene_object)\n    camera_json = get_json(camera_object)\n    animations_list_json = [get_json(x) for x in sorted(animations_list, key=str)]\n    current_mobjects_list_json = [get_json(x) for x in current_mobjects_list]\n    hash_camera, hash_animations, hash_current_mobjects = (\n        zlib.crc32(repr(json_val).encode())\n        for json_val in [camera_json, animations_list_json, current_mobjects_list_json]\n    )\n    hash_complete = f\"{hash_camera}_{hash_animations}_{hash_current_mobjects}\"\n    t_end = perf_counter()\n    logger.debug(\"Hashing done in %(time)s s.\", {\"time\": str(t_end - t_start)[:8]})\n    # End of the hashing for the animation, reset all the memoize.\n    _Memoizer.reset_already_processed()\n    logger.debug(\"Hash generated :  %(h)s\", {\"h\": hash_complete})\n    return hash_complete\n"
  },
  {
    "path": "manim/utils/images.py",
    "content": "\"\"\"Image manipulation utilities.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"get_full_raster_image_path\",\n    \"drag_pixels\",\n    \"invert_image\",\n    \"change_to_rgba_array\",\n]\n\nfrom pathlib import Path, PurePath\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\nfrom PIL import Image\n\nfrom .. import config\nfrom ..utils.file_ops import seek_full_path_from_defaults\n\nif TYPE_CHECKING:\n    from collections.abc import Sequence\n\n    from manim.typing import PixelArray, RGBAPixelArray, RGBPixelArray\n\n\ndef get_full_raster_image_path(image_file_name: str | PurePath) -> Path:\n    return seek_full_path_from_defaults(\n        image_file_name,\n        default_dir=config.get_dir(\"assets_dir\"),\n        extensions=[\".jpg\", \".jpeg\", \".png\", \".gif\", \".ico\"],\n    )\n\n\ndef get_full_vector_image_path(image_file_name: str | PurePath) -> Path:\n    return seek_full_path_from_defaults(\n        image_file_name,\n        default_dir=config.get_dir(\"assets_dir\"),\n        extensions=[\".svg\"],\n    )\n\n\ndef drag_pixels(frames: Sequence[PixelArray]) -> list[np.ndarray]:\n    curr = frames[0]\n    new_frames: list[np.ndarray] = []\n    for frame in frames:\n        curr += (curr == 0) * np.array(frame)\n        new_frames.append(np.array(curr))\n    return new_frames\n\n\ndef invert_image(image: PixelArray) -> Image:\n    arr = np.array(image)\n    arr = (255 * np.ones(arr.shape)).astype(arr.dtype) - arr\n    return Image.fromarray(arr)\n\n\ndef change_to_rgba_array(image: RGBPixelArray, dtype: str = \"uint8\") -> RGBAPixelArray:\n    \"\"\"Converts an RGB array into RGBA with the alpha value opacity maxed.\"\"\"\n    pa = image\n    if len(pa.shape) == 2:\n        pa = pa.reshape(list(pa.shape) + [1])\n    if pa.shape[2] == 1:\n        pa = pa.repeat(3, axis=2)\n    if pa.shape[2] == 3:\n        alphas = 255 * np.ones(\n            list(pa.shape[:2]) + [1],\n            dtype=dtype,\n        )\n        pa = np.append(pa, alphas, axis=2)\n    return pa\n"
  },
  {
    "path": "manim/utils/ipython_magic.py",
    "content": "\"\"\"Utilities for using Manim with IPython (in particular: Jupyter notebooks)\"\"\"\n\nfrom __future__ import annotations\n\nimport mimetypes\nimport shutil\nfrom datetime import datetime\nfrom pathlib import Path\nfrom typing import Any\n\nfrom manim import config, logger, tempconfig\nfrom manim.__main__ import main\nfrom manim.renderer.shader import shader_program_cache\n\nfrom ..constants import RendererType\n\n__all__ = [\"ManimMagic\"]\n\ntry:\n    from IPython import get_ipython\n    from IPython.core.interactiveshell import InteractiveShell\n    from IPython.core.magic import (\n        Magics,\n        line_cell_magic,\n        magics_class,\n        needs_local_scope,\n    )\n    from IPython.display import Image, Video, display\nexcept ImportError:\n    pass\nelse:\n\n    @magics_class\n    class ManimMagic(Magics):\n        def __init__(self, shell: InteractiveShell) -> None:\n            super().__init__(shell)\n            self.rendered_files: dict[Path, Path] = {}\n\n        @needs_local_scope\n        @line_cell_magic\n        def manim(\n            self,\n            line: str,\n            cell: str | None = None,\n            local_ns: dict[str, Any] | None = None,\n        ) -> None:\n            r\"\"\"Render Manim scenes contained in IPython cells.\n            Works as a line or cell magic.\n\n            .. hint::\n\n                This line and cell magic works best when used in a JupyterLab\n                environment: while all of the functionality is available for\n                classic Jupyter notebooks as well, it is possible that videos\n                sometimes don't update on repeated execution of the same cell\n                if the scene name stays the same.\n\n                This problem does not occur when using JupyterLab.\n\n            Please refer to `<https://jupyter.org/>`_ for more information about JupyterLab\n            and Jupyter notebooks.\n\n            Usage in line mode::\n\n                %manim [CLI options] MyAwesomeScene\n\n            Usage in cell mode::\n\n                %%manim [CLI options] MyAwesomeScene\n\n                class MyAweseomeScene(Scene):\n                    def construct(self):\n                        ...\n\n            Run ``%manim --help`` and ``%manim render --help`` for possible command line interface options.\n\n            .. note::\n\n                The maximal width of the rendered videos that are displayed in the notebook can be\n                configured via the ``media_width`` configuration option. The default is set to ``25vw``,\n                which is 25% of your current viewport width. To allow the output to become as large\n                as possible, set ``config.media_width = \"100%\"``.\n\n                The ``media_embed`` option will embed the image/video output in the notebook. This is\n                generally undesirable as it makes the notebooks very large, but is required on some\n                platforms (notably Google's CoLab, where it is automatically enabled unless suppressed\n                by ``config.embed = False``) and needed in cases when the notebook (or converted HTML\n                file) will be moved relative to the video locations. Use-cases include building\n                documentation with Sphinx and JupyterBook. See also the :mod:`manim directive for Sphinx\n                <manim.utils.docbuild.manim_directive>`.\n\n            Examples\n            --------\n\n            First make sure to put ``import manim``, or even ``from manim import *``\n            in a cell and evaluate it. Then, a typical Jupyter notebook cell for Manim\n            could look as follows::\n\n                %%manim -v WARNING --disable_caching -qm BannerExample\n\n                config.media_width = \"75%\"\n                config.media_embed = True\n\n                class BannerExample(Scene):\n                    def construct(self):\n                        self.camera.background_color = \"#ece6e2\"\n                        banner_large = ManimBanner(dark_theme=False).scale(0.7)\n                        self.play(banner_large.create())\n                        self.play(banner_large.expand())\n\n            Evaluating this cell will render and display the ``BannerExample`` scene defined in the body of the cell.\n\n            .. note::\n\n                In case you want to hide the red box containing the output progress bar, the ``progress_bar`` config\n                option should be set to ``None``. This can also be done by passing ``--progress_bar None`` as a\n                CLI flag.\n\n            \"\"\"\n            if cell:\n                exec(cell, local_ns)\n\n            args = line.split()\n            if not len(args) or \"-h\" in args or \"--help\" in args or \"--version\" in args:\n                main(args, standalone_mode=False, prog_name=\"manim\")\n                return\n\n            modified_args = self.add_additional_args(args)\n            args = main(modified_args, standalone_mode=False, prog_name=\"manim\")\n            assert isinstance(local_ns, dict)\n            with tempconfig(local_ns.get(\"config\", {})):\n                config.digest_args(args)\n\n                renderer = None\n                if config.renderer == RendererType.OPENGL:\n                    from manim.renderer.opengl_renderer import OpenGLRenderer\n\n                    renderer = OpenGLRenderer()\n\n                try:\n                    SceneClass = local_ns[config[\"scene_names\"][0]]\n                    scene = SceneClass(renderer=renderer)\n                    scene.render()\n                finally:\n                    # Shader cache becomes invalid as the context is destroyed\n                    shader_program_cache.clear()\n\n                    # Close OpenGL window here instead of waiting for the main thread to\n                    # finish causing the window to stay open and freeze\n                    if renderer is not None and renderer.window is not None:\n                        renderer.window.close()\n\n                if config[\"output_file\"] is None:\n                    logger.info(\"No output file produced\")\n                    return\n\n                local_path = Path(config[\"output_file\"]).relative_to(Path.cwd())\n                tmpfile = (\n                    Path(config[\"media_dir\"])\n                    / \"jupyter\"\n                    / f\"{_generate_file_name()}{local_path.suffix}\"\n                )\n\n                if local_path in self.rendered_files:\n                    self.rendered_files[local_path].unlink()\n                self.rendered_files[local_path] = tmpfile\n                tmpfile.parent.mkdir(parents=True, exist_ok=True)\n                shutil.copy(local_path, tmpfile)\n\n                file_type = mimetypes.guess_type(config[\"output_file\"])[0]\n                assert isinstance(file_type, str)\n                embed = config[\"media_embed\"]\n                if not embed:\n                    # videos need to be embedded when running in google colab.\n                    # do this automatically in case config.media_embed has not been\n                    # set explicitly.\n                    embed = \"google.colab\" in str(get_ipython())\n\n                if file_type.startswith(\"image\"):\n                    result = Image(filename=config[\"output_file\"])\n                else:\n                    result = Video(\n                        tmpfile,\n                        html_attributes=f'controls autoplay loop style=\"max-width: {config[\"media_width\"]};\"',\n                        embed=embed,\n                    )\n\n                display(result)\n\n        def add_additional_args(self, args: list[str]) -> list[str]:\n            additional_args = [\"--jupyter\"]\n            # Use webm to support transparency\n            if \"-t\" in args and \"--format\" not in args:\n                additional_args += [\"--format\", \"webm\"]\n            return additional_args + args[:-1] + [\"\"] + [args[-1]]\n\n\ndef _generate_file_name() -> str:\n    val: str = (\n        config[\"scene_names\"][0] + \"@\" + datetime.now().strftime(\"%Y-%m-%d@%H-%M-%S\")\n    )\n    return val\n"
  },
  {
    "path": "manim/utils/iterables.py",
    "content": "\"\"\"Operations on iterables.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"adjacent_n_tuples\",\n    \"adjacent_pairs\",\n    \"all_elements_are_instances\",\n    \"concatenate_lists\",\n    \"list_difference_update\",\n    \"list_update\",\n    \"listify\",\n    \"make_even\",\n    \"make_even_by_cycling\",\n    \"remove_list_redundancies\",\n    \"remove_nones\",\n    \"stretch_array_to_length\",\n    \"tuplify\",\n]\n\nimport itertools as it\nfrom collections.abc import (\n    Callable,\n    Collection,\n    Generator,\n    Hashable,\n    Iterable,\n    Reversible,\n    Sequence,\n)\nfrom typing import TYPE_CHECKING, TypeVar, overload\n\nimport numpy as np\n\nT = TypeVar(\"T\")\nU = TypeVar(\"U\")\nF = TypeVar(\"F\", np.float64, np.int_)\nH = TypeVar(\"H\", bound=Hashable)\n\n\nif TYPE_CHECKING:\n    import numpy.typing as npt\n\n\ndef adjacent_n_tuples(objects: Sequence[T], n: int) -> zip[tuple[T, ...]]:\n    \"\"\"Returns the Sequence objects cyclically split into n length tuples.\n\n    See Also\n    --------\n    adjacent_pairs : alias with n=2\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> list(adjacent_n_tuples([1, 2, 3, 4], 2))\n        [(1, 2), (2, 3), (3, 4), (4, 1)]\n        >>> list(adjacent_n_tuples([1, 2, 3, 4], 3))\n        [(1, 2, 3), (2, 3, 4), (3, 4, 1), (4, 1, 2)]\n    \"\"\"\n    return zip(*([*objects[k:], *objects[:k]] for k in range(n)), strict=True)\n\n\ndef adjacent_pairs(objects: Sequence[T]) -> zip[tuple[T, ...]]:\n    \"\"\"Alias for ``adjacent_n_tuples(objects, 2)``.\n\n    See Also\n    --------\n    adjacent_n_tuples\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> list(adjacent_pairs([1, 2, 3, 4]))\n        [(1, 2), (2, 3), (3, 4), (4, 1)]\n    \"\"\"\n    return adjacent_n_tuples(objects, 2)\n\n\ndef all_elements_are_instances(iterable: Iterable[object], Class: type[object]) -> bool:\n    \"\"\"Returns ``True`` if all elements of iterable are instances of Class.\n    False otherwise.\n    \"\"\"\n    return all(isinstance(e, Class) for e in iterable)\n\n\ndef batch_by_property(\n    items: Iterable[T], property_func: Callable[[T], U]\n) -> list[tuple[list[T], U | None]]:\n    \"\"\"Takes in a Sequence, and returns a list of tuples, (batch, prop)\n    such that all items in a batch have the same output when\n    put into the Callable property_func, and such that chaining all these\n    batches together would give the original Sequence (i.e. order is\n    preserved).\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> batch_by_property([(1, 2), (3, 4), (5, 6, 7), (8, 9)], len)\n        [([(1, 2), (3, 4)], 2), ([(5, 6, 7)], 3), ([(8, 9)], 2)]\n    \"\"\"\n    batch_prop_pairs: list[tuple[list[T], U | None]] = []\n    curr_batch: list[T] = []\n    curr_prop = None\n    for item in items:\n        prop = property_func(item)\n        if prop != curr_prop:\n            # Add current batch\n            if len(curr_batch) > 0:\n                batch_prop_pairs.append((curr_batch, curr_prop))\n            # Redefine curr\n            curr_prop = prop\n            curr_batch = [item]\n        else:\n            curr_batch.append(item)\n    if len(curr_batch) > 0:\n        batch_prop_pairs.append((curr_batch, curr_prop))\n    return batch_prop_pairs\n\n\ndef concatenate_lists(*list_of_lists: Iterable[T]) -> list[T]:\n    \"\"\"Combines the Iterables provided as arguments into one list.\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> concatenate_lists([1, 2], [3, 4], [5])\n        [1, 2, 3, 4, 5]\n    \"\"\"\n    return [item for lst in list_of_lists for item in lst]\n\n\ndef list_difference_update(l1: Iterable[T], l2: Iterable[T]) -> list[T]:\n    \"\"\"Returns a list containing all the elements of l1 not in l2.\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> list_difference_update([1, 2, 3, 4], [2, 4])\n        [1, 3]\n    \"\"\"\n    return [e for e in l1 if e not in l2]\n\n\ndef list_update(l1: Iterable[T], l2: Iterable[T]) -> list[T]:\n    \"\"\"Used instead of ``set.update()`` to maintain order,\n        making sure duplicates are removed from l1, not l2.\n        Removes overlap of l1 and l2 and then concatenates l2 unchanged.\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> list_update([1, 2, 3], [2, 4, 4])\n        [1, 3, 2, 4, 4]\n    \"\"\"\n    return [e for e in l1 if e not in l2] + list(l2)\n\n\n@overload\ndef listify(obj: str) -> list[str]: ...\n\n\n@overload\ndef listify(obj: Iterable[T]) -> list[T]: ...\n\n\n@overload\ndef listify(obj: T) -> list[T]: ...\n\n\ndef listify(obj: str | Iterable[T] | T) -> list[str] | list[T]:\n    \"\"\"Converts obj to a list intelligently.\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> listify(\"str\")\n        ['str']\n        >>> listify((1, 2))\n        [1, 2]\n        >>> listify(len)\n        [<built-in function len>]\n    \"\"\"\n    if isinstance(obj, str):\n        return [obj]\n    if isinstance(obj, Iterable):\n        return list(obj)\n    else:\n        return [obj]\n\n\ndef make_even(\n    iterable_1: Iterable[T], iterable_2: Iterable[U]\n) -> tuple[list[T], list[U]]:\n    \"\"\"Extends the shorter of the two iterables with duplicate values until its\n        length is equal to the longer iterable (favours earlier elements).\n\n    See Also\n    --------\n    make_even_by_cycling : cycles elements instead of favouring earlier ones\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> make_even([1, 2], [3, 4, 5, 6])\n        ([1, 1, 2, 2], [3, 4, 5, 6])\n\n        >>> make_even([1, 2], [3, 4, 5, 6, 7])\n        ([1, 1, 1, 2, 2], [3, 4, 5, 6, 7])\n    \"\"\"\n    list_1, list_2 = list(iterable_1), list(iterable_2)\n    len_list_1 = len(list_1)\n    len_list_2 = len(list_2)\n    length = max(len_list_1, len_list_2)\n    return (\n        [list_1[(n * len_list_1) // length] for n in range(length)],\n        [list_2[(n * len_list_2) // length] for n in range(length)],\n    )\n\n\ndef make_even_by_cycling(\n    iterable_1: Collection[T], iterable_2: Collection[U]\n) -> tuple[list[T], list[U]]:\n    \"\"\"Extends the shorter of the two iterables with duplicate values until its\n        length is equal to the longer iterable (cycles over shorter iterable).\n\n    See Also\n    --------\n    make_even : favours earlier elements instead of cycling them\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> make_even_by_cycling([1, 2], [3, 4, 5, 6])\n        ([1, 2, 1, 2], [3, 4, 5, 6])\n\n        >>> make_even_by_cycling([1, 2], [3, 4, 5, 6, 7])\n        ([1, 2, 1, 2, 1], [3, 4, 5, 6, 7])\n    \"\"\"\n    length = max(len(iterable_1), len(iterable_2))\n    cycle1 = it.cycle(iterable_1)\n    cycle2 = it.cycle(iterable_2)\n    return (\n        [next(cycle1) for _ in range(length)],\n        [next(cycle2) for _ in range(length)],\n    )\n\n\ndef remove_list_redundancies(lst: Reversible[H]) -> list[H]:\n    \"\"\"Used instead of ``list(set(l))`` to maintain order.\n    Keeps the last occurrence of each element.\n    \"\"\"\n    reversed_result = []\n    used = set()\n    for x in reversed(lst):\n        if x not in used:\n            reversed_result.append(x)\n            used.add(x)\n    reversed_result.reverse()\n    return reversed_result\n\n\ndef remove_nones(sequence: Iterable[T | None]) -> list[T]:\n    \"\"\"Removes elements where bool(x) evaluates to False.\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> remove_nones([\"m\", \"\", \"l\", 0, 42, False, True])\n        ['m', 'l', 42, True]\n    \"\"\"\n    # Note this is redundant with it.chain\n    return [x for x in sequence if x]\n\n\ndef resize_array(nparray: npt.NDArray[F], length: int) -> npt.NDArray[F]:\n    \"\"\"Extends/truncates nparray so that ``len(result) == length``.\n        The elements of nparray are cycled to achieve the desired length.\n\n    See Also\n    --------\n    resize_preserving_order : favours earlier elements instead of cycling them\n    make_even_by_cycling : similar cycling behaviour for balancing 2 iterables\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> points = np.array([[1, 2], [3, 4]])\n        >>> resize_array(points, 1)\n        array([[1, 2]])\n        >>> resize_array(points, 3)\n        array([[1, 2],\n               [3, 4],\n               [1, 2]])\n        >>> resize_array(points, 2)\n        array([[1, 2],\n               [3, 4]])\n    \"\"\"\n    if len(nparray) == length:\n        return nparray\n    return np.resize(nparray, (length, *nparray.shape[1:]))\n\n\ndef resize_preserving_order(\n    nparray: npt.NDArray[np.float64], length: int\n) -> npt.NDArray[np.float64]:\n    \"\"\"Extends/truncates nparray so that ``len(result) == length``.\n        The elements of nparray are duplicated to achieve the desired length\n        (favours earlier elements).\n\n        Constructs a zeroes array of length if nparray is empty.\n\n    See Also\n    --------\n    resize_array : cycles elements instead of favouring earlier ones\n    make_even : similar earlier-favouring behaviour for balancing 2 iterables\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> resize_preserving_order(np.array([]), 5)\n        array([0., 0., 0., 0., 0.])\n\n        >>> nparray = np.array([[1, 2], [3, 4]])\n        >>> resize_preserving_order(nparray, 1)\n        array([[1, 2]])\n\n        >>> resize_preserving_order(nparray, 3)\n        array([[1, 2],\n               [1, 2],\n               [3, 4]])\n    \"\"\"\n    if len(nparray) == 0:\n        return np.zeros((length, *nparray.shape[1:]))\n    if len(nparray) == length:\n        return nparray\n    indices = np.arange(length) * len(nparray) // length\n    return nparray[indices]\n\n\ndef resize_with_interpolation(nparray: npt.NDArray[F], length: int) -> npt.NDArray[F]:\n    \"\"\"Extends/truncates nparray so that ``len(result) == length``.\n        New elements are interpolated to achieve the desired length.\n\n        Note that if nparray's length changes, its dtype may too\n        (e.g. int -> float: see Examples)\n\n    See Also\n    --------\n    resize_array : cycles elements instead of interpolating\n    resize_preserving_order : favours earlier elements instead of interpolating\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> nparray = np.array([[1, 2], [3, 4]])\n        >>> resize_with_interpolation(nparray, 1)\n        array([[1., 2.]])\n        >>> resize_with_interpolation(nparray, 4)\n        array([[1.        , 2.        ],\n               [1.66666667, 2.66666667],\n               [2.33333333, 3.33333333],\n               [3.        , 4.        ]])\n        >>> nparray = np.array([[[1, 2], [3, 4]]])\n        >>> nparray = np.array([[1, 2], [3, 4], [5, 6]])\n        >>> resize_with_interpolation(nparray, 4)\n        array([[1.        , 2.        ],\n               [2.33333333, 3.33333333],\n               [3.66666667, 4.66666667],\n               [5.        , 6.        ]])\n        >>> nparray = np.array([[1, 2], [3, 4], [1, 2]])\n        >>> resize_with_interpolation(nparray, 4)\n        array([[1.        , 2.        ],\n               [2.33333333, 3.33333333],\n               [2.33333333, 3.33333333],\n               [1.        , 2.        ]])\n    \"\"\"\n    if len(nparray) == length:\n        return nparray\n    cont_indices = np.linspace(0, len(nparray) - 1, length)\n    return np.array(\n        [\n            (1 - a) * nparray[lh] + a * nparray[rh]\n            for ci in cont_indices\n            for lh, rh, a in [(int(ci), int(np.ceil(ci)), ci % 1)]\n        ],\n    )\n\n\ndef stretch_array_to_length(nparray: npt.NDArray[F], length: int) -> npt.NDArray[F]:\n    # todo: is this the same as resize_preserving_order()?\n    curr_len = len(nparray)\n    if curr_len > length:\n        raise Warning(\"Trying to stretch array to a length shorter than its own\")\n    indices = np.arange(length) / float(length)\n    indices *= curr_len\n    return nparray[indices.astype(int)]\n\n\n@overload\ndef tuplify(obj: str) -> tuple[str]: ...\n\n\n@overload\ndef tuplify(obj: Iterable[T]) -> tuple[T]: ...\n\n\n@overload\ndef tuplify(obj: T) -> tuple[T]: ...\n\n\ndef tuplify(obj: str | Iterable[T] | T) -> tuple[str] | tuple[T]:\n    \"\"\"Converts obj to a tuple intelligently.\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> tuplify(\"str\")\n        ('str',)\n        >>> tuplify([1, 2])\n        (1, 2)\n        >>> tuplify(len)\n        (<built-in function len>,)\n    \"\"\"\n    if isinstance(obj, str):\n        return (obj,)\n    if isinstance(obj, Iterable):\n        return tuple(obj)\n    else:\n        return (obj,)\n\n\ndef uniq_chain(*args: Iterable[T]) -> Generator[T, None, None]:\n    \"\"\"Returns a generator that yields all unique elements of the Iterables\n        provided via args in the order provided.\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> gen = uniq_chain([1, 2], [2, 3], [1, 4, 4])\n        >>> from collections.abc import Generator\n        >>> isinstance(gen, Generator)\n        True\n        >>> tuple(gen)\n        (1, 2, 3, 4)\n    \"\"\"\n    unique_items = set()\n    for x in it.chain(*args):\n        if x in unique_items:\n            continue\n        unique_items.add(x)\n        yield x\n\n\ndef hash_obj(obj: object) -> int:\n    \"\"\"Determines a hash, even of potentially mutable objects.\"\"\"\n    if isinstance(obj, dict):\n        return hash(tuple(sorted((hash_obj(k), hash_obj(v)) for k, v in obj.items())))\n\n    if isinstance(obj, set):\n        return hash(tuple(sorted(hash_obj(e) for e in obj)))\n\n    if isinstance(obj, (tuple, list)):\n        return hash(tuple(hash_obj(e) for e in obj))\n\n    return hash(obj)\n"
  },
  {
    "path": "manim/utils/module_ops.py",
    "content": "from __future__ import annotations\n\nimport importlib.util\nimport inspect\nimport re\nimport sys\nimport types\nimport warnings\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, Any, Literal, overload\n\nfrom manim._config import config, console, logger\nfrom manim.constants import (\n    CHOOSE_NUMBER_MESSAGE,\n    INVALID_NUMBER_MESSAGE,\n    NO_SCENE_MESSAGE,\n    SCENE_NOT_FOUND_MESSAGE,\n)\nfrom manim.scene.scene_file_writer import SceneFileWriter\n\nif TYPE_CHECKING:\n    from manim.scene.scene import Scene\n\n__all__ = [\"scene_classes_from_file\"]\n\n\ndef get_module(file_name: Path) -> types.ModuleType:\n    if str(file_name) == \"-\":\n        module = types.ModuleType(\"input_scenes\")\n        logger.info(\n            \"Enter the animation's code & end with an EOF (CTRL+D on Linux/Unix, CTRL+Z on Windows):\",\n        )\n        code = sys.stdin.read()\n        if not code.startswith(\"from manim import\"):\n            logger.warning(\n                \"Didn't find an import statement for Manim. Importing automatically...\",\n            )\n            code = \"from manim import *\\n\" + code\n        logger.info(\"Rendering animation from typed code...\")\n        try:\n            exec(code, module.__dict__)\n            return module\n        except Exception as e:\n            logger.error(f\"Failed to render scene: {str(e)}\")\n            sys.exit(2)\n    else:\n        if file_name.exists():\n            ext = file_name.suffix\n            if ext != \".py\":\n                raise ValueError(f\"{file_name} is not a valid Manim python script.\")\n            module_name = \".\".join(file_name.with_suffix(\"\").parts)\n\n            warnings.filterwarnings(\n                \"default\",\n                category=DeprecationWarning,\n                module=module_name,\n            )\n\n            spec = importlib.util.spec_from_file_location(module_name, file_name)\n            if isinstance(spec, importlib.machinery.ModuleSpec):\n                module = importlib.util.module_from_spec(spec)\n                sys.modules[module_name] = module\n                sys.path.insert(0, str(file_name.parent.absolute()))\n                assert spec.loader\n                spec.loader.exec_module(module)\n                return module\n            raise FileNotFoundError(f\"{file_name} not found\")\n        else:\n            raise FileNotFoundError(f\"{file_name} not found\")\n\n\ndef get_scene_classes_from_module(module: types.ModuleType) -> list[type[Scene]]:\n    from ..scene.scene import Scene\n\n    def is_child_scene(obj: Any, module: types.ModuleType) -> bool:\n        return (\n            inspect.isclass(obj)\n            and issubclass(obj, Scene)\n            and obj != Scene\n            and obj.__module__.startswith(module.__name__)\n        )\n\n    return [\n        member[1]\n        for member in inspect.getmembers(module, lambda x: is_child_scene(x, module))\n    ]\n\n\ndef get_scenes_to_render(scene_classes: list[type[Scene]]) -> list[type[Scene]]:\n    if not scene_classes:\n        logger.error(NO_SCENE_MESSAGE)\n        return []\n    if config[\"write_all\"]:\n        return scene_classes\n    result = []\n    for scene_name in config[\"scene_names\"]:\n        found = False\n        for scene_class in scene_classes:\n            if scene_class.__name__ == scene_name:\n                result.append(scene_class)\n                found = True\n                break\n        if not found and (scene_name != \"\"):\n            logger.error(SCENE_NOT_FOUND_MESSAGE.format(scene_name))\n    if result:\n        return result\n    if len(scene_classes) == 1:\n        config[\"scene_names\"] = [scene_classes[0].__name__]\n        return [scene_classes[0]]\n    return prompt_user_for_choice(scene_classes)\n\n\ndef prompt_user_for_choice(scene_classes: list[type[Scene]]) -> list[type[Scene]]:\n    num_to_class = {}\n    SceneFileWriter.force_output_as_scene_name = True\n    for count, scene_class in enumerate(scene_classes, 1):\n        name = scene_class.__name__\n        console.print(f\"{count}: {name}\", style=\"logging.level.info\")\n        num_to_class[count] = scene_class\n    try:\n        user_input = console.input(\n            f\"[log.message] {CHOOSE_NUMBER_MESSAGE} [/log.message]\",\n        )\n\n        if user_input == \"*\":\n            selected_scenes_classes = scene_classes\n        else:\n            selected_scenes_classes = [\n                num_to_class[int(num_str)]\n                for num_str in re.split(r\"\\s*,\\s*\", user_input.strip())\n            ]\n        config[\"scene_names\"] = [\n            scene_class.__name__ for scene_class in selected_scenes_classes\n        ]\n        return selected_scenes_classes\n    except KeyError:\n        logger.error(INVALID_NUMBER_MESSAGE)\n        sys.exit(2)\n    except EOFError:\n        sys.exit(1)\n    except ValueError:\n        logger.error(\"No scenes were selected. Exiting.\")\n        sys.exit(1)\n\n\n@overload\ndef scene_classes_from_file(\n    file_path: Path, require_single_scene: bool, full_list: Literal[True]\n) -> list[type[Scene]]: ...\n\n\n@overload\ndef scene_classes_from_file(\n    file_path: Path,\n    require_single_scene: Literal[True],\n    full_list: Literal[False] = False,\n) -> type[Scene]: ...\n\n\n@overload\ndef scene_classes_from_file(\n    file_path: Path,\n    require_single_scene: Literal[False] = False,\n    full_list: Literal[False] = False,\n) -> list[type[Scene]]: ...\n\n\ndef scene_classes_from_file(\n    file_path: Path, require_single_scene: bool = False, full_list: bool = False\n) -> type[Scene] | list[type[Scene]]:\n    module = get_module(file_path)\n    all_scene_classes = get_scene_classes_from_module(module)\n    if full_list:\n        return all_scene_classes\n    scene_classes_to_render = get_scenes_to_render(all_scene_classes)\n    if require_single_scene:\n        assert len(scene_classes_to_render) == 1\n        return scene_classes_to_render[0]\n    return scene_classes_to_render\n"
  },
  {
    "path": "manim/utils/opengl.py",
    "content": "from __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\nimport numpy.linalg as linalg\n\nfrom manim._config import config\nfrom manim.typing import ManimFloat\n\nif TYPE_CHECKING:\n    from typing import TypeAlias\n\n    import numpy.typing as npt\n\n    from manim.typing import MatrixMN, Point3D\n\n\ndepth = 20\n\n__all__ = [\n    \"matrix_to_shader_input\",\n    \"orthographic_projection_matrix\",\n    \"perspective_projection_matrix\",\n    \"translation_matrix\",\n    \"x_rotation_matrix\",\n    \"y_rotation_matrix\",\n    \"z_rotation_matrix\",\n    \"rotate_in_place_matrix\",\n    \"rotation_matrix\",\n    \"scale_matrix\",\n    \"view_matrix\",\n]\n\nFlattenedMatrix4x4: TypeAlias = tuple[\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n    float,\n]\n\n\ndef matrix_to_shader_input(matrix: MatrixMN) -> FlattenedMatrix4x4:\n    return tuple(matrix.T.ravel())\n\n\ndef orthographic_projection_matrix(\n    width: float | None = None,\n    height: float | None = None,\n    near: float = 1,\n    far: float = depth + 1,\n    format_: bool = True,\n) -> MatrixMN | FlattenedMatrix4x4:\n    if width is None:\n        width = config[\"frame_width\"]\n    if height is None:\n        height = config[\"frame_height\"]\n    projection_matrix = np.array(\n        [\n            [2 / width, 0, 0, 0],\n            [0, 2 / height, 0, 0],\n            [0, 0, -2 / (far - near), -(far + near) / (far - near)],\n            [0, 0, 0, 1],\n        ],\n    )\n    if format_:\n        return matrix_to_shader_input(projection_matrix)\n    else:\n        return projection_matrix\n\n\ndef perspective_projection_matrix(\n    width: float | None = None,\n    height: float | None = None,\n    near: float = 2,\n    far: float = 50,\n    format_: bool = True,\n) -> MatrixMN | FlattenedMatrix4x4:\n    if width is None:\n        width = config[\"frame_width\"] / 6\n    if height is None:\n        height = config[\"frame_height\"] / 6\n    projection_matrix = np.array(\n        [\n            [2 * near / width, 0, 0, 0],\n            [0, 2 * near / height, 0, 0],\n            [0, 0, (far + near) / (near - far), (2 * far * near) / (near - far)],\n            [0, 0, -1, 0],\n        ],\n    )\n    if format_:\n        return matrix_to_shader_input(projection_matrix)\n    else:\n        return projection_matrix\n\n\ndef translation_matrix(x: float = 0, y: float = 0, z: float = 0) -> MatrixMN:\n    return np.array(\n        [\n            [1, 0, 0, x],\n            [0, 1, 0, y],\n            [0, 0, 1, z],\n            [0, 0, 0, 1],\n        ],\n        dtype=ManimFloat,\n    )\n\n\ndef x_rotation_matrix(x: float = 0) -> MatrixMN:\n    return np.array(\n        [\n            [1, 0, 0, 0],\n            [0, np.cos(x), -np.sin(x), 0],\n            [0, np.sin(x), np.cos(x), 0],\n            [0, 0, 0, 1],\n        ],\n    )\n\n\ndef y_rotation_matrix(y: float = 0) -> MatrixMN:\n    return np.array(\n        [\n            [np.cos(y), 0, np.sin(y), 0],\n            [0, 1, 0, 0],\n            [-np.sin(y), 0, np.cos(y), 0],\n            [0, 0, 0, 1],\n        ],\n    )\n\n\ndef z_rotation_matrix(z: float = 0) -> MatrixMN:\n    return np.array(\n        [\n            [np.cos(z), -np.sin(z), 0, 0],\n            [np.sin(z), np.cos(z), 0, 0],\n            [0, 0, 1, 0],\n            [0, 0, 0, 1],\n        ],\n    )\n\n\n# TODO: When rotating around the x axis, rotation eventually stops.\ndef rotate_in_place_matrix(\n    initial_position: Point3D, x: float = 0, y: float = 0, z: float = 0\n) -> MatrixMN:\n    return np.matmul(\n        translation_matrix(*-initial_position),\n        np.matmul(\n            rotation_matrix(x, y, z),\n            translation_matrix(*initial_position),\n        ),\n    )\n\n\ndef rotation_matrix(x: float = 0, y: float = 0, z: float = 0) -> MatrixMN:\n    return np.matmul(\n        np.matmul(x_rotation_matrix(x), y_rotation_matrix(y)),\n        z_rotation_matrix(z),\n    )\n\n\ndef scale_matrix(scale_factor: float = 1) -> npt.NDArray:\n    return np.array(\n        [\n            [scale_factor, 0, 0, 0],\n            [0, scale_factor, 0, 0],\n            [0, 0, scale_factor, 0],\n            [0, 0, 0, 1],\n        ],\n        dtype=ManimFloat,\n    )\n\n\ndef view_matrix(\n    translation: Point3D | None = None,\n    x_rotation: float = 0,\n    y_rotation: float = 0,\n    z_rotation: float = 0,\n) -> MatrixMN:\n    if translation is None:\n        translation = np.array([0, 0, depth / 2 + 1])\n    model_matrix = np.matmul(\n        np.matmul(\n            translation_matrix(*translation),\n            rotation_matrix(x=x_rotation, y=y_rotation, z=z_rotation),\n        ),\n        scale_matrix(),\n    )\n    return tuple(linalg.inv(model_matrix).T.ravel())\n"
  },
  {
    "path": "manim/utils/parameter_parsing.py",
    "content": "from __future__ import annotations\n\nfrom collections.abc import Iterable\nfrom types import GeneratorType\nfrom typing import TypeVar\n\nT = TypeVar(\"T\")\n\n\ndef flatten_iterable_parameters(\n    args: Iterable[T | Iterable[T] | GeneratorType],\n) -> list[T]:\n    \"\"\"Flattens an iterable of parameters into a list of parameters.\n\n    Parameters\n    ----------\n    args\n        The iterable of parameters to flatten.\n        [(generator), [], (), ...]\n\n    Returns\n    -------\n    :class:`list`\n        The flattened list of parameters.\n    \"\"\"\n    flattened_parameters: list[T] = []\n    for arg in args:\n        if isinstance(arg, (Iterable, GeneratorType)):\n            flattened_parameters.extend(arg)\n        else:\n            flattened_parameters.append(arg)\n    return flattened_parameters\n"
  },
  {
    "path": "manim/utils/paths.py",
    "content": "\"\"\"Functions determining transformation paths between sets of points.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"straight_path\",\n    \"path_along_arc\",\n    \"clockwise_path\",\n    \"counterclockwise_path\",\n]\n\n\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\n\nfrom ..constants import OUT\nfrom ..utils.bezier import interpolate\nfrom ..utils.space_ops import normalize, rotation_matrix\n\nif TYPE_CHECKING:\n    from manim.typing import (\n        PathFuncType,\n        Point3D_Array,\n        Point3DLike_Array,\n        Vector3DLike,\n    )\n\n\nSTRAIGHT_PATH_THRESHOLD = 0.01\n\n\ndef straight_path() -> PathFuncType:\n    \"\"\"Simplest path function. Each point in a set goes in a straight path toward its destination.\n\n    Examples\n    --------\n\n    .. manim :: StraightPathExample\n\n        class StraightPathExample(Scene):\n            def construct(self):\n                colors = [RED, GREEN, BLUE]\n\n                starting_points = VGroup(\n                    *[\n                        Dot(LEFT + pos, color=color)\n                        for pos, color in zip([UP, DOWN, LEFT], colors)\n                    ]\n                )\n\n                finish_points = VGroup(\n                    *[\n                        Dot(RIGHT + pos, color=color)\n                        for pos, color in zip([ORIGIN, UP, DOWN], colors)\n                    ]\n                )\n\n                self.add(starting_points)\n                self.add(finish_points)\n                for dot in starting_points:\n                    self.add(TracedPath(dot.get_center, stroke_color=dot.get_color()))\n\n                self.wait()\n                self.play(\n                    Transform(\n                        starting_points,\n                        finish_points,\n                        path_func=utils.paths.straight_path(),\n                        run_time=2,\n                    )\n                )\n                self.wait()\n\n    \"\"\"\n    return interpolate\n\n\ndef path_along_circles(\n    arc_angle: float, circles_centers: Point3DLike_Array, axis: Vector3DLike = OUT\n) -> PathFuncType:\n    \"\"\"This function transforms each point by moving it roughly along a circle, each with its own specified center.\n\n    The path may be seen as each point smoothly changing its orbit from its starting position to its destination.\n\n    Parameters\n    ----------\n    arc_angle\n        The angle each point traverses around the quasicircle.\n    circles_centers\n        The centers of each point's quasicircle to rotate around.\n    axis\n        The axis of rotation.\n\n    Examples\n    --------\n\n    .. manim :: PathAlongCirclesExample\n\n        class PathAlongCirclesExample(Scene):\n            def construct(self):\n                colors = [RED, GREEN, BLUE]\n\n                starting_points = VGroup(\n                    *[\n                        Dot(LEFT + pos, color=color)\n                        for pos, color in zip([UP, DOWN, LEFT], colors)\n                    ]\n                )\n\n                finish_points = VGroup(\n                    *[\n                        Dot(RIGHT + pos, color=color)\n                        for pos, color in zip([ORIGIN, UP, DOWN], colors)\n                    ]\n                )\n\n                self.add(starting_points)\n                self.add(finish_points)\n                for dot in starting_points:\n                    self.add(TracedPath(dot.get_center, stroke_color=dot.get_color()))\n\n                circle_center = Dot(3 * LEFT)\n                self.add(circle_center)\n\n                self.wait()\n                self.play(\n                    Transform(\n                        starting_points,\n                        finish_points,\n                        path_func=utils.paths.path_along_circles(\n                            2 * PI, circle_center.get_center()\n                        ),\n                        run_time=3,\n                    )\n                )\n                self.wait()\n\n    \"\"\"\n    unit_axis = normalize(axis, fall_back=OUT)\n\n    def path(\n        start_points: Point3D_Array, end_points: Point3D_Array, alpha: float\n    ) -> Point3D_Array:\n        detransformed_end_points = circles_centers + np.dot(\n            end_points - circles_centers, rotation_matrix(-arc_angle, unit_axis).T\n        )\n        rot_matrix = rotation_matrix(alpha * arc_angle, unit_axis)\n        return circles_centers + np.dot(\n            interpolate(start_points, detransformed_end_points, alpha)\n            - circles_centers,\n            rot_matrix.T,\n        )\n\n    return path\n\n\ndef path_along_arc(arc_angle: float, axis: Vector3DLike = OUT) -> PathFuncType:\n    \"\"\"This function transforms each point by moving it along a circular arc.\n\n    Parameters\n    ----------\n    arc_angle\n        The angle each point traverses around a circular arc.\n    axis\n        The axis of rotation.\n\n    Examples\n    --------\n\n    .. manim :: PathAlongArcExample\n\n        class PathAlongArcExample(Scene):\n            def construct(self):\n                colors = [RED, GREEN, BLUE]\n\n                starting_points = VGroup(\n                    *[\n                        Dot(LEFT + pos, color=color)\n                        for pos, color in zip([UP, DOWN, LEFT], colors)\n                    ]\n                )\n\n                finish_points = VGroup(\n                    *[\n                        Dot(RIGHT + pos, color=color)\n                        for pos, color in zip([ORIGIN, UP, DOWN], colors)\n                    ]\n                )\n\n                self.add(starting_points)\n                self.add(finish_points)\n                for dot in starting_points:\n                    self.add(TracedPath(dot.get_center, stroke_color=dot.get_color()))\n\n                self.wait()\n                self.play(\n                    Transform(\n                        starting_points,\n                        finish_points,\n                        path_func=utils.paths.path_along_arc(TAU * 2 / 3),\n                        run_time=3,\n                    )\n                )\n                self.wait()\n\n    \"\"\"\n    if abs(arc_angle) < STRAIGHT_PATH_THRESHOLD:\n        return straight_path()\n    unit_axis = normalize(axis, fall_back=OUT)\n\n    def path(\n        start_points: Point3D_Array, end_points: Point3D_Array, alpha: float\n    ) -> Point3D_Array:\n        vects = end_points - start_points\n        centers = start_points + 0.5 * vects\n        if arc_angle != np.pi:\n            centers += np.cross(unit_axis, vects / 2.0) / np.tan(arc_angle / 2)\n        rot_matrix = rotation_matrix(alpha * arc_angle, unit_axis)\n        return centers + np.dot(start_points - centers, rot_matrix.T)\n\n    return path\n\n\ndef clockwise_path() -> PathFuncType:\n    \"\"\"This function transforms each point by moving clockwise around a half circle.\n\n    Examples\n    --------\n\n    .. manim :: ClockwisePathExample\n\n        class ClockwisePathExample(Scene):\n            def construct(self):\n                colors = [RED, GREEN, BLUE]\n\n                starting_points = VGroup(\n                    *[\n                        Dot(LEFT + pos, color=color)\n                        for pos, color in zip([UP, DOWN, LEFT], colors)\n                    ]\n                )\n\n                finish_points = VGroup(\n                    *[\n                        Dot(RIGHT + pos, color=color)\n                        for pos, color in zip([ORIGIN, UP, DOWN], colors)\n                    ]\n                )\n\n                self.add(starting_points)\n                self.add(finish_points)\n                for dot in starting_points:\n                    self.add(TracedPath(dot.get_center, stroke_color=dot.get_color()))\n\n                self.wait()\n                self.play(\n                    Transform(\n                        starting_points,\n                        finish_points,\n                        path_func=utils.paths.clockwise_path(),\n                        run_time=2,\n                    )\n                )\n                self.wait()\n\n    \"\"\"\n    return path_along_arc(-np.pi)\n\n\ndef counterclockwise_path() -> PathFuncType:\n    \"\"\"This function transforms each point by moving counterclockwise around a half circle.\n\n    Examples\n    --------\n\n    .. manim :: CounterclockwisePathExample\n\n        class CounterclockwisePathExample(Scene):\n            def construct(self):\n                colors = [RED, GREEN, BLUE]\n\n                starting_points = VGroup(\n                    *[\n                        Dot(LEFT + pos, color=color)\n                        for pos, color in zip([UP, DOWN, LEFT], colors)\n                    ]\n                )\n\n                finish_points = VGroup(\n                    *[\n                        Dot(RIGHT + pos, color=color)\n                        for pos, color in zip([ORIGIN, UP, DOWN], colors)\n                    ]\n                )\n\n                self.add(starting_points)\n                self.add(finish_points)\n                for dot in starting_points:\n                    self.add(TracedPath(dot.get_center, stroke_color=dot.get_color()))\n\n                self.wait()\n                self.play(\n                    Transform(\n                        starting_points,\n                        finish_points,\n                        path_func=utils.paths.counterclockwise_path(),\n                        run_time=2,\n                    )\n                )\n                self.wait()\n\n    \"\"\"\n    return path_along_arc(np.pi)\n\n\ndef spiral_path(angle: float, axis: Vector3DLike = OUT) -> PathFuncType:\n    \"\"\"This function transforms each point by moving along a spiral to its destination.\n\n    Parameters\n    ----------\n    angle\n        The angle each point traverses around a spiral.\n    axis\n        The axis of rotation.\n\n    Examples\n    --------\n\n    .. manim :: SpiralPathExample\n\n        class SpiralPathExample(Scene):\n            def construct(self):\n                colors = [RED, GREEN, BLUE]\n\n                starting_points = VGroup(\n                    *[\n                        Dot(LEFT + pos, color=color)\n                        for pos, color in zip([UP, DOWN, LEFT], colors)\n                    ]\n                )\n\n                finish_points = VGroup(\n                    *[\n                        Dot(RIGHT + pos, color=color)\n                        for pos, color in zip([ORIGIN, UP, DOWN], colors)\n                    ]\n                )\n\n                self.add(starting_points)\n                self.add(finish_points)\n                for dot in starting_points:\n                    self.add(TracedPath(dot.get_center, stroke_color=dot.get_color()))\n\n                self.wait()\n                self.play(\n                    Transform(\n                        starting_points,\n                        finish_points,\n                        path_func=utils.paths.spiral_path(2 * TAU),\n                        run_time=5,\n                    )\n                )\n                self.wait()\n\n    \"\"\"\n    if abs(angle) < STRAIGHT_PATH_THRESHOLD:\n        return straight_path()\n    unit_axis = normalize(axis, fall_back=OUT)\n\n    def path(\n        start_points: Point3D_Array, end_points: Point3D_Array, alpha: float\n    ) -> Point3D_Array:\n        rot_matrix = rotation_matrix((alpha - 1) * angle, unit_axis)\n        return start_points + alpha * np.dot(end_points - start_points, rot_matrix.T)\n\n    return path\n"
  },
  {
    "path": "manim/utils/polylabel.py",
    "content": "#!/usr/bin/env python\nfrom __future__ import annotations\n\nfrom queue import PriorityQueue\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\n\nif TYPE_CHECKING:\n    from collections.abc import Sequence\n\n    from manim.typing import (\n        Point2D,\n        Point2D_Array,\n        Point2DLike,\n        Point2DLike_Array,\n        Point3DLike_Array,\n    )\n\n\nclass Polygon:\n    \"\"\"\n    Initializes the Polygon with the given rings.\n\n    Parameters\n    ----------\n    rings\n        A sequence of points, where each sequence represents the rings of the polygon.\n        Typically, multiple rings indicate holes in the polygon.\n    \"\"\"\n\n    def __init__(self, rings: Sequence[Point2DLike_Array]) -> None:\n        np_rings: list[Point2D_Array] = [np.asarray(ring) for ring in rings]\n        # Flatten Array\n        csum = np.cumsum([ring.shape[0] for ring in np_rings])\n        self.array: Point2D_Array = np.concatenate(np_rings, axis=0)\n\n        # Compute Boundary\n        self.start: Point2D_Array = np.delete(self.array, csum - 1, axis=0)\n        self.stop: Point2D_Array = np.delete(self.array, csum % csum[-1], axis=0)\n        self.diff: Point2D_Array = np.delete(\n            np.diff(self.array, axis=0), csum[:-1] - 1, axis=0\n        )\n        self.norm: Point2D_Array = self.diff / np.einsum(\n            \"ij,ij->i\", self.diff, self.diff\n        ).reshape(-1, 1)\n\n        # Compute Centroid\n        x, y = self.start[:, 0], self.start[:, 1]\n        xr, yr = self.stop[:, 0], self.stop[:, 1]\n        self.area: float = 0.5 * (np.dot(x, yr) - np.dot(xr, y))\n        if self.area:\n            factor = x * yr - xr * y\n            cx = np.sum((x + xr) * factor) / (6.0 * self.area)\n            cy = np.sum((y + yr) * factor) / (6.0 * self.area)\n            self.centroid = np.array([cx, cy])\n\n    def compute_distance(self, point: Point2DLike) -> float:\n        \"\"\"Compute the minimum distance from a point to the polygon.\"\"\"\n        scalars = np.einsum(\"ij,ij->i\", self.norm, point - self.start)\n        clips = np.clip(scalars, 0, 1).reshape(-1, 1)\n        d: float = np.min(\n            np.linalg.norm(self.start + self.diff * clips - point, axis=1)\n        )\n        return d if self.inside(point) else -d\n\n    def _is_point_on_segment(\n        self,\n        x_point: float,\n        y_point: float,\n        x0: float,\n        y0: float,\n        x1: float,\n        y1: float,\n    ) -> bool:\n        \"\"\"\n        Check if a point is on the segment.\n\n        The segment is defined by (x0, y0) to (x1, y1).\n        \"\"\"\n        if min(x0, x1) <= x_point <= max(x0, x1) and min(y0, y1) <= y_point <= max(\n            y0, y1\n        ):\n            dx = x1 - x0\n            dy = y1 - y0\n            cross = dx * (y_point - y0) - dy * (x_point - x0)\n            return bool(np.isclose(cross, 0.0))\n        return False\n\n    def _ray_crosses_segment(\n        self,\n        x_point: float,\n        y_point: float,\n        x0: float,\n        y0: float,\n        x1: float,\n        y1: float,\n    ) -> bool:\n        \"\"\"\n        Check if a horizontal ray to the right from point (x_point, y_point) crosses the segment.\n\n        The segment is defined by (x0, y0) to (x1, y1).\n        \"\"\"\n        if (y0 > y_point) != (y1 > y_point):\n            slope = (x1 - x0) / (y1 - y0)\n            x_intersect = slope * (y_point - y0) + x0\n            return bool(x_point < x_intersect)\n        return False\n\n    def inside(self, point: Point2DLike) -> bool:\n        \"\"\"\n        Check if a point is inside the polygon.\n\n        Uses ray casting algorithm and checks boundary points consistently.\n        \"\"\"\n        point_x, point_y = point\n        start_x, start_y = self.start[:, 0], self.start[:, 1]\n        stop_x, stop_y = self.stop[:, 0], self.stop[:, 1]\n        segment_count = len(start_x)\n\n        for i in range(segment_count):\n            if self._is_point_on_segment(\n                point_x,\n                point_y,\n                start_x[i],\n                start_y[i],\n                stop_x[i],\n                stop_y[i],\n            ):\n                return True\n\n        crossings = 0\n        for i in range(segment_count):\n            if self._ray_crosses_segment(\n                point_x,\n                point_y,\n                start_x[i],\n                start_y[i],\n                stop_x[i],\n                stop_y[i],\n            ):\n                crossings += 1\n\n        return crossings % 2 == 1\n\n\nclass Cell:\n    \"\"\"\n    A square in a mesh covering the :class:`~.Polygon` passed as an argument.\n\n    Parameters\n    ----------\n    c\n        Center coordinates of the Cell.\n    h\n        Half-Size of the Cell.\n    polygon\n        :class:`~.Polygon` object for which the distance is computed.\n    \"\"\"\n\n    def __init__(self, c: Point2DLike, h: float, polygon: Polygon) -> None:\n        self.c: Point2D = np.asarray(c)\n        self.h = h\n        self.d = polygon.compute_distance(self.c)\n        self.p = self.d + self.h * np.sqrt(2)\n\n    def __lt__(self, other: Cell) -> bool:\n        return self.d < other.d\n\n    def __gt__(self, other: Cell) -> bool:\n        return self.d > other.d\n\n    def __le__(self, other: Cell) -> bool:\n        return self.d <= other.d\n\n    def __ge__(self, other: Cell) -> bool:\n        return self.d >= other.d\n\n\ndef polylabel(rings: Sequence[Point3DLike_Array], precision: float = 0.01) -> Cell:\n    \"\"\"\n    Finds the pole of inaccessibility (the point that is farthest from the edges of the polygon)\n    using an iterative grid-based approach.\n\n    Parameters\n    ----------\n    rings\n        A list of lists, where each list is a sequence of points representing the rings of the polygon.\n        Typically, multiple rings indicate holes in the polygon.\n    precision\n        The precision of the result (default is 0.01).\n\n    Returns\n    -------\n    Cell\n        A Cell containing the pole of inaccessibility to a given precision.\n    \"\"\"\n    # Precompute Polygon Data\n    np_rings: list[Point2D_Array] = [np.asarray(ring)[:, :2] for ring in rings]\n    polygon = Polygon(np_rings)\n\n    # Bounding Box\n    mins = np.min(polygon.array, axis=0)\n    maxs = np.max(polygon.array, axis=0)\n    dims = maxs - mins\n    s = np.min(dims)\n    h = s / 2.0\n\n    # Initial Grid\n    queue: PriorityQueue[Cell] = PriorityQueue()\n    xv, yv = np.meshgrid(np.arange(mins[0], maxs[0], s), np.arange(mins[1], maxs[1], s))\n    for corner in np.vstack([xv.ravel(), yv.ravel()]).T:\n        queue.put(Cell(corner + h, h, polygon))\n\n    # Initial Guess\n    best = Cell(polygon.centroid, 0, polygon)\n    bbox = Cell(mins + (dims / 2), 0, polygon)\n    if bbox.d > best.d:\n        best = bbox\n\n    # While there are cells to consider...\n    directions = np.array([[-1, -1], [1, -1], [-1, 1], [1, 1]])\n    while not queue.empty():\n        cell = queue.get()\n        if cell > best:\n            best = cell\n        # If a cell is promising, subdivide!\n        if cell.p - best.d > precision:\n            h = cell.h / 2.0\n            offsets = cell.c + directions * h\n            queue.put(Cell(offsets[0], h, polygon))\n            queue.put(Cell(offsets[1], h, polygon))\n            queue.put(Cell(offsets[2], h, polygon))\n            queue.put(Cell(offsets[3], h, polygon))\n    return best\n"
  },
  {
    "path": "manim/utils/qhull.py",
    "content": "#!/usr/bin/env python\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\n\nif TYPE_CHECKING:\n    from manim.typing import PointND, PointND_Array\n\n\nclass QuickHullPoint:\n    def __init__(self, coordinates: PointND_Array) -> None:\n        self.coordinates = coordinates\n\n    def __hash__(self) -> int:\n        return hash(self.coordinates.tobytes())\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, QuickHullPoint):\n            raise ValueError\n        are_coordinates_equal: bool = np.array_equal(\n            self.coordinates, other.coordinates\n        )\n        return are_coordinates_equal\n\n\nclass SubFacet:\n    def __init__(self, coordinates: PointND_Array) -> None:\n        self.coordinates = coordinates\n        self.points = frozenset(QuickHullPoint(c) for c in coordinates)\n\n    def __hash__(self) -> int:\n        return hash(self.points)\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, SubFacet):\n            raise ValueError\n        return self.points == other.points\n\n\nclass Facet:\n    def __init__(self, coordinates: PointND_Array, internal: PointND) -> None:\n        self.coordinates = coordinates\n        self.center: PointND = np.mean(coordinates, axis=0)\n        self.normal = self.compute_normal(internal)\n        self.subfacets = frozenset(\n            SubFacet(np.delete(self.coordinates, i, axis=0))\n            for i in range(self.coordinates.shape[0])\n        )\n\n    def compute_normal(self, internal: PointND) -> PointND:\n        centered = self.coordinates - self.center\n        _, _, vh = np.linalg.svd(centered)\n        normal: PointND = vh[-1, :]\n        normal /= np.linalg.norm(normal)\n\n        # If the normal points towards the internal point, flip it!\n        if np.dot(normal, self.center - internal) < 0:\n            normal *= -1\n\n        return normal\n\n    def __hash__(self) -> int:\n        return hash(self.subfacets)\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, Facet):\n            raise ValueError\n        return self.subfacets == other.subfacets\n\n\nclass Horizon:\n    def __init__(self) -> None:\n        self.facets: set[Facet] = set()\n        self.boundary: list[SubFacet] = []\n\n\nclass QuickHull:\n    \"\"\"\n    QuickHull algorithm for constructing a convex hull from a set of points.\n\n    Parameters\n    ----------\n    tolerance\n        A tolerance threshold for determining when points lie on the convex hull (default is 1e-5).\n\n    Attributes\n    ----------\n    facets\n        List of facets considered.\n    removed\n        Set of internal facets that have been removed from the hull during the construction process.\n    outside\n        Dictionary mapping each facet to its outside points and eye point.\n    neighbors\n        Mapping of subfacets to their neighboring facets. Each subfacet links precisely two neighbors.\n    unclaimed\n        Points that have not yet been classified as inside or outside the current hull.\n    internal\n        An internal point (i.e., the center of the initial simplex) used as a reference during hull construction.\n    tolerance\n        The tolerance used to determine if points are considered outside the current hull.\n    \"\"\"\n\n    def __init__(self, tolerance: float = 1e-5) -> None:\n        self.facets: list[Facet] = []\n        self.removed: set[Facet] = set()\n        self.outside: dict[Facet, tuple[PointND_Array | None, PointND | None]] = {}\n        self.neighbors: dict[SubFacet, set[Facet]] = {}\n        self.unclaimed: PointND_Array | None = None\n        self.internal: PointND | None = None\n        self.tolerance = tolerance\n\n    def initialize(self, points: PointND_Array) -> None:\n        # Sample Points\n        rng = np.random.default_rng()\n        simplex = points[\n            rng.choice(points.shape[0], points.shape[1] + 1, replace=False)\n        ]\n        self.unclaimed = points\n        new_internal: PointND = np.mean(simplex, axis=0)\n        self.internal = new_internal\n\n        # Build Simplex\n        for c in range(simplex.shape[0]):\n            facet = Facet(np.delete(simplex, c, axis=0), internal=new_internal)\n            self.classify(facet)\n            self.facets.append(facet)\n\n        # Attach Neighbors\n        for f in self.facets:\n            for sf in f.subfacets:\n                self.neighbors.setdefault(sf, set()).add(f)\n\n    def classify(self, facet: Facet) -> None:\n        assert self.unclaimed is not None, (\n            \"Call .initialize() before using .classify().\"\n        )\n\n        if not self.unclaimed.size:\n            self.outside[facet] = (None, None)\n            return\n\n        # Compute Projections\n        projections = (self.unclaimed - facet.center) @ facet.normal\n        arg = np.argmax(projections)\n        mask = projections > self.tolerance\n\n        # Identify Eye and Outside Set\n        eye = self.unclaimed[arg] if projections[arg] > self.tolerance else None\n        outside = self.unclaimed[mask]\n        self.outside[facet] = (outside, eye)\n        self.unclaimed = self.unclaimed[~mask]\n\n    def compute_horizon(self, eye: PointND, start_facet: Facet) -> Horizon:\n        horizon = Horizon()\n        self._recursive_horizon(eye, start_facet, horizon)\n        return horizon\n\n    def _recursive_horizon(self, eye: PointND, facet: Facet, horizon: Horizon) -> bool:\n        visible = np.dot(facet.normal, eye - facet.center) > 0\n        if not visible:\n            return False\n\n        # If the eye is visible from the facet:\n        # Label the facet as visible and cross each edge\n        horizon.facets.add(facet)\n        for subfacet in facet.subfacets:\n            neighbor = (self.neighbors[subfacet] - {facet}).pop()\n            # If the neighbor is not visible, then the edge shared must be on the boundary\n            if neighbor not in horizon.facets and not self._recursive_horizon(\n                eye, neighbor, horizon\n            ):\n                horizon.boundary.append(subfacet)\n        return True\n\n    def build(self, points: PointND_Array) -> None:\n        num, dim = points.shape\n        if (dim == 0) or (num < dim + 1):\n            raise ValueError(\"Not enough points supplied to build Convex Hull!\")\n        if dim == 1:\n            raise ValueError(\"The Convex Hull of 1D data is its min-max!\")\n\n        self.initialize(points)\n\n        # This helps the type checker.\n        assert self.unclaimed is not None\n        assert self.internal is not None\n\n        while True:\n            updated = False\n            for facet in self.facets:\n                if facet in self.removed:\n                    continue\n                outside, eye = self.outside[facet]\n                if eye is not None:\n                    updated = True\n                    horizon = self.compute_horizon(eye, facet)\n                    for f in horizon.facets:\n                        points_to_append = self.outside[f][0]\n                        # TODO: is this always true?\n                        assert points_to_append is not None\n                        self.unclaimed = np.vstack((self.unclaimed, points_to_append))\n                        self.removed.add(f)\n                        for sf in f.subfacets:\n                            self.neighbors[sf].discard(f)\n                            if self.neighbors[sf] == set():\n                                del self.neighbors[sf]\n                    for sf in horizon.boundary:\n                        nf = Facet(\n                            np.vstack((sf.coordinates, eye)), internal=self.internal\n                        )\n                        self.classify(nf)\n                        self.facets.append(nf)\n                        for nsf in nf.subfacets:\n                            self.neighbors.setdefault(nsf, set()).add(nf)\n            if not updated:\n                break\n"
  },
  {
    "path": "manim/utils/rate_functions.py",
    "content": "\"\"\"A selection of rate functions, i.e., *speed curves* for animations.\nPlease find a standard list at https://easings.net/. Here is a picture\nfor the non-standard ones\n\n.. manim:: RateFuncExample\n    :save_last_frame:\n\n    class RateFuncExample(Scene):\n        def construct(self):\n            x = VGroup()\n            for k, v in rate_functions.__dict__.items():\n                if \"function\" in str(v):\n                    if (\n                        not k.startswith(\"__\")\n                        and not k.startswith(\"sqrt\")\n                        and not k.startswith(\"bezier\")\n                    ):\n                        try:\n                            rate_func = v\n                            plot = (\n                                ParametricFunction(\n                                    lambda x: [x, rate_func(x), 0],\n                                    t_range=[0, 1, .01],\n                                    use_smoothing=False,\n                                    color=YELLOW,\n                                )\n                                .stretch_to_fit_width(1.5)\n                                .stretch_to_fit_height(1)\n                            )\n                            plot_bg = SurroundingRectangle(plot).set_color(WHITE)\n                            plot_title = (\n                                Text(rate_func.__name__, weight=BOLD)\n                                .scale(0.5)\n                                .next_to(plot_bg, UP, buff=0.1)\n                            )\n                            x.add(VGroup(plot_bg, plot, plot_title))\n                        except: # because functions `not_quite_there`, `function squish_rate_func` are not working.\n                            pass\n            x.arrange_in_grid(cols=8)\n            x.height = config.frame_height\n            x.width = config.frame_width\n            x.move_to(ORIGIN).scale(0.95)\n            self.add(x)\n\n\nThere are primarily 3 kinds of standard easing functions:\n\n#. Ease In - The animation has a smooth start.\n#. Ease Out - The animation has a smooth end.\n#. Ease In Out - The animation has a smooth start as well as smooth end.\n\n.. note:: The standard functions are not exported, so to use them you do something like this:\n    rate_func=rate_functions.ease_in_sine\n    On the other hand, the non-standard functions, which are used more commonly, are exported and can be used directly.\n\n.. manim:: RateFunctions1Example\n\n    class RateFunctions1Example(Scene):\n        def construct(self):\n            line1 = Line(3*LEFT, 3*RIGHT).shift(UP).set_color(RED)\n            line2 = Line(3*LEFT, 3*RIGHT).set_color(GREEN)\n            line3 = Line(3*LEFT, 3*RIGHT).shift(DOWN).set_color(BLUE)\n\n            dot1 = Dot().move_to(line1.get_left())\n            dot2 = Dot().move_to(line2.get_left())\n            dot3 = Dot().move_to(line3.get_left())\n\n            label1 = Tex(\"Ease In\").next_to(line1, RIGHT)\n            label2 = Tex(\"Ease out\").next_to(line2, RIGHT)\n            label3 = Tex(\"Ease In Out\").next_to(line3, RIGHT)\n\n            self.play(\n                FadeIn(VGroup(line1, line2, line3)),\n                FadeIn(VGroup(dot1, dot2, dot3)),\n                Write(VGroup(label1, label2, label3)),\n            )\n            self.play(\n                MoveAlongPath(dot1, line1, rate_func=rate_functions.ease_in_sine),\n                MoveAlongPath(dot2, line2, rate_func=rate_functions.ease_out_sine),\n                MoveAlongPath(dot3, line3, rate_func=rate_functions.ease_in_out_sine),\n                run_time=7\n            )\n            self.wait()\n\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"linear\",\n    \"smooth\",\n    \"smoothstep\",\n    \"smootherstep\",\n    \"smoothererstep\",\n    \"rush_into\",\n    \"rush_from\",\n    \"slow_into\",\n    \"double_smooth\",\n    \"there_and_back\",\n    \"there_and_back_with_pause\",\n    \"running_start\",\n    \"not_quite_there\",\n    \"wiggle\",\n    \"squish_rate_func\",\n    \"lingering\",\n    \"exponential_decay\",\n]\n\nfrom functools import wraps\nfrom math import sqrt\nfrom typing import Any, Protocol\n\nimport numpy as np\n\nfrom manim.utils.simple_functions import sigmoid\n\n\n# TODO: rewrite this to use ParamSpec when Python 3.9 is out of life\nclass RateFunction(Protocol):\n    def __call__(self, t: float, *args: Any, **kwargs: Any) -> float: ...\n\n\n# This is a decorator that makes sure any function it's used on will\n# return 0 if t<0 and 1 if t>1.\ndef unit_interval(function: RateFunction) -> RateFunction:\n    @wraps(function)\n    def wrapper(t: float, *args: Any, **kwargs: Any) -> float:\n        if 0 <= t <= 1:\n            return function(t, *args, **kwargs)\n        elif t < 0:\n            return 0\n        else:\n            return 1\n\n    return wrapper\n\n\n# This is a decorator that makes sure any function it's used on will\n# return 0 if t<0 or t>1.\ndef zero(function: RateFunction) -> RateFunction:\n    @wraps(function)\n    def wrapper(t: float, *args: Any, **kwargs: Any) -> float:\n        if 0 <= t <= 1:\n            return function(t, *args, **kwargs)\n        else:\n            return 0\n\n    return wrapper\n\n\n@unit_interval\ndef linear(t: float) -> float:\n    return t\n\n\n@unit_interval\ndef smooth(t: float, inflection: float = 10.0) -> float:\n    error = sigmoid(-inflection / 2)\n    return min(\n        max((sigmoid(inflection * (t - 0.5)) - error) / (1 - 2 * error), 0),\n        1,\n    )\n\n\n@unit_interval\ndef smoothstep(t: float) -> float:\n    \"\"\"Implementation of the 1st order SmoothStep sigmoid function.\n    The 1st derivative (speed) is zero at the endpoints.\n    https://en.wikipedia.org/wiki/Smoothstep\n    \"\"\"\n    return 3 * t**2 - 2 * t**3\n\n\n@unit_interval\ndef smootherstep(t: float) -> float:\n    \"\"\"Implementation of the 2nd order SmoothStep sigmoid function.\n    The 1st and 2nd derivatives (speed and acceleration) are zero at the endpoints.\n    https://en.wikipedia.org/wiki/Smoothstep\n    \"\"\"\n    return 6 * t**5 - 15 * t**4 + 10 * t**3\n\n\n@unit_interval\ndef smoothererstep(t: float) -> float:\n    \"\"\"Implementation of the 3rd order SmoothStep sigmoid function.\n    The 1st, 2nd and 3rd derivatives (speed, acceleration and jerk) are zero at the endpoints.\n    https://en.wikipedia.org/wiki/Smoothstep\n    \"\"\"\n    return 35 * t**4 - 84 * t**5 + 70 * t**6 - 20 * t**7\n\n\n@unit_interval\ndef rush_into(t: float, inflection: float = 10.0) -> float:\n    return 2 * smooth(t / 2.0, inflection)\n\n\n@unit_interval\ndef rush_from(t: float, inflection: float = 10.0) -> float:\n    return 2 * smooth(t / 2.0 + 0.5, inflection) - 1\n\n\n@unit_interval\ndef slow_into(t: float) -> float:\n    val: float = np.sqrt(1 - (1 - t) * (1 - t))\n    return val\n\n\n@unit_interval\ndef double_smooth(t: float) -> float:\n    if t < 0.5:\n        return 0.5 * smooth(2 * t)\n    else:\n        return 0.5 * (1 + smooth(2 * t - 1))\n\n\n@zero\ndef there_and_back(t: float, inflection: float = 10.0) -> float:\n    new_t = 2 * t if t < 0.5 else 2 * (1 - t)\n    return smooth(new_t, inflection)\n\n\n@zero\ndef there_and_back_with_pause(t: float, pause_ratio: float = 1.0 / 3) -> float:\n    a = 2.0 / (1.0 - pause_ratio)\n    if t < 0.5 - pause_ratio / 2:\n        return smooth(a * t)\n    elif t < 0.5 + pause_ratio / 2:\n        return 1\n    else:\n        return smooth(a - a * t)\n\n\n@unit_interval\ndef running_start(\n    t: float,\n    pull_factor: float = -0.5,\n) -> float:\n    t2 = t * t\n    t3 = t2 * t\n    t4 = t3 * t\n    t5 = t4 * t\n    t6 = t5 * t\n    mt = 1 - t\n    mt2 = mt * mt\n    mt3 = mt2 * mt\n    mt4 = mt3 * mt\n\n    # This is equivalent to creating a Bézier with [0, 0, pull_factor, pull_factor, 1, 1, 1]\n    # and evaluating it at t.\n    return (\n        15 * t2 * mt4 * pull_factor\n        + 20 * t3 * mt3 * pull_factor\n        + 15 * t4 * mt2\n        + 6 * t5 * mt\n        + t6\n    )\n\n\ndef not_quite_there(\n    func: RateFunction = smooth,\n    proportion: float = 0.7,\n) -> RateFunction:\n    def result(t: float, *args: Any, **kwargs: Any) -> float:\n        return proportion * func(t, *args, **kwargs)\n\n    return result\n\n\n@zero\ndef wiggle(t: float, wiggles: float = 2) -> float:\n    val: float = np.sin(wiggles * np.pi * t)\n    return there_and_back(t) * val\n\n\ndef squish_rate_func(\n    func: RateFunction,\n    a: float = 0.4,\n    b: float = 0.6,\n) -> RateFunction:\n    def result(t: float, *args: Any, **kwargs: Any) -> float:\n        if a == b:\n            return a\n\n        if t < a:\n            new_t = 0.0\n        elif t > b:\n            new_t = 1.0\n        else:\n            new_t = (t - a) / (b - a)\n        return func(new_t, *args, **kwargs)\n\n    return result\n\n\n# Stylistically, should this take parameters (with default values)?\n# Ultimately, the functionality is entirely subsumed by squish_rate_func,\n# but it may be useful to have a nice name for with nice default params for\n# \"lingering\", different from squish_rate_func's default params\n\n\n@unit_interval\ndef lingering(t: float) -> float:\n    def identity(t: float) -> float:\n        return t\n\n    # TODO: Isn't this just 0.8 * t?\n    return squish_rate_func(identity, 0, 0.8)(t)\n\n\n@unit_interval\ndef exponential_decay(t: float, half_life: float = 0.1) -> float:\n    # The half-life should be rather small to minimize\n    # the cut-off error at the end\n    val: float = 1 - np.exp(-t / half_life)\n    return val\n\n\n@unit_interval\ndef ease_in_sine(t: float) -> float:\n    val: float = 1 - np.cos((t * np.pi) / 2)\n    return val\n\n\n@unit_interval\ndef ease_out_sine(t: float) -> float:\n    val: float = np.sin((t * np.pi) / 2)\n    return val\n\n\n@unit_interval\ndef ease_in_out_sine(t: float) -> float:\n    val: float = -(np.cos(np.pi * t) - 1) / 2\n    return val\n\n\n@unit_interval\ndef ease_in_quad(t: float) -> float:\n    return t * t\n\n\n@unit_interval\ndef ease_out_quad(t: float) -> float:\n    return 1 - (1 - t) * (1 - t)\n\n\n@unit_interval\ndef ease_in_out_quad(t: float) -> float:\n    return 2 * t * t if t < 0.5 else 1 - pow(-2 * t + 2, 2) / 2\n\n\n@unit_interval\ndef ease_in_cubic(t: float) -> float:\n    return t * t * t\n\n\n@unit_interval\ndef ease_out_cubic(t: float) -> float:\n    return 1 - pow(1 - t, 3)\n\n\n@unit_interval\ndef ease_in_out_cubic(t: float) -> float:\n    return 4 * t * t * t if t < 0.5 else 1 - pow(-2 * t + 2, 3) / 2\n\n\n@unit_interval\ndef ease_in_quart(t: float) -> float:\n    return t * t * t * t\n\n\n@unit_interval\ndef ease_out_quart(t: float) -> float:\n    return 1 - pow(1 - t, 4)\n\n\n@unit_interval\ndef ease_in_out_quart(t: float) -> float:\n    return 8 * t * t * t * t if t < 0.5 else 1 - pow(-2 * t + 2, 4) / 2\n\n\n@unit_interval\ndef ease_in_quint(t: float) -> float:\n    return t * t * t * t * t\n\n\n@unit_interval\ndef ease_out_quint(t: float) -> float:\n    return 1 - pow(1 - t, 5)\n\n\n@unit_interval\ndef ease_in_out_quint(t: float) -> float:\n    return 16 * t * t * t * t * t if t < 0.5 else 1 - pow(-2 * t + 2, 5) / 2\n\n\n@unit_interval\ndef ease_in_expo(t: float) -> float:\n    return 0 if t == 0 else pow(2, 10 * t - 10)\n\n\n@unit_interval\ndef ease_out_expo(t: float) -> float:\n    return 1 if t == 1 else 1 - pow(2, -10 * t)\n\n\n@unit_interval\ndef ease_in_out_expo(t: float) -> float:\n    if t == 0:\n        return 0\n    elif t == 1:\n        return 1\n    elif t < 0.5:\n        return pow(2, 20 * t - 10) / 2\n    else:\n        return (2 - pow(2, -20 * t + 10)) / 2\n\n\n@unit_interval\ndef ease_in_circ(t: float) -> float:\n    return 1 - sqrt(1 - pow(t, 2))\n\n\n@unit_interval\ndef ease_out_circ(t: float) -> float:\n    return sqrt(1 - pow(t - 1, 2))\n\n\n@unit_interval\ndef ease_in_out_circ(t: float) -> float:\n    return (\n        (1 - sqrt(1 - pow(2 * t, 2))) / 2\n        if t < 0.5\n        else (sqrt(1 - pow(-2 * t + 2, 2)) + 1) / 2\n    )\n\n\n@unit_interval\ndef ease_in_back(t: float) -> float:\n    c1 = 1.70158\n    c3 = c1 + 1\n    return c3 * t * t * t - c1 * t * t\n\n\n@unit_interval\ndef ease_out_back(t: float) -> float:\n    c1 = 1.70158\n    c3 = c1 + 1\n    return 1 + c3 * pow(t - 1, 3) + c1 * pow(t - 1, 2)\n\n\n@unit_interval\ndef ease_in_out_back(t: float) -> float:\n    c1 = 1.70158\n    c2 = c1 * 1.525\n    return (\n        (pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2\n        if t < 0.5\n        else (pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2\n    )\n\n\n@unit_interval\ndef ease_in_elastic(t: float) -> float:\n    c4 = (2 * np.pi) / 3\n    if t == 0:\n        return 0\n    elif t == 1:\n        return 1\n    else:\n        val: float = -pow(2, 10 * t - 10) * np.sin((t * 10 - 10.75) * c4)\n        return val\n\n\n@unit_interval\ndef ease_out_elastic(t: float) -> float:\n    c4 = (2 * np.pi) / 3\n    if t == 0:\n        return 0\n    elif t == 1:\n        return 1\n    else:\n        val: float = pow(2, -10 * t) * np.sin((t * 10 - 0.75) * c4) + 1\n        return val\n\n\n@unit_interval\ndef ease_in_out_elastic(t: float) -> float:\n    c5 = (2 * np.pi) / 4.5\n    if t == 0:\n        return 0\n    elif t == 1:\n        return 1\n    elif t < 0.5:\n        val: float = -(pow(2, 20 * t - 10) * np.sin((20 * t - 11.125) * c5)) / 2\n        return val\n    else:\n        val = (pow(2, -20 * t + 10) * np.sin((20 * t - 11.125) * c5)) / 2 + 1\n        return val\n\n\n@unit_interval\ndef ease_in_bounce(t: float) -> float:\n    return 1 - ease_out_bounce(1 - t)\n\n\n@unit_interval\ndef ease_out_bounce(t: float) -> float:\n    n1 = 7.5625\n    d1 = 2.75\n\n    if t < 1 / d1:\n        return n1 * t * t\n    elif t < 2 / d1:\n        return n1 * (t - 1.5 / d1) * (t - 1.5 / d1) + 0.75\n    elif t < 2.5 / d1:\n        return n1 * (t - 2.25 / d1) * (t - 2.25 / d1) + 0.9375\n    else:\n        return n1 * (t - 2.625 / d1) * (t - 2.625 / d1) + 0.984375\n\n\n@unit_interval\ndef ease_in_out_bounce(t: float) -> float:\n    if t < 0.5:\n        return (1 - ease_out_bounce(1 - 2 * t)) / 2\n    else:\n        return (1 + ease_out_bounce(2 * t - 1)) / 2\n"
  },
  {
    "path": "manim/utils/simple_functions.py",
    "content": "\"\"\"A collection of simple functions.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"binary_search\",\n    \"choose\",\n    \"clip\",\n    \"sigmoid\",\n]\n\nimport math\nfrom collections.abc import Callable\nfrom functools import lru_cache\nfrom typing import Any, Protocol, TypeVar\n\nimport numpy as np\n\n\ndef binary_search(\n    function: Callable[[float], float],\n    target: float,\n    lower_bound: float,\n    upper_bound: float,\n    tolerance: float = 1e-4,\n) -> float | None:\n    \"\"\"Searches for a value in a range by repeatedly dividing the range in half.\n\n    To be more precise, performs numerical binary search to determine the\n    input to ``function``, between the bounds given, that outputs ``target``\n    to within ``tolerance`` (default of 0.0001).\n    Returns ``None`` if no input can be found within the bounds.\n\n    Examples\n    --------\n\n    Consider the polynomial :math:`x^2 + 3x + 1` where we search for\n    a target value of :math:`11`. An exact solution is :math:`x = 2`.\n\n    ::\n\n        >>> solution = binary_search(lambda x: x**2 + 3*x + 1, 11, 0, 5)\n        >>> bool(abs(solution - 2) < 1e-4)\n        True\n        >>> solution = binary_search(lambda x: x**2 + 3*x + 1, 11, 0, 5, tolerance=0.01)\n        >>> bool(abs(solution - 2) < 0.01)\n        True\n\n    Searching in the interval :math:`[0, 5]` for a target value of :math:`71`\n    does not yield a solution::\n\n        >>> binary_search(lambda x: x**2 + 3*x + 1, 71, 0, 5) is None\n        True\n    \"\"\"\n    lh = lower_bound\n    rh = upper_bound\n    mh: float = np.mean(np.array([lh, rh]))\n    while abs(rh - lh) > tolerance:\n        mh = np.mean(np.array([lh, rh]))\n        lx, mx, rx = (function(h) for h in (lh, mh, rh))\n        if lx == target:\n            return lh\n        if rx == target:\n            return rh\n\n        if lx <= target <= rx:\n            if mx > target:\n                rh = mh\n            else:\n                lh = mh\n        elif lx > target > rx:\n            lh, rh = rh, lh\n        else:\n            return None\n\n    return mh\n\n\n@lru_cache(maxsize=10)\ndef choose(n: int, k: int) -> int:\n    r\"\"\"The binomial coefficient n choose k.\n\n    :math:`\\binom{n}{k}` describes the number of possible choices of\n    :math:`k` elements from a set of :math:`n` elements.\n\n    References\n    ----------\n    - https://en.wikipedia.org/wiki/Combination\n    - https://docs.python.org/3/library/math.html#math.comb\n    \"\"\"\n    value: int = math.comb(n, k)\n    return value\n\n\nclass Comparable(Protocol):\n    def __lt__(self, other: Any) -> bool: ...\n\n    def __gt__(self, other: Any) -> bool: ...\n\n\nComparableT = TypeVar(\"ComparableT\", bound=Comparable)\n\n\ndef clip(a: ComparableT, min_a: ComparableT, max_a: ComparableT) -> ComparableT:\n    \"\"\"Clips ``a`` to the interval [``min_a``, ``max_a``].\n\n    Accepts any comparable objects (i.e. those that support <, >).\n    Returns ``a`` if it is between ``min_a`` and ``max_a``.\n    Otherwise, whichever of ``min_a`` and ``max_a`` is closest.\n\n    Examples\n    --------\n    ::\n\n        >>> clip(15, 11, 20)\n        15\n        >>> clip('a', 'h', 'k')\n        'h'\n    \"\"\"\n    if a < min_a:\n        return min_a\n    elif a > max_a:\n        return max_a\n    return a\n\n\ndef sigmoid(x: float) -> float:\n    r\"\"\"Returns the output of the logistic function.\n\n    The logistic function, a common example of a sigmoid function, is defined\n    as :math:`\\frac{1}{1 + e^{-x}}`.\n\n    References\n    ----------\n    - https://en.wikipedia.org/wiki/Sigmoid_function\n    - https://en.wikipedia.org/wiki/Logistic_function\n    \"\"\"\n    value: float = 1.0 / (1 + np.exp(-x))\n    return value\n"
  },
  {
    "path": "manim/utils/sounds.py",
    "content": "\"\"\"Sound-related utility functions.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"get_full_sound_file_path\",\n]\n\nfrom typing import TYPE_CHECKING\n\nfrom .. import config\nfrom ..utils.file_ops import seek_full_path_from_defaults\n\nif TYPE_CHECKING:\n    from pathlib import Path\n\n    from manim.typing import StrPath\n\n\n# Still in use by add_sound() function in scene_file_writer.py\ndef get_full_sound_file_path(sound_file_name: StrPath) -> Path:\n    return seek_full_path_from_defaults(\n        sound_file_name,\n        default_dir=config.get_dir(\"assets_dir\"),\n        extensions=[\".wav\", \".mp3\"],\n    )\n"
  },
  {
    "path": "manim/utils/space_ops.py",
    "content": "\"\"\"Utility functions for two- and three-dimensional vectors.\"\"\"\n\nfrom __future__ import annotations\n\nimport itertools as it\nfrom collections.abc import Callable, Sequence\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\nfrom mapbox_earcut import triangulate_float32 as earcut\nfrom scipy.spatial.transform import Rotation\n\nfrom manim.constants import DOWN, OUT, PI, RIGHT, TAU, UP\nfrom manim.utils.iterables import adjacent_pairs\n\nif TYPE_CHECKING:\n    import numpy.typing as npt\n\n    from manim.typing import (\n        ManimFloat,\n        MatrixMN,\n        Point2D_Array,\n        Point3D,\n        Point3DLike,\n        Point3DLike_Array,\n        PointND,\n        PointNDLike_Array,\n        Vector2D,\n        Vector2D_Array,\n        Vector3D,\n        Vector3DLike,\n        Vector3DLike_Array,\n    )\n\n__all__ = [\n    \"quaternion_mult\",\n    \"quaternion_from_angle_axis\",\n    \"angle_axis_from_quaternion\",\n    \"quaternion_conjugate\",\n    \"rotate_vector\",\n    \"thick_diagonal\",\n    \"rotation_matrix\",\n    \"rotation_about_z\",\n    \"z_to_vector\",\n    \"angle_of_vector\",\n    \"angle_between_vectors\",\n    \"normalize\",\n    \"get_unit_normal\",\n    \"compass_directions\",\n    \"regular_vertices\",\n    \"complex_to_R3\",\n    \"R3_to_complex\",\n    \"complex_func_to_R3_func\",\n    \"center_of_mass\",\n    \"midpoint\",\n    \"find_intersection\",\n    \"line_intersection\",\n    \"get_winding_number\",\n    \"shoelace\",\n    \"shoelace_direction\",\n    \"cross2d\",\n    \"earclip_triangulation\",\n    \"cartesian_to_spherical\",\n    \"spherical_to_cartesian\",\n    \"perpendicular_bisector\",\n]\n\n\ndef norm_squared(v: float) -> float:\n    val: float = np.dot(v, v)\n    return val\n\n\ndef cross(v1: Vector3DLike, v2: Vector3DLike) -> Vector3D:\n    return np.array(\n        [\n            v1[1] * v2[2] - v1[2] * v2[1],\n            v1[2] * v2[0] - v1[0] * v2[2],\n            v1[0] * v2[1] - v1[1] * v2[0],\n        ]\n    )\n\n\n# Quaternions\n# TODO, implement quaternion type\n\n\ndef quaternion_mult(\n    *quats: Sequence[float],\n) -> np.ndarray | list[float | np.ndarray]:\n    \"\"\"Gets the Hamilton product of the quaternions provided.\n    For more information, check `this Wikipedia page\n    <https://en.wikipedia.org/wiki/Quaternion>`__.\n\n    Returns\n    -------\n    Union[np.ndarray, List[Union[float, np.ndarray]]]\n        Returns a list of product of two quaternions.\n    \"\"\"\n    if len(quats) == 0:\n        return [1, 0, 0, 0]\n    result = quats[0]\n    for next_quat in quats[1:]:\n        w1, x1, y1, z1 = result\n        w2, x2, y2, z2 = next_quat\n        result = [\n            w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2,\n            w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2,\n            w1 * y2 + y1 * w2 + z1 * x2 - x1 * z2,\n            w1 * z2 + z1 * w2 + x1 * y2 - y1 * x2,\n        ]\n    return result\n\n\ndef quaternion_from_angle_axis(\n    angle: float,\n    axis: np.ndarray,\n    axis_normalized: bool = False,\n) -> list[float]:\n    \"\"\"Gets a quaternion from an angle and an axis.\n    For more information, check `this Wikipedia page\n    <https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles>`__.\n\n    Parameters\n    ----------\n    angle\n        The angle for the quaternion.\n    axis\n        The axis for the quaternion\n    axis_normalized\n        Checks whether the axis is normalized, by default False\n\n    Returns\n    -------\n    list[float]\n        Gives back a quaternion from the angle and axis\n    \"\"\"\n    if not axis_normalized:\n        axis = normalize(axis)\n    return [np.cos(angle / 2), *(np.sin(angle / 2) * axis)]\n\n\ndef angle_axis_from_quaternion(quaternion: Sequence[float]) -> Sequence[float]:\n    \"\"\"Gets angle and axis from a quaternion.\n\n    Parameters\n    ----------\n    quaternion\n        The quaternion from which we get the angle and axis.\n\n    Returns\n    -------\n    Sequence[float]\n        Gives the angle and axis\n    \"\"\"\n    axis = normalize(quaternion[1:], fall_back=np.array([1, 0, 0]))\n    angle = 2 * np.arccos(quaternion[0])\n    if angle > TAU / 2:\n        angle = TAU - angle\n    return angle, axis\n\n\ndef quaternion_conjugate(quaternion: Sequence[float]) -> np.ndarray:\n    \"\"\"Used for finding the conjugate of the quaternion\n\n    Parameters\n    ----------\n    quaternion\n        The quaternion for which you want to find the conjugate for.\n\n    Returns\n    -------\n    np.ndarray\n        The conjugate of the quaternion.\n    \"\"\"\n    result = np.array(quaternion)\n    result[1:] *= -1\n    return result\n\n\ndef rotate_vector(\n    vector: Vector3DLike, angle: float, axis: Vector3DLike = OUT\n) -> Vector3D:\n    \"\"\"Function for rotating a vector.\n\n    Parameters\n    ----------\n    vector\n        The vector to be rotated.\n    angle\n        The angle to be rotated by.\n    axis\n        The axis to be rotated, by default OUT\n\n    Returns\n    -------\n    np.ndarray\n        The rotated vector with provided angle and axis.\n\n    Raises\n    ------\n    ValueError\n        If vector is not of dimension 2 or 3.\n    \"\"\"\n    if len(vector) > 3:\n        raise ValueError(\"Vector must have the correct dimensions.\")\n    if len(vector) == 2:\n        vector = np.append(vector, 0)\n    return rotation_matrix(angle, axis) @ vector\n\n\ndef thick_diagonal(dim: int, thickness: int = 2) -> MatrixMN:\n    row_indices = np.arange(dim).repeat(dim).reshape((dim, dim))\n    col_indices = np.transpose(row_indices)\n    return (np.abs(row_indices - col_indices) < thickness).astype(\"uint8\")\n\n\ndef rotation_matrix_transpose_from_quaternion(quat: np.ndarray) -> list[np.ndarray]:\n    \"\"\"Converts the quaternion, quat, to an equivalent rotation matrix representation.\n    For more information, check `this page\n    <https://in.mathworks.com/help/driving/ref/quaternion.rotmat.html>`_.\n\n    Parameters\n    ----------\n    quat\n        The quaternion which is to be converted.\n\n    Returns\n    -------\n    List[np.ndarray]\n        Gives back the Rotation matrix representation, returned as a 3-by-3\n        matrix or 3-by-3-by-N multidimensional array.\n    \"\"\"\n    quat_inv = quaternion_conjugate(quat)\n    return [\n        quaternion_mult(quat, [0, *basis], quat_inv)[1:]\n        for basis in [\n            [1, 0, 0],\n            [0, 1, 0],\n            [0, 0, 1],\n        ]\n    ]\n\n\ndef rotation_matrix_from_quaternion(quat: np.ndarray) -> np.ndarray:\n    return np.transpose(rotation_matrix_transpose_from_quaternion(quat))\n\n\ndef rotation_matrix_transpose(angle: float, axis: Vector3DLike) -> np.ndarray:\n    if all(np.array(axis)[:2] == np.zeros(2)):\n        return rotation_about_z(angle * np.sign(axis[2])).T\n    return rotation_matrix(angle, axis).T\n\n\ndef rotation_matrix(\n    angle: float,\n    axis: Vector3DLike,\n    homogeneous: bool = False,\n) -> np.ndarray:\n    \"\"\"Rotation in R^3 about a specified axis of rotation.\"\"\"\n    inhomogeneous_rotation_matrix = Rotation.from_rotvec(\n        angle * normalize(axis)\n    ).as_matrix()\n    if not homogeneous:\n        return inhomogeneous_rotation_matrix\n    else:\n        rotation_matrix = np.eye(4)\n        rotation_matrix[:3, :3] = inhomogeneous_rotation_matrix\n        return rotation_matrix\n\n\ndef rotation_about_z(angle: float) -> np.ndarray:\n    \"\"\"Returns a rotation matrix for a given angle.\n\n    Parameters\n    ----------\n    angle\n        Angle for the rotation matrix.\n\n    Returns\n    -------\n    np.ndarray\n        Gives back the rotated matrix.\n    \"\"\"\n    c, s = np.cos(angle), np.sin(angle)\n    return np.array(\n        [\n            [c, -s, 0],\n            [s, c, 0],\n            [0, 0, 1],\n        ]\n    )\n\n\ndef z_to_vector(vector: np.ndarray) -> np.ndarray:\n    \"\"\"\n    Returns some matrix in SO(3) which takes the z-axis to the\n    (normalized) vector provided as an argument\n    \"\"\"\n    axis_z = normalize(vector)\n    axis_y = normalize(cross(axis_z, RIGHT))\n    axis_x = cross(axis_y, axis_z)\n    if np.linalg.norm(axis_y) == 0:\n        # the vector passed just so happened to be in the x direction.\n        axis_x = normalize(cross(UP, axis_z))\n        axis_y = -cross(axis_x, axis_z)\n\n    return np.array([axis_x, axis_y, axis_z]).T\n\n\ndef angle_of_vector(vector: Sequence[float] | np.ndarray) -> float:\n    \"\"\"Returns polar coordinate theta when vector is projected on xy plane.\n\n    Parameters\n    ----------\n    vector\n        The vector to find the angle for.\n\n    Returns\n    -------\n    float\n        The angle of the vector projected.\n    \"\"\"\n    if isinstance(vector, np.ndarray) and len(vector.shape) > 1:\n        if vector.shape[0] < 2:\n            raise ValueError(\"Vector must have the correct dimensions. (2, n)\")\n        c_vec = np.empty(vector.shape[1], dtype=np.complex128)\n        c_vec.real = vector[0]\n        c_vec.imag = vector[1]\n        val1: float = np.angle(c_vec)\n        return val1\n    val: float = np.angle(complex(*vector[:2]))\n    return val\n\n\ndef angle_between_vectors(v1: np.ndarray, v2: np.ndarray) -> float:\n    \"\"\"Returns the angle between two vectors.\n    This angle will always be between 0 and pi\n\n    Parameters\n    ----------\n    v1\n        The first vector.\n    v2\n        The second vector.\n\n    Returns\n    -------\n    float\n        The angle between the vectors.\n    \"\"\"\n    val: float = 2 * np.arctan2(\n        np.linalg.norm(normalize(v1) - normalize(v2)),\n        np.linalg.norm(normalize(v1) + normalize(v2)),\n    )\n\n    return val\n\n\ndef normalize(\n    vect: np.ndarray | tuple[float], fall_back: np.ndarray | None = None\n) -> np.ndarray:\n    norm = np.linalg.norm(vect)\n    if norm > 0:\n        return np.array(vect) / norm\n    else:\n        return fall_back or np.zeros(len(vect))\n\n\ndef normalize_along_axis(array: np.ndarray, axis: np.ndarray) -> np.ndarray:\n    \"\"\"Normalizes an array with the provided axis.\n\n    Parameters\n    ----------\n    array\n        The array which has to be normalized.\n    axis\n        The axis to be normalized to.\n\n    Returns\n    -------\n    np.ndarray\n        Array which has been normalized according to the axis.\n    \"\"\"\n    norms = np.sqrt((array * array).sum(axis))\n    norms[norms == 0] = 1\n    buffed_norms = np.repeat(norms, array.shape[axis]).reshape(array.shape)\n    array /= buffed_norms\n    return array\n\n\ndef get_unit_normal(v1: Vector3DLike, v2: Vector3DLike, tol: float = 1e-6) -> Vector3D:\n    \"\"\"Gets the unit normal of the vectors.\n\n    Parameters\n    ----------\n    v1\n        The first vector.\n    v2\n        The second vector\n    tol\n        [description], by default 1e-6\n\n    Returns\n    -------\n    np.ndarray\n        The normal of the two vectors.\n    \"\"\"\n    np_v1 = np.asarray(v1)\n    np_v2 = np.asarray(v2)\n\n    # Instead of normalizing v1 and v2, just divide by the greatest\n    # of all their absolute components, which is just enough\n    div1, div2 = max(np.abs(np_v1)), max(np.abs(np_v2))\n    if div1 == 0.0:\n        if div2 == 0.0:\n            return DOWN\n        u = np_v2 / div2\n    elif div2 == 0.0:\n        u = np_v1 / div1\n    else:\n        # Normal scenario: v1 and v2 are both non-null\n        u1, u2 = np_v1 / div1, np_v2 / div2\n        cp = cross(u1, u2)\n        cp_norm = np.sqrt(norm_squared(cp))\n        if cp_norm > tol:\n            return cp / cp_norm\n        # Otherwise, v1 and v2 were aligned\n        u = u1\n\n    # If you are here, you have an \"unique\", non-zero, unit-ish vector u\n    # If it's also too aligned to the Z axis, just return DOWN\n    if abs(u[0]) < tol and abs(u[1]) < tol:\n        return DOWN\n    # Otherwise rotate u in the plane it shares with the Z axis,\n    # 90° TOWARDS the Z axis. This is done via (u x [0, 0, 1]) x u,\n    # which gives [-xz, -yz, x²+y²] (slightly scaled as well)\n    cp = np.array([-u[0] * u[2], -u[1] * u[2], u[0] * u[0] + u[1] * u[1]])\n    cp_norm = np.sqrt(norm_squared(cp))\n    # Because the norm(u) == 0 case was filtered in the beginning,\n    # there is no need to check if the norm of cp is 0\n    return cp / cp_norm\n\n\n###\n\n\ndef compass_directions(n: int = 4, start_vect: np.ndarray = RIGHT) -> np.ndarray:\n    \"\"\"Finds the cardinal directions using tau.\n\n    Parameters\n    ----------\n    n\n        The amount to be rotated, by default 4\n    start_vect\n        The direction for the angle to start with, by default RIGHT\n\n    Returns\n    -------\n    np.ndarray\n        The angle which has been rotated.\n    \"\"\"\n    angle = TAU / n\n    return np.array([rotate_vector(start_vect, k * angle) for k in range(n)])\n\n\ndef regular_vertices(\n    n: int, *, radius: float = 1, start_angle: float | None = None\n) -> tuple[np.ndarray, float]:\n    \"\"\"Generates regularly spaced vertices around a circle centered at the origin.\n\n    Parameters\n    ----------\n    n\n        The number of vertices\n    radius\n        The radius of the circle that the vertices are placed on.\n    start_angle\n        The angle the vertices start at.\n\n        If unspecified, for even ``n`` values, ``0`` will be used.\n        For odd ``n`` values, 90 degrees is used.\n\n    Returns\n    -------\n    vertices : :class:`numpy.ndarray`\n        The regularly spaced vertices.\n    start_angle : :class:`float`\n        The angle the vertices start at.\n    \"\"\"\n    if start_angle is None:\n        start_angle = 0 if n % 2 == 0 else TAU / 4\n\n    start_vector = rotate_vector(RIGHT * radius, start_angle)\n    vertices = compass_directions(n, start_vector)\n\n    return vertices, start_angle\n\n\ndef complex_to_R3(complex_num: complex) -> np.ndarray:\n    return np.array((complex_num.real, complex_num.imag, 0))\n\n\ndef R3_to_complex(point: Sequence[float]) -> np.ndarray:\n    return complex(*point[:2])\n\n\ndef complex_func_to_R3_func(\n    complex_func: Callable[[complex], complex],\n) -> Callable[[Point3DLike], Point3D]:\n    return lambda p: complex_to_R3(complex_func(R3_to_complex(p)))\n\n\ndef center_of_mass(points: PointNDLike_Array) -> PointND:\n    \"\"\"Gets the center of mass of the points in space.\n\n    Parameters\n    ----------\n    points\n        The points to find the center of mass from.\n\n    Returns\n    -------\n    np.ndarray\n        The center of mass of the points.\n    \"\"\"\n    return np.average(points, 0, np.ones(len(points)))\n\n\ndef midpoint(\n    point1: Sequence[float],\n    point2: Sequence[float],\n) -> float | np.ndarray:\n    \"\"\"Gets the midpoint of two points.\n\n    Parameters\n    ----------\n    point1\n        The first point.\n    point2\n        The second point.\n\n    Returns\n    -------\n    Union[float, np.ndarray]\n        The midpoint of the points\n    \"\"\"\n    return center_of_mass([point1, point2])\n\n\ndef line_intersection(\n    line1: Sequence[np.ndarray], line2: Sequence[np.ndarray]\n) -> np.ndarray:\n    \"\"\"Returns the intersection point of two lines, each defined by\n    a pair of distinct points lying on the line.\n\n    Parameters\n    ----------\n    line1\n        A list of two points that determine the first line.\n    line2\n        A list of two points that determine the second line.\n\n    Returns\n    -------\n    np.ndarray\n        The intersection points of the two lines which are intersecting.\n\n    Raises\n    ------\n    ValueError\n        Error is produced if the two lines don't intersect with each other\n        or if the coordinates don't lie on the xy-plane.\n    \"\"\"\n    if any(np.array([line1, line2])[:, :, 2].reshape(-1)):\n        # checks for z coordinates != 0\n        raise ValueError(\"Coords must be in the xy-plane.\")\n\n    # algorithm from https://stackoverflow.com/a/42727584\n    padded = (\n        np.pad(np.array(i)[:, :2], ((0, 0), (0, 1)), constant_values=1)\n        for i in (line1, line2)\n    )\n    line1, line2 = (cross(*i) for i in padded)\n    x, y, z = cross(line1, line2)\n\n    if z == 0:\n        raise ValueError(\n            \"The lines are parallel, there is no unique intersection point.\"\n        )\n\n    return np.array([x / z, y / z, 0])\n\n\ndef find_intersection(\n    p0s: Point3DLike_Array,\n    v0s: Vector3DLike_Array,\n    p1s: Point3DLike_Array,\n    v1s: Vector3DLike_Array,\n    threshold: float = 1e-5,\n) -> list[Point3D]:\n    \"\"\"\n    Return the intersection of a line passing through p0 in direction v0\n    with one passing through p1 in direction v1 (or array of intersections\n    from arrays of such points/directions).\n    For 3d values, it returns the point on the ray p0 + v0 * t closest to the\n    ray p1 + v1 * t\n    \"\"\"\n    # algorithm from https://en.wikipedia.org/wiki/Skew_lines#Nearest_points\n    result = []\n\n    for p0, v0, p1, v1 in zip(p0s, v0s, p1s, v1s, strict=True):\n        normal = cross(v1, cross(v0, v1))\n        denom = max(np.dot(v0, normal), threshold)\n        result += [p0 + np.dot(p1 - p0, normal) / denom * v0]\n    return result\n\n\ndef get_winding_number(points: Sequence[np.ndarray]) -> float:\n    \"\"\"Determine the number of times a polygon winds around the origin.\n\n    The orientation is measured mathematically positively, i.e.,\n    counterclockwise.\n\n    Parameters\n    ----------\n    points\n        The vertices of the polygon being queried.\n\n    Examples\n    --------\n\n    >>> from manim import Square, UP, get_winding_number\n    >>> polygon = Square()\n    >>> get_winding_number(polygon.get_vertices())\n    np.float64(1.0)\n    >>> polygon.shift(2 * UP)\n    Square\n    >>> get_winding_number(polygon.get_vertices())\n    np.float64(0.0)\n    \"\"\"\n    total_angle: float = 0\n    for p1, p2 in adjacent_pairs(points):\n        d_angle = angle_of_vector(p2) - angle_of_vector(p1)\n        d_angle = ((d_angle + PI) % TAU) - PI\n        total_angle += d_angle\n    val: float = total_angle / TAU\n    return val\n\n\ndef shoelace(x_y: Point2D_Array) -> float:\n    \"\"\"2D implementation of the shoelace formula.\n\n    Returns\n    -------\n    :class:`float`\n        Returns signed area.\n    \"\"\"\n    x = x_y[:, 0]\n    y = x_y[:, 1]\n    val: float = np.trapezoid(y, x)\n    return val\n\n\ndef shoelace_direction(x_y: Point2D_Array) -> str:\n    \"\"\"\n    Uses the area determined by the shoelace method to determine whether\n    the input set of points is directed clockwise or counterclockwise.\n\n    Returns\n    -------\n    :class:`str`\n        Either ``\"CW\"`` or ``\"CCW\"``.\n    \"\"\"\n    area = shoelace(x_y)\n    return \"CW\" if area > 0 else \"CCW\"\n\n\ndef cross2d(\n    a: Vector2D | Vector2D_Array,\n    b: Vector2D | Vector2D_Array,\n) -> ManimFloat | npt.NDArray[ManimFloat]:\n    \"\"\"Compute the determinant(s) of the passed\n    vector (sequences).\n\n    Parameters\n    ----------\n    a\n        A vector or a sequence of vectors.\n    b\n        A vector or a sequence of vectors.\n\n    Returns\n    -------\n    Sequence[float] | float\n        The determinant or sequence of determinants\n        of the first two components of the specified\n        vectors.\n\n    Examples\n    --------\n    .. code-block:: pycon\n\n        >>> cross2d(np.array([1, 2]), np.array([3, 4]))\n        np.int64(-2)\n        >>> cross2d(\n        ...     np.array([[1, 2, 0], [1, 0, 0]]),\n        ...     np.array([[3, 4, 0], [0, 1, 0]]),\n        ... )\n        array([-2,  1])\n    \"\"\"\n    if len(a.shape) == 2:\n        return a[:, 0] * b[:, 1] - a[:, 1] * b[:, 0]\n    else:\n        return a[0] * b[1] - b[0] * a[1]\n\n\ndef earclip_triangulation(verts: np.ndarray, ring_ends: list) -> list:\n    \"\"\"Returns a list of indices giving a triangulation\n    of a polygon, potentially with holes.\n\n    Parameters\n    ----------\n    verts\n        verts is a numpy array of points.\n    ring_ends\n        ring_ends is a list of indices indicating where\n        the ends of new paths are.\n\n    Returns\n    -------\n    list\n        A list of indices giving a triangulation of a polygon.\n    \"\"\"\n    # First, connect all the rings so that the polygon\n    # with holes is instead treated as a (very convex)\n    # polygon with one edge.  Do this by drawing connections\n    # between rings close to each other\n    rings = [\n        list(range(e0, e1)) for e0, e1 in zip([0, *ring_ends], ring_ends, strict=False)\n    ]\n    attached_rings = rings[:1]\n    detached_rings = rings[1:]\n    loop_connections = {}\n\n    while detached_rings:\n        i_range, j_range = (\n            list(\n                filter(\n                    # Ignore indices that are already being\n                    # used to draw some connection\n                    lambda i: i not in loop_connections,\n                    it.chain(*ring_group),\n                ),\n            )\n            for ring_group in (attached_rings, detached_rings)\n        )\n\n        # Closest point on the attached rings to an estimated midpoint\n        # of the detached rings\n        tmp_j_vert = midpoint(verts[j_range[0]], verts[j_range[len(j_range) // 2]])\n        i = min(i_range, key=lambda i: norm_squared(verts[i] - tmp_j_vert))\n        # Closest point of the detached rings to the aforementioned\n        # point of the attached rings\n        j = min(j_range, key=lambda j: norm_squared(verts[i] - verts[j]))\n        # Recalculate i based on new j\n        i = min(i_range, key=lambda i: norm_squared(verts[i] - verts[j]))\n\n        # Remember to connect the polygon at these points\n        loop_connections[i] = j\n        loop_connections[j] = i\n\n        # Move the ring which j belongs to from the\n        # attached list to the detached list\n        new_ring = next(\n            (ring for ring in detached_rings if ring[0] <= j < ring[-1]), None\n        )\n        if new_ring is not None:\n            detached_rings.remove(new_ring)\n            attached_rings.append(new_ring)\n        else:\n            raise Exception(\"Could not find a ring to attach\")\n\n    # Setup linked list\n    after: list[int] = []\n    end0 = 0\n    for end1 in ring_ends:\n        after.extend(range(end0 + 1, end1))\n        after.append(end0)\n        end0 = end1\n\n    # Find an ordering of indices walking around the polygon\n    indices = []\n    i = 0\n    for _ in range(len(verts) + len(ring_ends) - 1):\n        # starting = False\n        if i in loop_connections:\n            j = loop_connections[i]\n            indices.extend([i, j])\n            i = after[j]\n        else:\n            indices.append(i)\n            i = after[i]\n        if i == 0:\n            break\n\n    meta_indices = earcut(verts[indices, :2], np.array([len(indices)], dtype=np.uint32))\n    return [indices[mi] for mi in meta_indices]\n\n\ndef cartesian_to_spherical(vec: Vector3DLike) -> np.ndarray:\n    \"\"\"Returns an array of numbers corresponding to each\n    polar coordinate value (distance, phi, theta).\n\n    Parameters\n    ----------\n    vec\n        A numpy array or a sequence of floats ``[x, y, z]``.\n    \"\"\"\n    norm = np.linalg.norm(vec)\n    if norm == 0:\n        return np.zeros(3)\n    r = norm\n    phi = np.arccos(vec[2] / r)\n    theta = np.arctan2(vec[1], vec[0])\n    return np.array([r, theta, phi])\n\n\ndef spherical_to_cartesian(spherical: Sequence[float]) -> np.ndarray:\n    \"\"\"Returns a numpy array ``[x, y, z]`` based on the spherical\n    coordinates given.\n\n    Parameters\n    ----------\n    spherical\n        A list of three floats that correspond to the following:\n\n        r - The distance between the point and the origin.\n\n        theta - The azimuthal angle of the point to the positive x-axis.\n\n        phi - The vertical angle of the point to the positive z-axis.\n    \"\"\"\n    r, theta, phi = spherical\n    return np.array(\n        [\n            r * np.cos(theta) * np.sin(phi),\n            r * np.sin(theta) * np.sin(phi),\n            r * np.cos(phi),\n        ],\n    )\n\n\ndef perpendicular_bisector(\n    line: Sequence[np.ndarray],\n    norm_vector: Vector3D = OUT,\n) -> Sequence[np.ndarray]:\n    \"\"\"Returns a list of two points that correspond\n    to the ends of the perpendicular bisector of the\n    two points given.\n\n    Parameters\n    ----------\n    line\n        a list of two numpy array points (corresponding\n        to the ends of a line).\n    norm_vector\n        the vector perpendicular to both the line given\n        and the perpendicular bisector.\n\n    Returns\n    -------\n    list\n        A list of two numpy array points that correspond\n        to the ends of the perpendicular bisector\n    \"\"\"\n    p1 = line[0]\n    p2 = line[1]\n    direction = cross(p1 - p2, norm_vector)\n    m = midpoint(p1, p2)\n    return [m + direction, m - direction]\n"
  },
  {
    "path": "manim/utils/testing/__init__.py",
    "content": "\"\"\"Utilities for Manim tests using `pytest <https://pytest.org>`_.\n\nFor more information about Manim testing, see:\n\n-   :doc:`/contributing/development`, specifically the ``Tests`` bullet\n    point under :ref:`polishing-changes-and-submitting-a-pull-request`\n-   :doc:`/contributing/testing`\n\n.. autosummary::\n   :toctree: ../reference\n\n   frames_comparison\n   _frames_testers\n   _show_diff\n   _test_class_makers\n\n\"\"\"\n"
  },
  {
    "path": "manim/utils/testing/_frames_testers.py",
    "content": "from __future__ import annotations\n\nimport contextlib\nimport logging\nimport warnings\nfrom collections.abc import Generator\nfrom pathlib import Path\n\nimport numpy as np\n\nfrom manim.typing import PixelArray\n\nfrom ._show_diff import show_diff_helper\n\nFRAME_ABSOLUTE_TOLERANCE = 1.01\nFRAME_MISMATCH_RATIO_TOLERANCE = 1e-5\n\nlogger = logging.getLogger(\"manim\")\n\n\nclass _FramesTester:\n    def __init__(self, file_path: Path, show_diff: bool = False) -> None:\n        self._file_path = file_path\n        self._show_diff = show_diff\n        self._frames: np.ndarray\n        self._number_frames: int = 0\n        self._frames_compared = 0\n\n    @contextlib.contextmanager\n    def testing(self) -> Generator[None, None, None]:\n        with np.load(self._file_path) as data:\n            self._frames = data[\"frame_data\"]\n            # For backward compatibility, when the control data contains only one frame (<= v0.8.0)\n            if len(self._frames.shape) != 4:\n                self._frames = np.expand_dims(self._frames, axis=0)\n            logger.debug(self._frames.shape)\n            self._number_frames = np.ma.size(self._frames, axis=0)\n            yield\n            assert self._frames_compared == self._number_frames, (\n                f\"The scene tested contained {self._frames_compared} frames, \"\n                f\"when there are {self._number_frames} control frames for this test.\"\n            )\n\n    def check_frame(self, frame_number: int, frame: PixelArray) -> None:\n        assert frame_number < self._number_frames, (\n            f\"The tested scene is at frame number {frame_number} \"\n            f\"when there are {self._number_frames} control frames.\"\n        )\n        try:\n            np.testing.assert_allclose(\n                frame,\n                self._frames[frame_number],\n                atol=FRAME_ABSOLUTE_TOLERANCE,\n                err_msg=f\"Frame no {frame_number}. You can use --show_diff to visually show the difference.\",\n                verbose=False,\n            )\n            self._frames_compared += 1\n        except AssertionError as e:\n            number_of_matches = np.isclose(\n                frame, self._frames[frame_number], atol=FRAME_ABSOLUTE_TOLERANCE\n            ).sum()\n            number_of_mismatches = frame.size - number_of_matches\n            if number_of_mismatches / frame.size < FRAME_MISMATCH_RATIO_TOLERANCE:\n                # we tolerate a small (< 0.001%) amount of pixel value errors\n                # in the tests, this accounts for minor OS dependent inconsistencies\n                self._frames_compared += 1\n                warnings.warn(\n                    f\"Mismatch of {number_of_mismatches} pixel values in frame {frame_number} \"\n                    f\"against control data in {self._file_path}. Below error threshold, \"\n                    \"continuing...\",\n                    stacklevel=1,\n                )\n                return\n\n            if self._show_diff:\n                show_diff_helper(\n                    frame_number,\n                    frame,\n                    self._frames[frame_number],\n                    self._file_path.name,\n                )\n            raise e\n\n\nclass _ControlDataWriter(_FramesTester):\n    def __init__(self, file_path: Path, size_frame: tuple) -> None:\n        self.file_path = file_path\n        self.frames = np.empty((0, *size_frame, 4))\n        self._number_frames_written: int = 0\n\n    # Actually write a frame.\n    def check_frame(self, index: int, frame: PixelArray) -> None:\n        frame = frame[np.newaxis, ...]\n        self.frames = np.concatenate((self.frames, frame))\n        self._number_frames_written += 1\n\n    @contextlib.contextmanager\n    def testing(self) -> Generator[None, None, None]:\n        yield\n        self.save_contol_data()\n\n    def save_contol_data(self) -> None:\n        self.frames = self.frames.astype(\"uint8\")\n        np.savez_compressed(self.file_path, frame_data=self.frames)\n        logger.info(\n            f\"{self._number_frames_written} control frames saved in {self.file_path}\",\n        )\n"
  },
  {
    "path": "manim/utils/testing/_show_diff.py",
    "content": "from __future__ import annotations\n\nimport logging\nimport warnings\n\nimport numpy as np\n\nfrom manim.typing import PixelArray\n\n\ndef show_diff_helper(\n    frame_number: int,\n    frame_data: PixelArray,\n    expected_frame_data: PixelArray,\n    control_data_filename: str,\n) -> None:\n    \"\"\"Will visually display with matplotlib differences between frame generated and the one expected.\"\"\"\n    import matplotlib.gridspec as gridspec\n    import matplotlib.pyplot as plt\n\n    gs = gridspec.GridSpec(2, 2)\n    fig = plt.figure()\n    fig.suptitle(f\"Test difference summary at frame {frame_number}\", fontsize=16)\n\n    ax = fig.add_subplot(gs[0, 0])\n    ax.imshow(frame_data)\n    ax.set_title(\"Generated\")\n\n    ax = fig.add_subplot(gs[0, 1])\n    ax.imshow(expected_frame_data)\n    ax.set_title(\"Expected\")\n\n    ax = fig.add_subplot(gs[1, :])\n    diff_im = expected_frame_data.copy()\n    diff_im = np.where(\n        frame_data != np.array([0, 0, 0, 255]),\n        np.array([0, 255, 0, 255], dtype=\"uint8\"),\n        np.array([0, 0, 0, 255], dtype=\"uint8\"),\n    )  # Set any non-black pixels to green\n    np.putmask(\n        diff_im,\n        expected_frame_data != frame_data,\n        np.array([255, 0, 0, 255], dtype=\"uint8\"),\n    )  # Set any different pixels to red\n    ax.imshow(diff_im, interpolation=\"nearest\")\n    ax.set_title(\"Difference summary: (green = same, red = different)\")\n\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"error\")\n        try:\n            plt.show()\n        except UserWarning:\n            filename = f\"{control_data_filename[:-4]}-diff.pdf\"\n            plt.savefig(filename)\n            logging.warning(\n                \"Interactive matplotlib interface not available,\"\n                f\" diff saved to {filename}.\"\n            )\n"
  },
  {
    "path": "manim/utils/testing/_test_class_makers.py",
    "content": "from __future__ import annotations\n\nfrom collections.abc import Callable\nfrom typing import Any\n\nfrom manim.renderer.cairo_renderer import CairoRenderer\nfrom manim.renderer.opengl_renderer import OpenGLRenderer\nfrom manim.scene.scene import Scene\nfrom manim.scene.scene_file_writer import SceneFileWriter\nfrom manim.typing import PixelArray, StrPath\n\nfrom ._frames_testers import _FramesTester\n\n\ndef _make_test_scene_class(\n    base_scene: type[Scene],\n    construct_test: Callable[[Scene], None],\n    test_renderer: CairoRenderer | OpenGLRenderer | None,\n) -> type[Scene]:\n    # TODO: Get the type annotation right for the base_scene argument.\n    class _TestedScene(base_scene):  # type: ignore[valid-type, misc]\n        def __init__(self, *args: Any, **kwargs: Any) -> None:\n            super().__init__(*args, renderer=test_renderer, **kwargs)\n\n        def construct(self) -> None:\n            construct_test(self)\n\n            # Manim hack to render the very last frame (normally the last frame is not the very end of the animation)\n            if self.animations is not None:\n                self.update_to_time(self.get_run_time(self.animations))\n                self.renderer.render(self, 1, self.moving_mobjects)\n\n    return _TestedScene\n\n\ndef _make_test_renderer_class(from_renderer: type) -> Any:\n    # Just for inheritance.\n    class _TestRenderer(from_renderer):\n        pass\n\n    return _TestRenderer\n\n\nclass DummySceneFileWriter(SceneFileWriter):\n    \"\"\"Delegate of SceneFileWriter used to test the frames.\"\"\"\n\n    def __init__(\n        self,\n        renderer: CairoRenderer | OpenGLRenderer,\n        scene_name: str,\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(renderer, scene_name, **kwargs)\n        self.i = 0\n\n    def init_output_directories(self, scene_name: str) -> None:\n        pass\n\n    def add_partial_movie_file(self, hash_animation: str | None) -> None:\n        pass\n\n    def begin_animation(\n        self, allow_write: bool = True, file_path: StrPath | None = None\n    ) -> Any:\n        pass\n\n    def end_animation(self, allow_write: bool = False) -> None:\n        pass\n\n    def combine_to_movie(self) -> None:\n        pass\n\n    def combine_to_section_videos(self) -> None:\n        pass\n\n    def clean_cache(self) -> None:\n        pass\n\n    def write_frame(\n        self, frame_or_renderer: PixelArray | OpenGLRenderer, num_frames: int = 1\n    ) -> None:\n        self.i += 1\n\n\ndef _make_scene_file_writer_class(tester: _FramesTester) -> type[SceneFileWriter]:\n    class TestSceneFileWriter(DummySceneFileWriter):\n        def write_frame(\n            self, frame_or_renderer: PixelArray | OpenGLRenderer, num_frames: int = 1\n        ) -> None:\n            tester.check_frame(self.i, frame_or_renderer)\n            super().write_frame(frame_or_renderer, num_frames=num_frames)\n\n    return TestSceneFileWriter\n"
  },
  {
    "path": "manim/utils/testing/config_graphical_tests_monoframe.cfg",
    "content": "# Custom manim configuration used to run tests when only using the last frame.\n[CLI]\n\nframe_rate = 6\npixel_height = 480\npixel_width = 854\ndisable_caching = True\n"
  },
  {
    "path": "manim/utils/testing/config_graphical_tests_multiframes.cfg",
    "content": "# Custom manim configuration used to run tests when testing several frames.\n[CLI]\n\nframe_rate = 6\npixel_height = 240\npixel_width = 427\ndisable_caching = True\n"
  },
  {
    "path": "manim/utils/testing/frames_comparison.py",
    "content": "from __future__ import annotations\n\nimport functools\nimport inspect\nfrom collections.abc import Callable\nfrom pathlib import Path\nfrom typing import Any\n\nimport cairo\nimport pytest\nfrom _pytest.fixtures import FixtureRequest\n\nfrom manim import Scene\nfrom manim._config import tempconfig\nfrom manim._config.utils import ManimConfig\nfrom manim.camera.three_d_camera import ThreeDCamera\nfrom manim.renderer.cairo_renderer import CairoRenderer\nfrom manim.renderer.opengl_renderer import OpenGLRenderer\nfrom manim.scene.three_d_scene import ThreeDScene\nfrom manim.typing import StrPath\n\nfrom ._frames_testers import _ControlDataWriter, _FramesTester\nfrom ._test_class_makers import (\n    DummySceneFileWriter,\n    _make_scene_file_writer_class,\n    _make_test_renderer_class,\n    _make_test_scene_class,\n)\n\nSCENE_PARAMETER_NAME = \"scene\"\n_tests_root_dir_path = Path(__file__).absolute().parents[2]\nPATH_CONTROL_DATA = _tests_root_dir_path / Path(\"control_data\", \"graphical_units_data\")\nMIN_CAIRO_VERSION = 11800\n\n\ndef frames_comparison(\n    func: Callable | None = None,\n    *,\n    last_frame: bool = True,\n    renderer_class: type[CairoRenderer | OpenGLRenderer] = CairoRenderer,\n    base_scene: type[Scene] = Scene,\n    **custom_config: Any,\n) -> Callable:\n    \"\"\"Compares the frames generated by the test with control frames previously registered.\n\n    If there is no control frames for this test, the test will fail. To generate\n    control frames for a given test, pass ``--set_test`` flag to pytest\n    while running the test.\n\n    Note that this decorator can be use with or without parentheses.\n\n    Parameters\n    ----------\n    last_frame\n        whether the test should test the last frame, by default True.\n    renderer_class\n        The base renderer to use (OpenGLRenderer/CairoRenderer), by default CairoRenderer\n    base_scene\n        The base class for the scene (ThreeDScene, etc.), by default Scene\n\n    .. warning::\n        By default, last_frame is True, which means that only the last frame is tested.\n        If the scene has a moving animation, then the test must set last_frame to False.\n    \"\"\"\n\n    def decorator_maker(tested_scene_construct: Callable) -> Callable:\n        if (\n            SCENE_PARAMETER_NAME\n            not in inspect.getfullargspec(tested_scene_construct).args\n        ):\n            raise Exception(\n                f\"Invalid graphical test function test function : must have '{SCENE_PARAMETER_NAME}'as one of the parameters.\",\n            )\n\n        # Exclude \"scene\" from the argument list of the signature.\n        old_sig = inspect.signature(\n            functools.partial(tested_scene_construct, scene=None),\n        )\n\n        if \"__module_test__\" not in tested_scene_construct.__globals__:\n            raise Exception(\n                \"There is no module test name indicated for the graphical unit test. You have to declare __module_test__ in the test file.\",\n            )\n        module_name = tested_scene_construct.__globals__.get(\"__module_test__\")\n        assert isinstance(module_name, str)\n        test_name = tested_scene_construct.__name__[len(\"test_\") :]\n\n        @functools.wraps(tested_scene_construct)\n        # The \"request\" parameter is meant to be used as a fixture by pytest. See below.\n        def wrapper(\n            *args: Any, request: FixtureRequest, tmp_path: StrPath, **kwargs: Any\n        ) -> None:\n            # check for cairo version\n            if (\n                renderer_class is CairoRenderer\n                and cairo.cairo_version() < MIN_CAIRO_VERSION\n            ):\n                pytest.skip(\"Cairo version is too old. Skipping cairo graphical tests.\")\n            # Wraps the test_function to a construct method, to \"freeze\" the eventual additional arguments (parametrizations fixtures).\n            construct = functools.partial(tested_scene_construct, *args, **kwargs)\n\n            # Kwargs contains the eventual parametrization arguments.\n            # This modifies the test_name so that it is defined by the parametrization\n            # arguments too.\n            # Example: if \"length\" is parametrized from 0 to 20, the kwargs\n            # will be once with {\"length\" : 1}, etc.\n            test_name_with_param = test_name + \"_\".join(\n                f\"_{str(tup[0])}[{str(tup[1])}]\" for tup in kwargs.items()\n            )\n\n            config_tests = _config_test(last_frame)\n\n            config_tests[\"text_dir\"] = tmp_path\n            config_tests[\"tex_dir\"] = tmp_path\n\n            if last_frame:\n                config_tests[\"frame_rate\"] = 1\n                config_tests[\"dry_run\"] = True\n\n            setting_test = request.config.getoption(\"--set_test\")\n            try:\n                test_file_path = tested_scene_construct.__globals__[\"__file__\"]\n            except Exception:\n                test_file_path = None\n            real_test = _make_test_comparing_frames(\n                file_path=_control_data_path(\n                    test_file_path,\n                    module_name,\n                    test_name_with_param,\n                    setting_test,\n                ),\n                base_scene=base_scene,\n                construct=construct,\n                renderer_class=renderer_class,\n                is_set_test_data_test=setting_test,\n                last_frame=last_frame,\n                show_diff=request.config.getoption(\"--show_diff\"),\n                size_frame=(config_tests[\"pixel_height\"], config_tests[\"pixel_width\"]),\n            )\n\n            # Isolate the config used for the test, to avoid modifying the global config during the test run.\n            with tempconfig({**config_tests, **custom_config}):\n                real_test()\n\n        parameters = list(old_sig.parameters.values())\n        # Adds \"request\" param into the signature of the wrapper, to use the associated pytest fixture.\n        # This fixture is needed to have access to flags value and pytest's config. See above.\n        if \"request\" not in old_sig.parameters:\n            parameters += [inspect.Parameter(\"request\", inspect.Parameter.KEYWORD_ONLY)]\n        if \"tmp_path\" not in old_sig.parameters:\n            parameters += [\n                inspect.Parameter(\"tmp_path\", inspect.Parameter.KEYWORD_ONLY),\n            ]\n        new_sig = old_sig.replace(parameters=parameters)\n        wrapper.__signature__ = new_sig  # type: ignore[attr-defined]\n\n        # Reach a bit into pytest internals to hoist the marks from our wrapped\n        # function.\n        wrapper.pytestmark = []  # type: ignore[attr-defined]\n        new_marks = getattr(tested_scene_construct, \"pytestmark\", [])\n        wrapper.pytestmark = new_marks  # type: ignore[attr-defined]\n        return wrapper\n\n    # Case where the decorator is called with and without parentheses.\n    # If func is None, callabl(None) returns False\n    if callable(func):\n        return decorator_maker(func)\n    return decorator_maker\n\n\ndef _make_test_comparing_frames(\n    file_path: Path,\n    base_scene: type[Scene],\n    construct: Callable[[Scene], None],\n    renderer_class: type,  # Renderer type, there is no superclass renderer yet .....\n    is_set_test_data_test: bool,\n    last_frame: bool,\n    show_diff: bool,\n    size_frame: tuple,\n) -> Callable[[], None]:\n    \"\"\"Create the real pytest test that will fail if the frames mismatch.\n\n    Parameters\n    ----------\n    file_path\n        The path of the control frames.\n    base_scene\n        The base scene class.\n    construct\n        The construct method (= the test function)\n    renderer_class\n        The renderer base class.\n    show_diff\n        whether to visually show_diff (see --show_diff)\n\n    Returns\n    -------\n    Callable[[], None]\n        The pytest test.\n    \"\"\"\n    if is_set_test_data_test:\n        frames_tester: _FramesTester = _ControlDataWriter(\n            file_path, size_frame=size_frame\n        )\n    else:\n        frames_tester = _FramesTester(file_path, show_diff=show_diff)\n\n    file_writer_class = (\n        _make_scene_file_writer_class(frames_tester)\n        if not last_frame\n        else DummySceneFileWriter\n    )\n    testRenderer = _make_test_renderer_class(renderer_class)\n\n    def real_test() -> None:\n        with frames_tester.testing():\n            sceneTested = _make_test_scene_class(\n                base_scene=base_scene,\n                construct_test=construct,\n                # NOTE this is really ugly but it's due to the very bad design of the two renderers.\n                # If you pass a custom renderer to the Scene, the Camera class given as an argument in the Scene\n                # is not passed to the renderer. See __init__ of Scene.\n                # This potentially prevents OpenGL testing.\n                test_renderer=(\n                    testRenderer(file_writer_class=file_writer_class)\n                    if base_scene is not ThreeDScene\n                    else testRenderer(\n                        file_writer_class=file_writer_class,\n                        camera_class=ThreeDCamera,\n                    )\n                ),  # testRenderer(file_writer_class=file_writer_class),\n            )\n            scene_tested = sceneTested(skip_animations=True)\n            scene_tested.render()\n            if last_frame:\n                frames_tester.check_frame(-1, scene_tested.renderer.get_frame())\n\n    return real_test\n\n\ndef _control_data_path(\n    test_file_path: str | None, module_name: str, test_name: str, setting_test: bool\n) -> Path:\n    if test_file_path is None:\n        # For some reason, path to test file containing @frames_comparison could not\n        # be determined. Use local directory instead.\n        test_file_path = __file__\n\n    path = Path(test_file_path).absolute().parent / \"control_data\" / module_name\n\n    if setting_test:\n        # Create the directory if not existing.\n        path.mkdir(exist_ok=True)\n    if not setting_test and not path.exists():\n        raise Exception(f\"The control frames directory can't be found  in {path}\")\n    path = (path / test_name).with_suffix(\".npz\")\n    if not setting_test and not path.is_file():\n        raise Exception(\n            f\"The control frame for the test {test_name} cannot be found in {path.parent}. \"\n            \"Make sure you generated the control frames first.\",\n        )\n    return path\n\n\ndef _config_test(last_frame: bool) -> ManimConfig:\n    return ManimConfig().digest_file(\n        str(\n            Path(__file__).parent\n            / (\n                \"config_graphical_tests_monoframe.cfg\"\n                if last_frame\n                else \"config_graphical_tests_multiframes.cfg\"\n            ),\n        ),\n    )\n"
  },
  {
    "path": "manim/utils/tex.py",
    "content": "\"\"\"Utilities for processing LaTeX templates.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"TexTemplate\",\n]\n\nimport copy\nimport re\nimport warnings\nfrom dataclasses import dataclass, field\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, Any\n\nif TYPE_CHECKING:\n    from typing import Self\n\n    from manim.typing import StrPath\n\n_DEFAULT_PREAMBLE = r\"\"\"\\usepackage[english]{babel}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\"\"\"\n\n_BEGIN_DOCUMENT = r\"\\begin{document}\"\n_END_DOCUMENT = r\"\\end{document}\"\n\n\n@dataclass(eq=True)\nclass TexTemplate:\n    \"\"\"TeX templates are used to create ``Tex`` and ``MathTex`` objects.\"\"\"\n\n    _body: str = field(default=\"\", init=False)\n    \"\"\"A custom body, can be set from a file.\"\"\"\n\n    tex_compiler: str = \"latex\"\n    \"\"\"The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``.\"\"\"\n\n    description: str = \"\"\n    \"\"\"A description of the template\"\"\"\n\n    output_format: str = \".dvi\"\n    \"\"\"The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``.\"\"\"\n\n    documentclass: str = r\"\\documentclass[preview]{standalone}\"\n    r\"\"\"The command defining the documentclass, e.g. ``\\documentclass[preview]{standalone}``.\"\"\"\n\n    preamble: str = _DEFAULT_PREAMBLE\n    r\"\"\"The document's preamble, i.e. the part between ``\\documentclass`` and ``\\begin{document}``.\"\"\"\n\n    placeholder_text: str = \"YourTextHere\"\n    \"\"\"Text in the document that will be replaced by the expression to be rendered.\"\"\"\n\n    post_doc_commands: str = \"\"\n    r\"\"\"Text (definitions, commands) to be inserted at right after ``\\begin{document}``, e.g. ``\\boldmath``.\"\"\"\n\n    @property\n    def body(self) -> str:\n        \"\"\"The entire TeX template.\"\"\"\n        return self._body or \"\\n\".join(\n            filter(\n                None,\n                [\n                    self.documentclass,\n                    self.preamble,\n                    _BEGIN_DOCUMENT,\n                    self.post_doc_commands,\n                    self.placeholder_text,\n                    _END_DOCUMENT,\n                ],\n            )\n        )\n\n    @body.setter\n    def body(self, value: str) -> None:\n        self._body = value\n\n    @classmethod\n    def from_file(cls, file: StrPath = \"tex_template.tex\", **kwargs: Any) -> Self:\n        \"\"\"Create an instance by reading the content of a file.\n\n        Using the ``add_to_preamble`` and ``add_to_document`` methods on this instance\n        will have no effect, as the body is read from the file.\n        \"\"\"\n        instance = cls(**kwargs)\n        instance.body = Path(file).read_text(encoding=\"utf-8\")\n        return instance\n\n    def add_to_preamble(self, txt: str, prepend: bool = False) -> Self:\n        r\"\"\"Adds text to the TeX template's preamble (e.g. definitions, packages). Text can be inserted at the beginning or at the end of the preamble.\n\n        Parameters\n        ----------\n        txt\n            String containing the text to be added, e.g. ``\\usepackage{hyperref}``.\n        prepend\n            Whether the text should be added at the beginning of the preamble, i.e. right after ``\\documentclass``.\n            Default is to add it at the end of the preamble, i.e. right before ``\\begin{document}``.\n        \"\"\"\n        if self._body:\n            warnings.warn(\n                \"This TeX template was created with a fixed body, trying to add text the preamble will have no effect.\",\n                UserWarning,\n                stacklevel=2,\n            )\n        if prepend:\n            self.preamble = txt + \"\\n\" + self.preamble\n        else:\n            self.preamble += \"\\n\" + txt\n        return self\n\n    def add_to_document(self, txt: str) -> Self:\n        r\"\"\"Adds text to the TeX template just after \\begin{document}, e.g. ``\\boldmath``.\n\n        Parameters\n        ----------\n        txt\n            String containing the text to be added.\n        \"\"\"\n        if self._body:\n            warnings.warn(\n                \"This TeX template was created with a fixed body, trying to add text the document will have no effect.\",\n                UserWarning,\n                stacklevel=2,\n            )\n        self.post_doc_commands += txt\n        return self\n\n    def get_texcode_for_expression(self, expression: str) -> str:\n        r\"\"\"Inserts expression verbatim into TeX template.\n\n        Parameters\n        ----------\n        expression\n            The string containing the expression to be typeset, e.g. ``$\\sqrt{2}$``\n\n        Returns\n        -------\n        :class:`str`\n            LaTeX code based on current template, containing the given ``expression`` and ready for typesetting\n        \"\"\"\n        return self.body.replace(self.placeholder_text, expression)\n\n    def get_texcode_for_expression_in_env(\n        self, expression: str, environment: str\n    ) -> str:\n        r\"\"\"Inserts expression into TeX template wrapped in ``\\begin{environment}`` and ``\\end{environment}``.\n\n        Parameters\n        ----------\n        expression\n            The string containing the expression to be typeset, e.g. ``$\\sqrt{2}$``.\n        environment\n            The string containing the environment in which the expression should be typeset, e.g. ``align*``.\n\n        Returns\n        -------\n        :class:`str`\n            LaTeX code based on template, containing the given expression inside its environment, ready for typesetting\n        \"\"\"\n        begin, end = _texcode_for_environment(environment)\n        return self.body.replace(\n            self.placeholder_text, \"\\n\".join([begin, expression, end])\n        )\n\n    def copy(self) -> Self:\n        \"\"\"Create a deep copy of the TeX template instance.\"\"\"\n        return copy.deepcopy(self)\n\n\ndef _texcode_for_environment(environment: str) -> tuple[str, str]:\n    r\"\"\"Processes the tex_environment string to return the correct ``\\begin{environment}[extra]{extra}`` and\n    ``\\end{environment}`` strings.\n\n    Parameters\n    ----------\n    environment\n        The tex_environment as a string. Acceptable formats include:\n        ``{align*}``, ``align*``, ``{tabular}[t]{cccl}``, ``tabular}{cccl``, ``\\begin{tabular}[t]{cccl}``.\n\n    Returns\n    -------\n    Tuple[:class:`str`, :class:`str`]\n        A pair of strings representing the opening and closing of the tex environment, e.g.\n        ``\\begin{tabular}{cccl}`` and ``\\end{tabular}``\n    \"\"\"\n    environment = environment.removeprefix(r\"\\begin\").removeprefix(\"{\")\n\n    # The \\begin command takes everything and closes with a brace\n    begin = r\"\\begin{\" + environment\n    # If it doesn't end on } or ], assume missing }\n    if not begin.endswith((\"}\", \"]\")):\n        begin += \"}\"\n\n    # While the \\end command terminates at the first closing brace\n    split_at_brace = re.split(\"}\", environment, maxsplit=1)\n    end = r\"\\end{\" + split_at_brace[0] + \"}\"\n\n    return begin, end\n"
  },
  {
    "path": "manim/utils/tex_file_writing.py",
    "content": "\"\"\"Interface for writing, compiling, and converting ``.tex`` files.\n\n.. SEEALSO::\n\n    :mod:`.mobject.svg.tex_mobject`\n\n\"\"\"\n\nfrom __future__ import annotations\n\nimport hashlib\nimport re\nimport subprocess\nimport unicodedata\nfrom collections.abc import Generator, Iterable, Sequence\nfrom pathlib import Path\nfrom re import Match\nfrom typing import Any\n\nfrom manim.utils.tex import TexTemplate\n\nfrom .. import config, logger\n\n__all__ = [\"tex_to_svg_file\"]\n\n\ndef tex_hash(expression: Any) -> str:\n    id_str = str(expression)\n    hasher = hashlib.sha256()\n    hasher.update(id_str.encode())\n    # Truncating at 16 bytes for cleanliness\n    return hasher.hexdigest()[:16]\n\n\ndef tex_to_svg_file(\n    expression: str,\n    environment: str | None = None,\n    tex_template: TexTemplate | None = None,\n) -> Path:\n    r\"\"\"Takes a tex expression and returns the svg version of the compiled tex\n\n    Parameters\n    ----------\n    expression\n        String containing the TeX expression to be rendered, e.g. ``\\\\sqrt{2}`` or ``foo``\n    environment\n        The string containing the environment in which the expression should be typeset, e.g. ``align*``\n    tex_template\n        Template class used to typesetting. If not set, use default template set via `config[\"tex_template\"]`\n\n    Returns\n    -------\n    :class:`Path`\n        Path to generated SVG file.\n    \"\"\"\n    if tex_template is None:\n        tex_template = config[\"tex_template\"]\n    tex_file = generate_tex_file(expression, environment, tex_template)\n\n    # check if svg already exists\n    svg_file = tex_file.with_suffix(\".svg\")\n    if svg_file.exists():\n        return svg_file\n\n    dvi_file = compile_tex(\n        tex_file,\n        tex_template.tex_compiler,\n        tex_template.output_format,\n    )\n    svg_file = convert_to_svg(dvi_file, tex_template.output_format)\n    if not config[\"no_latex_cleanup\"]:\n        delete_nonsvg_files()\n    return svg_file\n\n\ndef generate_tex_file(\n    expression: str,\n    environment: str | None = None,\n    tex_template: TexTemplate | None = None,\n) -> Path:\n    r\"\"\"Takes a tex expression (and an optional tex environment),\n    and returns a fully formed tex file ready for compilation.\n\n    Parameters\n    ----------\n    expression\n        String containing the TeX expression to be rendered, e.g. ``\\\\sqrt{2}`` or ``foo``\n    environment\n        The string containing the environment in which the expression should be typeset, e.g. ``align*``\n    tex_template\n        Template class used to typesetting. If not set, use default template set via `config[\"tex_template\"]`\n\n    Returns\n    -------\n    :class:`Path`\n        Path to generated TeX file\n    \"\"\"\n    if tex_template is None:\n        tex_template = config[\"tex_template\"]\n    if environment is not None:\n        output = tex_template.get_texcode_for_expression_in_env(expression, environment)\n    else:\n        output = tex_template.get_texcode_for_expression(expression)\n\n    tex_dir = config.get_dir(\"tex_dir\")\n    tex_dir.mkdir(parents=True, exist_ok=True)\n\n    result = tex_dir / (tex_hash(output) + \".tex\")\n    if not result.exists():\n        logger.info(\n            \"Writing %(expression)s to %(path)s\",\n            {\"expression\": expression, \"path\": f\"{result}\"},\n        )\n        result.write_text(output, encoding=\"utf-8\")\n    return result\n\n\ndef make_tex_compilation_command(\n    tex_compiler: str, output_format: str, tex_file: Path, tex_dir: Path\n) -> list[str]:\n    \"\"\"Prepares the TeX compilation command, i.e. the TeX compiler name\n    and all necessary CLI flags.\n\n    Parameters\n    ----------\n    tex_compiler\n        String containing the compiler to be used, e.g. ``pdflatex`` or ``lualatex``\n    output_format\n        String containing the output format generated by the compiler, e.g. ``.dvi`` or ``.pdf``\n    tex_file\n        File name of TeX file to be typeset.\n    tex_dir\n        Path to the directory where compiler output will be stored.\n\n    Returns\n    -------\n    :class:`list[str]`\n        Compilation command according to given parameters\n    \"\"\"\n    if tex_compiler in {\"latex\", \"pdflatex\", \"luatex\", \"lualatex\"}:\n        command = [\n            tex_compiler,\n            \"-interaction=batchmode\",\n            f\"-output-format={output_format[1:]}\",\n            \"-halt-on-error\",\n            f\"-output-directory={tex_dir.as_posix()}\",\n            f\"{tex_file.as_posix()}\",\n        ]\n    elif tex_compiler == \"xelatex\":\n        if output_format == \".xdv\":\n            outflag = [\"-no-pdf\"]\n        elif output_format == \".pdf\":\n            outflag = []\n        else:\n            raise ValueError(\"xelatex output is either pdf or xdv\")\n        command = [\n            \"xelatex\",\n            *outflag,\n            \"-interaction=batchmode\",\n            \"-halt-on-error\",\n            f\"-output-directory={tex_dir.as_posix()}\",\n            f\"{tex_file.as_posix()}\",\n        ]\n    else:\n        raise ValueError(f\"Tex compiler {tex_compiler} unknown.\")\n    return command\n\n\ndef insight_inputenc_error(matching: Match[str]) -> Generator[str]:\n    code_point = chr(int(matching[1], 16))\n    name = unicodedata.name(code_point)\n    yield f\"TexTemplate does not support character '{name}' (U+{matching[1]}).\"\n    yield \"See the documentation for manim.mobject.svg.tex_mobject for details on using a custom TexTemplate.\"\n\n\ndef insight_package_not_found_error(matching: Match[str]) -> Generator[str]:\n    yield f\"You do not have package {matching[1]} installed.\"\n    yield f\"Install {matching[1]} it using your LaTeX package manager, or check for typos.\"\n\n\ndef compile_tex(tex_file: Path, tex_compiler: str, output_format: str) -> Path:\n    \"\"\"Compiles a tex_file into a .dvi or a .xdv or a .pdf\n\n    Parameters\n    ----------\n    tex_file\n        File name of TeX file to be typeset.\n    tex_compiler\n        String containing the compiler to be used, e.g. ``pdflatex`` or ``lualatex``\n    output_format\n        String containing the output format generated by the compiler, e.g. ``.dvi`` or ``.pdf``\n\n    Returns\n    -------\n    :class:`Path`\n        Path to generated output file in desired format (DVI, XDV or PDF).\n    \"\"\"\n    result = tex_file.with_suffix(output_format)\n    tex_dir = config.get_dir(\"tex_dir\")\n    if not result.exists():\n        command = make_tex_compilation_command(\n            tex_compiler,\n            output_format,\n            tex_file,\n            tex_dir,\n        )\n        cp = subprocess.run(command, stdout=subprocess.DEVNULL)\n        if cp.returncode != 0:\n            log_file = tex_file.with_suffix(\".log\")\n            print_all_tex_errors(log_file, tex_compiler, tex_file)\n            raise ValueError(\n                f\"{tex_compiler} error converting to\"\n                f\" {output_format[1:]}. See log output above or\"\n                f\" the log file: {log_file}\",\n            )\n    return result\n\n\ndef convert_to_svg(dvi_file: Path, extension: str, page: int = 1) -> Path:\n    \"\"\"Converts a .dvi, .xdv, or .pdf file into an svg using dvisvgm.\n\n    Parameters\n    ----------\n    dvi_file\n        File name of the input file to be converted.\n    extension\n        String containing the file extension and thus indicating the file type, e.g. ``.dvi`` or ``.pdf``\n    page\n        Page to be converted if input file is multi-page.\n\n    Returns\n    -------\n    :class:`Path`\n        Path to generated SVG file.\n    \"\"\"\n    result = dvi_file.with_suffix(\".svg\")\n    if not result.exists():\n        command = [\n            \"dvisvgm\",\n            *([\"--pdf\"] if extension == \".pdf\" else []),\n            f\"--page={page}\",\n            \"--no-fonts\",\n            \"--verbosity=0\",\n            f\"--output={result.as_posix()}\",\n            f\"{dvi_file.as_posix()}\",\n        ]\n        subprocess.run(command, stdout=subprocess.DEVNULL)\n\n    # if the file does not exist now, this means conversion failed\n    if not result.exists():\n        raise ValueError(\n            f\"Your installation does not support converting {dvi_file.suffix} files to SVG.\"\n            f\" Consider updating dvisvgm to at least version 2.4.\"\n            f\" If this does not solve the problem, please refer to our troubleshooting guide at:\"\n            f\" https://docs.manim.community/en/stable/faq/general.html#my-installation-\"\n            f\"does-not-support-converting-pdf-to-svg-help\",\n        )\n\n    return result\n\n\ndef delete_nonsvg_files(additional_endings: Iterable[str] = ()) -> None:\n    \"\"\"Deletes every file that does not have a suffix in ``(\".svg\", \".tex\", *additional_endings)``\n\n    Parameters\n    ----------\n    additional_endings\n        Additional endings to whitelist\n    \"\"\"\n    tex_dir = config.get_dir(\"tex_dir\")\n    file_suffix_whitelist = {\".svg\", \".tex\", *additional_endings}\n\n    for f in tex_dir.iterdir():\n        if f.suffix not in file_suffix_whitelist:\n            f.unlink()\n\n\ndef print_all_tex_errors(log_file: Path, tex_compiler: str, tex_file: Path) -> None:\n    if not log_file.exists():\n        raise RuntimeError(\n            f\"{tex_compiler} failed but did not produce a log file. \"\n            \"Check your LaTeX installation.\",\n        )\n    with log_file.open(encoding=\"utf-8\") as f:\n        tex_compilation_log = f.readlines()\n    error_indices = [\n        index for index, line in enumerate(tex_compilation_log) if line.startswith(\"!\")\n    ]\n    if error_indices:\n        with tex_file.open(encoding=\"utf-8\") as f:\n            tex = f.readlines()\n        for error_index in error_indices:\n            print_tex_error(tex_compilation_log, error_index, tex)\n\n\nLATEX_ERROR_INSIGHTS = [\n    (\n        r\"inputenc Error: Unicode character (?:.*) \\(U\\+([0-9a-fA-F]+)\\)\",\n        insight_inputenc_error,\n    ),\n    (\n        r\"LaTeX Error: File `(.*?[clsty])' not found\",\n        insight_package_not_found_error,\n    ),\n]\n\n\ndef print_tex_error(\n    tex_compilation_log: Sequence[str],\n    error_start_index: int,\n    tex_source: Sequence[str],\n) -> None:\n    logger.error(\n        f\"LaTeX compilation error: {tex_compilation_log[error_start_index][2:]}\",\n    )\n\n    # TeX errors eventually contain a line beginning 'l.xxx` where xxx is the line number that caused the compilation\n    # failure. This code finds the next such line after the error current error message\n    line_of_tex_error = (\n        int(\n            [\n                log_line\n                for log_line in tex_compilation_log[error_start_index:]\n                if log_line.startswith(\"l.\")\n            ][0]\n            .split(\" \")[0]\n            .split(\".\")[1],\n        )\n        - 1\n    )\n    # our tex error may be on a line outside our user input because of post-processing\n    if line_of_tex_error >= len(tex_source):\n        return None\n\n    context = [\"Context of error: \\n\"]\n    if line_of_tex_error < 3:\n        context += tex_source[: line_of_tex_error + 3]\n        context[-4] = \"-> \" + context[-4]\n    elif line_of_tex_error > len(tex_source) - 3:\n        context += tex_source[line_of_tex_error - 1 :]\n        context[1] = \"-> \" + context[1]\n    else:\n        context += tex_source[line_of_tex_error - 3 : line_of_tex_error + 3]\n        context[-4] = \"-> \" + context[-4]\n\n    context_joined = \"\".join(context)\n    logger.error(context_joined)\n\n    for insights in LATEX_ERROR_INSIGHTS:\n        prob, get_insight = insights\n        matching = re.search(\n            prob,\n            \"\".join(tex_compilation_log[error_start_index])[2:],\n        )\n        if matching is not None:\n            for insight in get_insight(matching):\n                logger.info(insight)\n"
  },
  {
    "path": "manim/utils/tex_templates.py",
    "content": "\"\"\"A library of LaTeX templates.\"\"\"\n\nfrom __future__ import annotations\n\n__all__ = [\n    \"TexTemplateLibrary\",\n    \"TexFontTemplates\",\n]\n\nfrom .tex import *\n\n# This file makes TexTemplateLibrary and TexFontTemplates available for use in manim Tex and MathTex objects.\n\n\ndef _new_ams_template() -> TexTemplate:\n    \"\"\"Returns a simple Tex Template with only basic AMS packages\"\"\"\n    preamble = r\"\"\"\n\\usepackage[english]{babel}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\n\"\"\"\n    return TexTemplate(preamble=preamble)\n\n\n\"\"\" Tex Template preamble used by original upstream 3b1b \"\"\"\n_3b1b_preamble = r\"\"\"\n\\usepackage[english]{babel}\n\\usepackage[utf8]{inputenc}\n\\usepackage[T1]{fontenc}\n\\usepackage{lmodern}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\n\\usepackage{dsfont}\n\\usepackage{setspace}\n\\usepackage{tipa}\n\\usepackage{relsize}\n\\usepackage{textcomp}\n\\usepackage{mathrsfs}\n\\usepackage{calligra}\n\\usepackage{wasysym}\n\\usepackage{ragged2e}\n\\usepackage{physics}\n\\usepackage{xcolor}\n\\usepackage{microtype}\n\\DisableLigatures{encoding = *, family = * }\n\\linespread{1}\n\"\"\"\n\n\n# TexTemplateLibrary\n#\nclass TexTemplateLibrary:\n    \"\"\"\n    A collection of basic TeX template objects\n\n    Examples\n    --------\n    Normal usage as a value for the keyword argument tex_template of Tex() and MathTex() mobjects::\n\n        ``Tex(\"My TeX code\", tex_template=TexTemplateLibrary.ctex)``\n\n    \"\"\"\n\n    default = TexTemplate(preamble=_3b1b_preamble)\n    \"\"\"An instance of the default TeX template in manim\"\"\"\n\n    threeb1b = TexTemplate(preamble=_3b1b_preamble)\n    \"\"\" An instance of the default TeX template used by 3b1b \"\"\"\n\n    ctex = TexTemplate(\n        tex_compiler=\"xelatex\",\n        output_format=\".xdv\",\n        preamble=_3b1b_preamble.replace(\n            r\"\\DisableLigatures{encoding = *, family = * }\",\n            r\"\\usepackage[UTF8]{ctex}\",\n        ),\n    )\n    \"\"\"An instance of the TeX template used by 3b1b when using the use_ctex flag\"\"\"\n\n    simple = _new_ams_template()\n    \"\"\"An instance of a simple TeX template with only basic AMS packages loaded\"\"\"\n\n\n# TexFontTemplates\n#\n# TexFontTemplates takes a font_id and returns the appropriate TexTemplate()\n# Usage:\n#       my_tex_template = TexFontTemplates.font_id\n#\n# Note: not all of these will work out-of-the-box.\n# They may require specific fonts to be installed on the local system.\n# For example TexFontTemplates.comic_sans will only work if the Microsoft font 'Comic Sans'\n# is installed on the local system.\n#\n# More information on these templates, along with example output can be found at\n# http://jf.burnol.free.fr/showcase.html\"\n#\n#\n# Choices for font_id are:\n#\n# american_typewriter       : \"American Typewriter\"\n# antykwa                   : \"Antykwa Półtawskiego (TX Fonts for Greek and math symbols)\"\n# apple_chancery            : \"Apple Chancery\"\n# auriocus_kalligraphicus   : \"Auriocus Kalligraphicus (Symbol Greek)\"\n# baskervald_adf_fourier    : \"Baskervald ADF with Fourier\"\n# baskerville_it            : \"Baskerville (Italic)\"\n# biolinum                  : \"Biolinum\"\n# brushscriptx              : \"BrushScriptX-Italic (PX math and Greek)\"\n# chalkboard_se             : \"Chalkboard SE\"\n# chalkduster               : \"Chalkduster\"\n# comfortaa                 : \"Comfortaa\"\n# comic_sans                : \"Comic Sans MS\"\n# droid_sans                : \"Droid Sans\"\n# droid_sans_it             : \"Droid Sans (Italic)\"\n# droid_serif               : \"Droid Serif\"\n# droid_serif_px_it         : \"Droid Serif (PX math symbols) (Italic)\"\n# ecf_augie                 : \"ECF Augie (Euler Greek)\"\n# ecf_jd                    : \"ECF JD (with TX fonts)\"\n# ecf_skeetch               : \"ECF Skeetch (CM Greek)\"\n# ecf_tall_paul             : \"ECF Tall Paul (with Symbol font)\"\n# ecf_webster               : \"ECF Webster (with TX fonts)\"\n# electrum_adf              : \"Electrum ADF (CM Greek)\"\n# epigrafica                : Epigrafica\n# fourier_utopia            : \"Fourier Utopia (Fourier upright Greek)\"\n# french_cursive            : \"French Cursive (Euler Greek)\"\n# gfs_bodoni                : \"GFS Bodoni\"\n# gfs_didot                 : \"GFS Didot (Italic)\"\n# gfs_neoHellenic           : \"GFS NeoHellenic\"\n# gnu_freesans_tx           : \"GNU FreeSerif (and TX fonts symbols)\"\n# gnu_freeserif_freesans    : \"GNU FreeSerif and FreeSans\"\n# helvetica_fourier_it      : \"Helvetica with Fourier (Italic)\"\n# latin_modern_tw_it        : \"Latin Modern Typewriter Proportional (CM Greek) (Italic)\"\n# latin_modern_tw           : \"Latin Modern Typewriter Proportional\"\n# libertine                 : \"Libertine\"\n# libris_adf_fourier        : \"Libris ADF with Fourier\"\n# minion_pro_myriad_pro     : \"Minion Pro and Myriad Pro (and TX fonts symbols)\"\n# minion_pro_tx             : \"Minion Pro (and TX fonts symbols)\"\n# new_century_schoolbook    : \"New Century Schoolbook (Symbol Greek)\"\n# new_century_schoolbook_px : \"New Century Schoolbook (Symbol Greek, PX math symbols)\"\n# noteworthy_light          : \"Noteworthy Light\"\n# palatino                  : \"Palatino (Symbol Greek)\"\n# papyrus                   : \"Papyrus\"\n# romande_adf_fourier_it    : \"Romande ADF with Fourier (Italic)\"\n# slitex                    : \"SliTeX (Euler Greek)\"\n# times_fourier_it          : \"Times with Fourier (Italic)\"\n# urw_avant_garde           : \"URW Avant Garde (Symbol Greek)\"\n# urw_zapf_chancery         : \"URW Zapf Chancery (CM Greek)\"\n# venturis_adf_fourier_it   : \"Venturis ADF with Fourier (Italic)\"\n# verdana_it                : \"Verdana (Italic)\"\n# vollkorn_fourier_it       : \"Vollkorn with Fourier (Italic)\"\n# vollkorn                  : \"Vollkorn (TX fonts for Greek and math symbols)\"\n# zapf_chancery             : \"Zapf Chancery\"\n# -----------------------------------------------------------------------------------------\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n\n# Latin Modern Typewriter Proportional\nlmtp = _new_ams_template()\nlmtp.description = \"Latin Modern Typewriter Proportional\"\nlmtp.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[variablett]{lmodern}\n\\renewcommand{\\rmdefault}{\\ttdefault}\n\\usepackage[LGRgreek]{mathastext}\n\\MTgreekfont{lmtt} % no lgr lmvtt, so use lgr lmtt\n\\Mathastext\n\\let\\varepsilon\\epsilon % only \\varsigma in LGR\n\"\"\",\n)\n\n\n# Fourier Utopia (Fourier upright Greek)\nfufug = _new_ams_template()\nfufug.description = \"Fourier Utopia (Fourier upright Greek)\"\nfufug.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[upright]{fourier}\n\\usepackage{mathastext}\n\"\"\",\n)\n\n\n# Droid Serif\ndroidserif = _new_ams_template()\ndroidserif.description = \"Droid Serif\"\ndroidserif.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[default]{droidserif}\n\\usepackage[LGRgreek]{mathastext}\n\\let\\varepsilon\\epsilon\n\"\"\",\n)\n\n\n# Droid Sans\ndroidsans = _new_ams_template()\ndroidsans.description = \"Droid Sans\"\ndroidsans.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[default]{droidsans}\n\\usepackage[LGRgreek]{mathastext}\n\\let\\varepsilon\\epsilon\n\"\"\",\n)\n\n\n# New Century Schoolbook (Symbol Greek)\nncssg = _new_ams_template()\nncssg.description = \"New Century Schoolbook (Symbol Greek)\"\nncssg.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{newcent}\n\\usepackage[symbolgreek]{mathastext}\n\\linespread{1.1}\n\"\"\",\n)\n\n\n# French Cursive (Euler Greek)\nfceg = _new_ams_template()\nfceg.description = \"French Cursive (Euler Greek)\"\nfceg.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[default]{frcursive}\n\\usepackage[eulergreek,noplusnominus,noequal,nohbar,%\nnolessnomore,noasterisk]{mathastext}\n\"\"\",\n)\n\n\n# Auriocus Kalligraphicus (Symbol Greek)\naksg = _new_ams_template()\naksg.description = \"Auriocus Kalligraphicus (Symbol Greek)\"\naksg.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{aurical}\n\\renewcommand{\\rmdefault}{AuriocusKalligraphicus}\n\\usepackage[symbolgreek]{mathastext}\n\"\"\",\n)\n\n\n# Palatino (Symbol Greek)\npalatinosg = _new_ams_template()\npalatinosg.description = \"Palatino (Symbol Greek)\"\npalatinosg.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{palatino}\n\\usepackage[symbolmax,defaultmathsizes]{mathastext}\n\"\"\",\n)\n\n\n# Comfortaa\ncomfortaa = _new_ams_template()\ncomfortaa.description = \"Comfortaa\"\ncomfortaa.add_to_preamble(\n    r\"\"\"\n\\usepackage[default]{comfortaa}\n\\usepackage[LGRgreek,defaultmathsizes,noasterisk]{mathastext}\n\\let\\varphi\\phi\n\\linespread{1.06}\n\"\"\",\n)\n\n\n# ECF Augie (Euler Greek)\necfaugieeg = _new_ams_template()\necfaugieeg.description = \"ECF Augie (Euler Greek)\"\necfaugieeg.add_to_preamble(\n    r\"\"\"\n\\renewcommand\\familydefault{fau} % emerald package\n\\usepackage[defaultmathsizes,eulergreek]{mathastext}\n\"\"\",\n)\n\n\n# Electrum ADF (CM Greek)\nelectrumadfcm = _new_ams_template()\nelectrumadfcm.description = \"Electrum ADF (CM Greek)\"\nelectrumadfcm.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[LGRgreek,basic,defaultmathsizes]{mathastext}\n\\usepackage[lf]{electrum}\n\\Mathastext\n\\let\\varphi\\phi\n\"\"\",\n)\n\n\n# American Typewriter\namericantypewriter = _new_ams_template()\namericantypewriter.description = \"American Typewriter\"\namericantypewriter.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{American Typewriter}\n\\usepackage[defaultmathsizes]{mathastext}\n\"\"\",\n)\namericantypewriter.tex_compiler = \"xelatex\"\namericantypewriter.output_format = \".xdv\"\n\n# Minion Pro and Myriad Pro (and TX fonts symbols)\nmpmptx = _new_ams_template()\nmpmptx.description = \"Minion Pro and Myriad Pro (and TX fonts symbols)\"\nmpmptx.add_to_preamble(\n    r\"\"\"\n\\usepackage{txfonts}\n\\usepackage[upright]{txgreeks}\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{Minion Pro}\n\\setsansfont[Mapping=tex-text,Scale=MatchUppercase]{Myriad Pro}\n\\renewcommand\\familydefault\\sfdefault\n\\usepackage[defaultmathsizes]{mathastext}\n\\renewcommand\\familydefault\\rmdefault\n\"\"\",\n)\nmpmptx.tex_compiler = \"xelatex\"\nmpmptx.output_format = \".xdv\"\n\n\n# New Century Schoolbook (Symbol Greek, PX math symbols)\nncssgpxm = _new_ams_template()\nncssgpxm.description = \"New Century Schoolbook (Symbol Greek, PX math symbols)\"\nncssgpxm.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{pxfonts}\n\\usepackage{newcent}\n\\usepackage[symbolgreek,defaultmathsizes]{mathastext}\n\\linespread{1.06}\n\"\"\",\n)\n\n\n# Vollkorn (TX fonts for Greek and math symbols)\nvollkorntx = _new_ams_template()\nvollkorntx.description = \"Vollkorn (TX fonts for Greek and math symbols)\"\nvollkorntx.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{txfonts}\n\\usepackage[upright]{txgreeks}\n\\usepackage{vollkorn}\n\\usepackage[defaultmathsizes]{mathastext}\n\"\"\",\n)\n\n\n# Libertine\nlibertine = _new_ams_template()\nlibertine.description = \"Libertine\"\nlibertine.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{libertine}\n\\usepackage[greek=n]{libgreek}\n\\usepackage[noasterisk,defaultmathsizes]{mathastext}\n\"\"\",\n)\n\n\n# SliTeX (Euler Greek)\nslitexeg = _new_ams_template()\nslitexeg.description = \"SliTeX (Euler Greek)\"\nslitexeg.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{tpslifonts}\n\\usepackage[eulergreek,defaultmathsizes]{mathastext}\n\\MTEulerScale{1.06}\n\\linespread{1.2}\n\"\"\",\n)\n\n\n# ECF Webster (with TX fonts)\necfwebstertx = _new_ams_template()\necfwebstertx.description = \"ECF Webster (with TX fonts)\"\necfwebstertx.add_to_preamble(\n    r\"\"\"\n\\usepackage{txfonts}\n\\usepackage[upright]{txgreeks}\n\\renewcommand\\familydefault{fwb} % emerald package\n\\usepackage{mathastext}\n\\renewcommand{\\int}{\\intop\\limits}\n\\linespread{1.5}\n\"\"\",\n)\necfwebstertx.add_to_document(\n    r\"\"\"\n\\mathversion{bold}\n\"\"\",\n)\n\n\n# Romande ADF with Fourier (Italic)\nitalicromandeadff = _new_ams_template()\nitalicromandeadff.description = \"Romande ADF with Fourier (Italic)\"\nitalicromandeadff.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{fourier}\n\\usepackage{romande}\n\\usepackage[italic,defaultmathsizes,noasterisk]{mathastext}\n\\renewcommand{\\itshape}{\\swashstyle}\n\"\"\",\n)\n\n\n# Apple Chancery\napplechancery = _new_ams_template()\napplechancery.description = \"Apple Chancery\"\napplechancery.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{Apple Chancery}\n\\usepackage[defaultmathsizes]{mathastext}\n\"\"\",\n)\napplechancery.tex_compiler = \"xelatex\"\napplechancery.output_format = \".xdv\"\n\n\n# Zapf Chancery\nzapfchancery = _new_ams_template()\nzapfchancery.description = \"Zapf Chancery\"\nzapfchancery.add_to_preamble(\n    r\"\"\"\n\\DeclareFontFamily{T1}{pzc}{}\n\\DeclareFontShape{T1}{pzc}{mb}{it}{<->s*[1.2] pzcmi8t}{}\n\\DeclareFontShape{T1}{pzc}{m}{it}{<->ssub * pzc/mb/it}{}\n\\usepackage{chancery} % = \\renewcommand{\\rmdefault}{pzc}\n\\renewcommand\\shapedefault\\itdefault\n\\renewcommand\\bfdefault\\mddefault\n\\usepackage[defaultmathsizes]{mathastext}\n\\linespread{1.05}\n\"\"\",\n)\n\n\n# Verdana (Italic)\nitalicverdana = _new_ams_template()\nitalicverdana.description = \"Verdana (Italic)\"\nitalicverdana.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{Verdana}\n\\usepackage[defaultmathsizes,italic]{mathastext}\n\"\"\",\n)\nitalicverdana.tex_compiler = \"xelatex\"\nitalicverdana.output_format = \".xdv\"\n\n\n# URW Zapf Chancery (CM Greek)\nurwzccmg = _new_ams_template()\nurwzccmg.description = \"URW Zapf Chancery (CM Greek)\"\nurwzccmg.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\DeclareFontFamily{T1}{pzc}{}\n\\DeclareFontShape{T1}{pzc}{mb}{it}{<->s*[1.2] pzcmi8t}{}\n\\DeclareFontShape{T1}{pzc}{m}{it}{<->ssub * pzc/mb/it}{}\n\\DeclareFontShape{T1}{pzc}{mb}{sl}{<->ssub * pzc/mb/it}{}\n\\DeclareFontShape{T1}{pzc}{m}{sl}{<->ssub * pzc/mb/sl}{}\n\\DeclareFontShape{T1}{pzc}{m}{n}{<->ssub * pzc/mb/it}{}\n\\usepackage{chancery}\n\\usepackage{mathastext}\n\\linespread{1.05}\"\"\",\n)\nurwzccmg.add_to_document(\n    r\"\"\"\n\\boldmath\n\"\"\",\n)\n\n\n# Comic Sans MS\ncomicsansms = _new_ams_template()\ncomicsansms.description = \"Comic Sans MS\"\ncomicsansms.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{Comic Sans MS}\n\\usepackage[defaultmathsizes]{mathastext}\n\"\"\",\n)\ncomicsansms.tex_compiler = \"xelatex\"\ncomicsansms.output_format = \".xdv\"\n\n\n# GFS Didot (Italic)\nitalicgfsdidot = _new_ams_template()\nitalicgfsdidot.description = \"GFS Didot (Italic)\"\nitalicgfsdidot.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\renewcommand\\rmdefault{udidot}\n\\usepackage[LGRgreek,defaultmathsizes,italic]{mathastext}\n\\let\\varphi\\phi\n\"\"\",\n)\n\n\n# Chalkduster\nchalkduster = _new_ams_template()\nchalkduster.description = \"Chalkduster\"\nchalkduster.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{Chalkduster}\n\\usepackage[defaultmathsizes]{mathastext}\n\"\"\",\n)\nchalkduster.tex_compiler = \"lualatex\"\nchalkduster.output_format = \".pdf\"\n\n\n# Minion Pro (and TX fonts symbols)\nmptx = _new_ams_template()\nmptx.description = \"Minion Pro (and TX fonts symbols)\"\nmptx.add_to_preamble(\n    r\"\"\"\n\\usepackage{txfonts}\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{Minion Pro}\n\\usepackage[defaultmathsizes]{mathastext}\n\"\"\",\n)\nmptx.tex_compiler = \"xelatex\"\nmptx.output_format = \".xdv\"\n\n\n# GNU FreeSerif and FreeSans\ngnufsfs = _new_ams_template()\ngnufsfs.description = \"GNU FreeSerif and FreeSans\"\ngnufsfs.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\setmainfont[ExternalLocation,\n                Mapping=tex-text,\n                BoldFont=FreeSerifBold,\n                ItalicFont=FreeSerifItalic,\n                BoldItalicFont=FreeSerifBoldItalic]{FreeSerif}\n\\setsansfont[ExternalLocation,\n                Mapping=tex-text,\n                BoldFont=FreeSansBold,\n                ItalicFont=FreeSansOblique,\n                BoldItalicFont=FreeSansBoldOblique,\n                Scale=MatchLowercase]{FreeSans}\n\\renewcommand{\\familydefault}{lmss}\n\\usepackage[LGRgreek,defaultmathsizes,noasterisk]{mathastext}\n\\renewcommand{\\familydefault}{\\sfdefault}\n\\Mathastext\n\\let\\varphi\\phi % no `var' phi in LGR encoding\n\\renewcommand{\\familydefault}{\\rmdefault}\n\"\"\",\n)\ngnufsfs.tex_compiler = \"xelatex\"\ngnufsfs.output_format = \".xdv\"\n\n# GFS NeoHellenic\ngfsneohellenic = _new_ams_template()\ngfsneohellenic.description = \"GFS NeoHellenic\"\ngfsneohellenic.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\renewcommand{\\rmdefault}{neohellenic}\n\\usepackage[LGRgreek]{mathastext}\n\\let\\varphi\\phi\n\\linespread{1.06}\n\"\"\",\n)\n\n\n# ECF Tall Paul (with Symbol font)\necftallpaul = _new_ams_template()\necftallpaul.description = \"ECF Tall Paul (with Symbol font)\"\necftallpaul.add_to_preamble(\n    r\"\"\"\n\\DeclareFontFamily{T1}{ftp}{}\n\\DeclareFontShape{T1}{ftp}{m}{n}{\n    <->s*[1.4] ftpmw8t\n}{} % increase size by factor 1.4\n\\renewcommand\\familydefault{ftp} % emerald package\n\\usepackage[symbol]{mathastext}\n\\let\\infty\\inftypsy\n\"\"\",\n)\n\n\n# Droid Sans (Italic)\nitalicdroidsans = _new_ams_template()\nitalicdroidsans.description = \"Droid Sans (Italic)\"\nitalicdroidsans.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[default]{droidsans}\n\\usepackage[LGRgreek,defaultmathsizes,italic]{mathastext}\n\\let\\varphi\\phi\n\"\"\",\n)\n\n\n# Baskerville (Italic)\nitalicbaskerville = _new_ams_template()\nitalicbaskerville.description = \"Baskerville (Italic)\"\nitalicbaskerville.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{Baskerville}\n\\usepackage[defaultmathsizes,italic]{mathastext}\n\"\"\",\n)\nitalicbaskerville.tex_compiler = \"xelatex\"\nitalicbaskerville.output_format = \".xdv\"\n\n\n# ECF JD (with TX fonts)\necfjdtx = _new_ams_template()\necfjdtx.description = \"ECF JD (with TX fonts)\"\necfjdtx.add_to_preamble(\n    r\"\"\"\n\\usepackage{txfonts}\n\\usepackage[upright]{txgreeks}\n\\renewcommand\\familydefault{fjd} % emerald package\n\\usepackage{mathastext}\n\"\"\",\n)\necfjdtx.add_to_document(\n    r\"\"\"\\mathversion{bold}\n\"\"\",\n)\n\n\n# Antykwa Półtawskiego (TX Fonts for Greek and math symbols)\naptxgm = _new_ams_template()\naptxgm.description = \"Antykwa Półtawskiego (TX Fonts for Greek and math symbols)\"\naptxgm.add_to_preamble(\n    r\"\"\"\n\\usepackage[OT4,OT1]{fontenc}\n\\usepackage{txfonts}\n\\usepackage[upright]{txgreeks}\n\\usepackage{antpolt}\n\\usepackage[defaultmathsizes,nolessnomore]{mathastext}\n\"\"\",\n)\n\n\n# Papyrus\npapyrus = _new_ams_template()\npapyrus.description = \"Papyrus\"\npapyrus.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{Papyrus}\n\\usepackage[defaultmathsizes]{mathastext}\n\"\"\",\n)\npapyrus.tex_compiler = \"xelatex\"\npapyrus.output_format = \".xdv\"\n\n\n# GNU FreeSerif (and TX fonts symbols)\ngnufstx = _new_ams_template()\ngnufstx.description = \"GNU FreeSerif (and TX fonts symbols)\"\ngnufstx.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\usepackage{txfonts}  %\\let\\mathbb=\\varmathbb\n\\setmainfont[ExternalLocation,\n                Mapping=tex-text,\n                BoldFont=FreeSerifBold,\n                ItalicFont=FreeSerifItalic,\n                BoldItalicFont=FreeSerifBoldItalic]{FreeSerif}\n\\usepackage[defaultmathsizes]{mathastext}\n\"\"\",\n)\ngnufstx.tex_compiler = \"xelatex\"\ngnufstx.output_format = \".pdf\"\n\n\n# ECF Skeetch (CM Greek)\necfscmg = _new_ams_template()\necfscmg.description = \"ECF Skeetch (CM Greek)\"\necfscmg.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[T1]{fontenc}\n\\DeclareFontFamily{T1}{fsk}{}\n\\DeclareFontShape{T1}{fsk}{m}{n}{<->s*[1.315] fskmw8t}{}\n\\renewcommand\\rmdefault{fsk}\n\\usepackage[noendash,defaultmathsizes,nohbar,defaultimath]{mathastext}\n\"\"\",\n)\n\n\n# Latin Modern Typewriter Proportional (CM Greek) (Italic)\nitaliclmtpcm = _new_ams_template()\nitaliclmtpcm.description = \"Latin Modern Typewriter Proportional (CM Greek) (Italic)\"\nitaliclmtpcm.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[variablett,nomath]{lmodern}\n\\renewcommand{\\familydefault}{\\ttdefault}\n\\usepackage[frenchmath]{mathastext}\n\\linespread{1.08}\n\"\"\",\n)\n\n\n# Baskervald ADF with Fourier\nbaskervaldadff = _new_ams_template()\nbaskervaldadff.description = \"Baskervald ADF with Fourier\"\nbaskervaldadff.add_to_preamble(\n    r\"\"\"\n\\usepackage[upright]{fourier}\n\\usepackage{baskervald}\n\\usepackage[defaultmathsizes,noasterisk]{mathastext}\n\"\"\",\n)\n\n\n# Droid Serif (PX math symbols) (Italic)\nitalicdroidserifpx = _new_ams_template()\nitalicdroidserifpx.description = \"Droid Serif (PX math symbols) (Italic)\"\nitalicdroidserifpx.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{pxfonts}\n\\usepackage[default]{droidserif}\n\\usepackage[LGRgreek,defaultmathsizes,italic,basic]{mathastext}\n\\let\\varphi\\phi\n\"\"\",\n)\n\n\n# Biolinum\nbiolinum = _new_ams_template()\nbiolinum.description = \"Biolinum\"\nbiolinum.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{libertine}\n\\renewcommand{\\familydefault}{\\sfdefault}\n\\usepackage[greek=n,biolinum]{libgreek}\n\\usepackage[noasterisk,defaultmathsizes]{mathastext}\n\"\"\",\n)\n\n\n# Vollkorn with Fourier (Italic)\nitalicvollkornf = _new_ams_template()\nitalicvollkornf.description = \"Vollkorn with Fourier (Italic)\"\nitalicvollkornf.add_to_preamble(\n    r\"\"\"\n\\usepackage{fourier}\n\\usepackage{vollkorn}\n\\usepackage[italic,nohbar]{mathastext}\n\"\"\",\n)\n\n\n# Chalkboard SE\nchalkboardse = _new_ams_template()\nchalkboardse.description = \"Chalkboard SE\"\nchalkboardse.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{Chalkboard SE}\n\\usepackage[defaultmathsizes]{mathastext}\n\"\"\",\n)\nchalkboardse.tex_compiler = \"xelatex\"\nchalkboardse.output_format = \".xdv\"\n\n\n# Noteworthy Light\nnoteworthylight = _new_ams_template()\nnoteworthylight.description = \"Noteworthy Light\"\nnoteworthylight.add_to_preamble(\n    r\"\"\"\n\\usepackage[no-math]{fontspec}\n\\setmainfont[Mapping=tex-text]{Noteworthy Light}\n\\usepackage[defaultmathsizes]{mathastext}\n\"\"\",\n)\n\n\n# Epigrafica\nepigrafica = _new_ams_template()\nepigrafica.description = \"Epigrafica\"\nepigrafica.add_to_preamble(\n    r\"\"\"\n\\usepackage[LGR,OT1]{fontenc}\n\\usepackage{epigrafica}\n\\usepackage[basic,LGRgreek,defaultmathsizes]{mathastext}\n\\let\\varphi\\phi\n\\linespread{1.2}\n\"\"\",\n)\n\n\n# Libris ADF with Fourier\nlibrisadff = _new_ams_template()\nlibrisadff.description = \"Libris ADF with Fourier\"\nlibrisadff.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[upright]{fourier}\n\\usepackage{libris}\n\\renewcommand{\\familydefault}{\\sfdefault}\n\\usepackage[noasterisk]{mathastext}\n\"\"\",\n)\n\n\n# Venturis ADF with Fourier (Italic)\nitalicvanturisadff = _new_ams_template()\nitalicvanturisadff.description = \"Venturis ADF with Fourier (Italic)\"\nitalicvanturisadff.add_to_preamble(\n    r\"\"\"\n\\usepackage{fourier}\n\\usepackage[lf]{venturis}\n\\usepackage[italic,defaultmathsizes,noasterisk]{mathastext}\n\"\"\",\n)\n\n\n# GFS Bodoni\ngfsbodoni = _new_ams_template()\ngfsbodoni.description = \"GFS Bodoni\"\ngfsbodoni.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\renewcommand{\\rmdefault}{bodoni}\n\\usepackage[LGRgreek]{mathastext}\n\\let\\varphi\\phi\n\\linespread{1.06}\n\"\"\",\n)\n\n\n# BrushScriptX-Italic (PX math and Greek)\nbrushscriptxpx = _new_ams_template()\nbrushscriptxpx.description = \"BrushScriptX-Italic (PX math and Greek)\"\nbrushscriptxpx.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{pxfonts}\n%\\usepackage{pbsi}\n\\renewcommand{\\rmdefault}{pbsi}\n\\renewcommand{\\mddefault}{xl}\n\\renewcommand{\\bfdefault}{xl}\n\\usepackage[defaultmathsizes,noasterisk]{mathastext}\n\"\"\",\n)\nbrushscriptxpx.add_to_document(\n    r\"\"\"\\boldmath\n\"\"\",\n)\nbrushscriptxpx.tex_compiler = \"xelatex\"\nbrushscriptxpx.output_format = \".xdv\"\n\n\n# URW Avant Garde (Symbol Greek)\nurwagsg = _new_ams_template()\nurwagsg.description = \"URW Avant Garde (Symbol Greek)\"\nurwagsg.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage{avant}\n\\renewcommand{\\familydefault}{\\sfdefault}\n\\usepackage[symbolgreek,defaultmathsizes]{mathastext}\n\"\"\",\n)\n\n\n# Times with Fourier (Italic)\nitalictimesf = _new_ams_template()\nitalictimesf.description = \"Times with Fourier (Italic)\"\nitalictimesf.add_to_preamble(\n    r\"\"\"\n\\usepackage{fourier}\n\\renewcommand{\\rmdefault}{ptm}\n\\usepackage[italic,defaultmathsizes,noasterisk]{mathastext}\n\"\"\",\n)\n\n\n# Helvetica with Fourier (Italic)\nitalichelveticaf = _new_ams_template()\nitalichelveticaf.description = \"Helvetica with Fourier (Italic)\"\nitalichelveticaf.add_to_preamble(\n    r\"\"\"\n\\usepackage[T1]{fontenc}\n\\usepackage[scaled]{helvet}\n\\usepackage{fourier}\n\\renewcommand{\\rmdefault}{phv}\n\\usepackage[italic,defaultmathsizes,noasterisk]{mathastext}\n\"\"\",\n)\n\n\nclass TexFontTemplates:\n    \"\"\"\n    A collection of TeX templates for the fonts described at http://jf.burnol.free.fr/showcase.html\n\n    These templates are specifically designed to allow you to typeset formulae and mathematics using\n    different fonts. They are based on the mathastext LaTeX package.\n\n    Examples\n    ---------\n    Normal usage as a value for the keyword argument tex_template of Tex() and MathTex() mobjects::\n\n        ``Tex(\"My TeX code\", tex_template=TexFontTemplates.comic_sans)``\n\n    Notes\n    ------\n    Many of these templates require that specific fonts\n    are installed on your local machine.\n    For example, choosing the template TexFontTemplates.comic_sans will\n    not compile if the Comic Sans Microsoft font is not installed.\n\n    To experiment, try to render the TexFontTemplateLibrary example scene:\n         ``manim path/to/manim/example_scenes/advanced_tex_fonts.py TexFontTemplateLibrary -p -ql``\n    \"\"\"\n\n    american_typewriter = americantypewriter\n    \"\"\"American Typewriter\"\"\"\n    antykwa = aptxgm\n    \"\"\"Antykwa Półtawskiego (TX Fonts for Greek and math symbols)\"\"\"\n    apple_chancery = applechancery\n    \"\"\"Apple Chancery\"\"\"\n    auriocus_kalligraphicus = aksg\n    \"\"\"Auriocus Kalligraphicus (Symbol Greek)\"\"\"\n    baskervald_adf_fourier = baskervaldadff\n    \"\"\"Baskervald ADF with Fourier\"\"\"\n    baskerville_it = italicbaskerville\n    \"\"\"Baskerville (Italic)\"\"\"\n    biolinum = biolinum\n    \"\"\"Biolinum\"\"\"\n    brushscriptx = brushscriptxpx\n    \"\"\"BrushScriptX-Italic (PX math and Greek)\"\"\"\n    chalkboard_se = chalkboardse\n    \"\"\"Chalkboard SE\"\"\"\n    chalkduster = chalkduster\n    \"\"\"Chalkduster\"\"\"\n    comfortaa = comfortaa\n    \"\"\"Comfortaa\"\"\"\n    comic_sans = comicsansms\n    \"\"\"Comic Sans MS\"\"\"\n    droid_sans = droidsans\n    \"\"\"Droid Sans\"\"\"\n    droid_sans_it = italicdroidsans\n    \"\"\"Droid Sans (Italic)\"\"\"\n    droid_serif = droidserif\n    \"\"\"Droid Serif\"\"\"\n    droid_serif_px_it = italicdroidserifpx\n    \"\"\"Droid Serif (PX math symbols) (Italic)\"\"\"\n    ecf_augie = ecfaugieeg\n    \"\"\"ECF Augie (Euler Greek)\"\"\"\n    ecf_jd = ecfjdtx\n    \"\"\"ECF JD (with TX fonts)\"\"\"\n    ecf_skeetch = ecfscmg\n    \"\"\"ECF Skeetch (CM Greek)\"\"\"\n    ecf_tall_paul = ecftallpaul\n    \"\"\"ECF Tall Paul (with Symbol font)\"\"\"\n    ecf_webster = ecfwebstertx\n    \"\"\"ECF Webster (with TX fonts)\"\"\"\n    electrum_adf = electrumadfcm\n    \"\"\"Electrum ADF (CM Greek)\"\"\"\n    epigrafica = epigrafica\n    \"\"\" Epigrafica \"\"\"\n    fourier_utopia = fufug\n    \"\"\"Fourier Utopia (Fourier upright Greek)\"\"\"\n    french_cursive = fceg\n    \"\"\"French Cursive (Euler Greek)\"\"\"\n    gfs_bodoni = gfsbodoni\n    \"\"\"GFS Bodoni\"\"\"\n    gfs_didot = italicgfsdidot\n    \"\"\"GFS Didot (Italic)\"\"\"\n    gfs_neoHellenic = gfsneohellenic\n    \"\"\"GFS NeoHellenic\"\"\"\n    gnu_freesans_tx = gnufstx\n    \"\"\"GNU FreeSerif (and TX fonts symbols)\"\"\"\n    gnu_freeserif_freesans = gnufsfs\n    \"\"\"GNU FreeSerif and FreeSans\"\"\"\n    helvetica_fourier_it = italichelveticaf\n    \"\"\"Helvetica with Fourier (Italic)\"\"\"\n    latin_modern_tw_it = italiclmtpcm\n    \"\"\"Latin Modern Typewriter Proportional (CM Greek) (Italic)\"\"\"\n    latin_modern_tw = lmtp\n    \"\"\"Latin Modern Typewriter Proportional\"\"\"\n    libertine = libertine\n    \"\"\"Libertine\"\"\"\n    libris_adf_fourier = librisadff\n    \"\"\"Libris ADF with Fourier\"\"\"\n    minion_pro_myriad_pro = mpmptx\n    \"\"\"Minion Pro and Myriad Pro (and TX fonts symbols)\"\"\"\n    minion_pro_tx = mptx\n    \"\"\"Minion Pro (and TX fonts symbols)\"\"\"\n    new_century_schoolbook = ncssg\n    \"\"\"New Century Schoolbook (Symbol Greek)\"\"\"\n    new_century_schoolbook_px = ncssgpxm\n    \"\"\"New Century Schoolbook (Symbol Greek, PX math symbols)\"\"\"\n    noteworthy_light = noteworthylight\n    \"\"\"Noteworthy Light\"\"\"\n    palatino = palatinosg\n    \"\"\"Palatino (Symbol Greek)\"\"\"\n    papyrus = papyrus\n    \"\"\"Papyrus\"\"\"\n    romande_adf_fourier_it = italicromandeadff\n    \"\"\"Romande ADF with Fourier (Italic)\"\"\"\n    slitex = slitexeg\n    \"\"\"SliTeX (Euler Greek)\"\"\"\n    times_fourier_it = italictimesf\n    \"\"\"Times with Fourier (Italic)\"\"\"\n    urw_avant_garde = urwagsg\n    \"\"\"URW Avant Garde (Symbol Greek)\"\"\"\n    urw_zapf_chancery = urwzccmg\n    \"\"\"URW Zapf Chancery (CM Greek)\"\"\"\n    venturis_adf_fourier_it = italicvanturisadff\n    \"\"\"Venturis ADF with Fourier (Italic)\"\"\"\n    verdana_it = italicverdana\n    \"\"\"Verdana (Italic)\"\"\"\n    vollkorn_fourier_it = italicvollkornf\n    \"\"\"Vollkorn with Fourier (Italic)\"\"\"\n    vollkorn = vollkorntx\n    \"\"\"Vollkorn (TX fonts for Greek and math symbols)\"\"\"\n    zapf_chancery = zapfchancery\n    \"\"\"Zapf Chancery\"\"\"\n"
  },
  {
    "path": "manim/utils/unit.py",
    "content": "\"\"\"Implement the Unit class.\"\"\"\n\nfrom __future__ import annotations\n\nimport numpy as np\n\nfrom .. import config, constants\nfrom ..typing import Vector3D\n\n__all__ = [\"Pixels\", \"Degrees\", \"Munits\", \"Percent\"]\n\n\nclass _PixelUnits:\n    def __mul__(self, val: float) -> float:\n        return val * config.frame_width / config.pixel_width\n\n    def __rmul__(self, val: float) -> float:\n        return val * config.frame_width / config.pixel_width\n\n\nclass Percent:\n    def __init__(self, axis: Vector3D) -> None:\n        if np.array_equal(axis, constants.X_AXIS):\n            self.length = config.frame_width\n        if np.array_equal(axis, constants.Y_AXIS):\n            self.length = config.frame_height\n        if np.array_equal(axis, constants.Z_AXIS):\n            raise NotImplementedError(\"length of Z axis is undefined\")\n\n    def __mul__(self, val: float) -> float:\n        return val / 100 * self.length\n\n    def __rmul__(self, val: float) -> float:\n        return val / 100 * self.length\n\n\nPixels = _PixelUnits()\nDegrees = constants.PI / 180\nMunits = 1\n"
  },
  {
    "path": "mypy.ini",
    "content": "[mypy]\nstrict = False\nfiles = manim\npython_version = 3.11\n; plugins = numpy.typing.mypy_plugin\nignore_errors = False\ncache_fine_grained = True\n\n# Apparently mypy cannot understand the difference between methods and callable attributes.\n#   See https://github.com/python/mypy/issues/2427#issuecomment-929688736\n#   and https://github.com/python/mypy/issues/2427#issuecomment-1419206807\ndisable_error_code = method-assign\n\n# Disallow Dynamic Typing\n# disallow_any_unimported = True\n# disallow_any_expr = False\n# disallow_any_decorated = True\n# disallow_any_explicit = True\n# disallow_any_generics = True\n# disallow_subclassing_any = True\n#\n# # Disallow Untyped Defs and Calls\ndisallow_untyped_calls = True\ndisallow_untyped_defs = True\ndisallow_incomplete_defs = True\n# check_untyped_defs = False\n# disallow_untyped_decorators = True\n#\n# # None and Optional Handling\n# implicit_optional = False\n# strict_optional = True\n#\n# # Configuring Warnings\n# warn_redundant_casts = True\nwarn_unused_ignores = True\nwarn_return_any = True\n# warn_unreachable = True\n#\n# # Strictness Flags\n# allow_untyped_globals = False\n# allow_redefinition = False\n# local_partial_types = False\n# strict_equality = True\n#\n# # Configuring Error Messages\n# show_error_context = True\n# show_column_numbers = True\n# show_error_codes = True\n# pretty = True\n# color_output = True\n# error_summary = True\n#\n# disable_recursive_aliases = True\n\n[mypy-manim._config.utils]\nignore_errors = True\n\n[mypy-manim.animation.animation]\nignore_errors = True\n\n[mypy-manim.animation.creation]\nignore_errors = True\n\n[mypy-manim.animation.speedmodifier]\nignore_errors = True\n\n[mypy-manim.animation.transform_matching_parts]\nignore_errors = True\n\n[mypy-manim.animation.transform]\nignore_errors = True\n\n[mypy-manim.animation.updaters.mobject_update_utils]\nignore_errors = True\n\n[mypy-manim.camera.mapping_camera]\nignore_errors = True\n\n[mypy-manim.mobject.graphing.coordinate_systems]\nignore_errors = True\n\n[mypy-manim.mobject.graph]\nignore_errors = True\n\n[mypy-manim.mobject.logo]\nignore_errors = True\n\n[mypy-manim.mobject.opengl.opengl_point_cloud_mobject]\nignore_errors = True\n\n[mypy-manim.mobject.opengl.opengl_surface]\nignore_errors = True\n\n[mypy-manim.mobject.opengl.opengl_vectorized_mobject]\nignore_errors = True\n\n[mypy-manim.mobject.table]\nignore_errors = True\n\n[mypy-manim.mobject.types.point_cloud_mobject]\nignore_errors = True\n\n[mypy-manim.mobject.types.vectorized_mobject]\nignore_errors = True\n\n[mypy-manim.mobject.vector_field]\nignore_errors = True\n\n[mypy-manim.renderer.shader_wrapper]\nignore_errors = True\n\n[mypy-manim.scene.three_d_scene]\nignore_errors = True\n\n[mypy-manim.utils.hashing]\nignore_errors = True\n\n\n\n# ---------------- Stubless imported Modules --------------------------\n\n# We should be able to create stubs for this or type hint it\n[mypy-manimpango]\nignore_missing_imports = True\n\n# Has stubs in 3.8\n[mypy-pydub]\nignore_missing_imports = True\n\n[mypy-matplotlib]\nignore_missing_imports = True\n\n[mypy-scipy.*]\nignore_missing_imports = True\n\n[mypy-networkx]\nignore_missing_imports = True\n\n[mypy-git]\nignore_missing_imports = True\n\n[mypy-moderngl.*]\nignore_missing_imports = True\n\n[mypy-moderngl_window.*]\nignore_missing_imports = True\n\n[mypy-dearpygui.*]\nignore_missing_imports = True\n\n[mypy-screeninfo]\nignore_missing_imports = True\n\n[mypy-IPython.*]\nignore_missing_imports = True\n\n[mypy-watchdog.*]\nignore_missing_imports = True\n\n[mypy-tqdm]\nignore_missing_imports = True\n\n[mypy-mapbox_earcut]\nignore_missing_imports = True\n\n[mypy-click_default_group]\nignore_missing_imports = True\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[project]\nname = \"manim\"\nversion = \"0.20.1\"\ndescription = \"Animation engine for explanatory math videos.\"\nauthors = [\n  {name = \"The Manim Community Developers\", email = \"contact@manim.community\"},\n  {name = \"Grant '3Blue1Brown' Sanderson\", email = \"grant@3blue1brown.com\"},\n]\nlicense = \"MIT\"\nreadme = \"README.md\"\nclassifiers = [\n    \"Development Status :: 4 - Beta\",\n    \"License :: OSI Approved :: MIT License\",\n    \"Topic :: Scientific/Engineering\",\n    \"Topic :: Multimedia :: Video\",\n    \"Topic :: Multimedia :: Graphics\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Programming Language :: Python :: 3.12\",\n    \"Programming Language :: Python :: 3.13\",\n    \"Programming Language :: Python :: 3.14\",\n    \"Natural Language :: English\",\n    ]\nrequires-python = \">=3.11\"\ndependencies = [\n    \"audioop-lts>=0.2.1 ; python_full_version >= '3.13'\",\n    \"av>=15.0\",\n    \"beautifulsoup4>=4.12\",\n    \"click>=8.0\",\n    \"cloup>=2.0.0\",\n    \"decorator>=4.3.2\",\n    \"isosurfaces>=0.1.1\",\n    \"manimpango>=0.6.1,<1.0.0\",\n    \"mapbox-earcut>=1.0.0\",\n    \"moderngl-window>=2.0.0\",\n    \"moderngl>=5.7.0,<6.0.0\",\n    \"networkx>=2.6\",\n    \"numpy>=2.1\",\n    \"pillow>=11.0\",\n    \"pycairo>=1.14,<2.0.0\",\n    \"pydub>=0.22.0\",\n    \"pygments>=2.17\",\n    \"rich>=12.0.0\",\n    \"scipy>=1.13.0\",\n    \"scipy>=1.15.0 ; python_full_version >= '3.13'\",\n    \"screeninfo>=0.7.0\",\n    \"skia-pathops>=0.9.0\",\n    \"srt>=3.0.0\",\n    \"svgelements>=1.9.0\",\n    \"tqdm>=4.21.0\",\n    \"typing-extensions>=4.12.0\",\n    \"watchdog>=2.0.0\",\n]\n\n\n[project.scripts]\n\"manim\" = \"manim.__main__:main\"\n\"manimce\" = \"manim.__main__:main\"\n\n[project.urls]\nrepository = \"https://github.com/manimcommunity/manim\"\ndocumentation = \"https://docs.manim.community/\"\nhomepage = \"https://www.manim.community/\"\n\"Bug Tracker\" = \"https://github.com/ManimCommunity/manim/issues\"\n\"Changelog\" = \"https://docs.manim.community/en/stable/changelog.html\"\n\"X / Twitter\" = \"https://x.com/manimcommunity\"\n\"Bluesky\" = \"https://bsky.app/profile/manim.community\"\n\"Discord\" = \"https://www.manim.community/discord/\"\n\n[project.optional-dependencies]\ngui = [\n    \"dearpygui>=1.0.0\",\n]\njupyterlab = [\n    \"jupyterlab>=4.3.4\",\n    \"notebook>=7.3.2\",\n]\n\n[dependency-groups]\ndev = [\n    \"furo>=2024.8.6\",\n    \"matplotlib>=3.9.4\",\n    \"myst-parser>=3.0.1\",\n    \"pre-commit>=4.1.0\",\n    \"pytest>=8.3.4\",\n    \"pytest-cov>=6.0.0\",\n    \"pytest-xdist>=2.2,<3.0\",\n    \"ruff>=0.14.7\",\n    \"sphinx>=7.4.7\",\n    \"sphinx-copybutton>=0.5.2\",\n    \"sphinx-design>=0.6.1\",\n    \"sphinx-reredirects>=0.1.5\",\n    \"sphinxcontrib-programoutput>=0.18\",\n    \"sphinxext-opengraph>=0.9.1\",\n    \"types-decorator>=5.1.8.20250121\",\n    \"types-pillow>=10.2.0.20240822\",\n    \"types-pygments>=2.19.0.20250107\",\n    \"psutil>=6.1.1\",\n    \"requests>=2.32.3\",\n]\n\n[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[tool.hatch.build]\ninclude = [\n  \"/manim\"\n]\nexclude = [\n  \"/docker\",\n  \"/logo\",\n  \"/scripts\",\n]\n\n[tool.pytest.ini_options]\nmarkers = \"slow: Mark the test as slow. Can be skipped with --skip_slow\"\naddopts = \"--no-cov-on-fail --cov=manim --cov-report xml --cov-report term -n auto --dist=loadfile --durations=0\"\n\n[tool.isort]\nprofile = \"black\"\n\n[tool.coverage.run]\nomit = [\"*tests*\"]\n\n[tool.coverage.report]\nexclude_lines = [\"pragma: no cover\", \"if TYPE_CHECKING:\"]\n\n[tool.ruff]\nline-length = 88\ntarget-version = \"py311\"\nextend-exclude = [\n  \".github\",\n  \".hg\",\n  \".env\",\n  \"env\",\n  \"build\",\n  \"buck-out\",\n  \"media\",\n]\nfix = true\n\n[tool.ruff.lint]\nselect = [\n  \"A\",\n  \"B\",\n  \"C4\",\n  \"D\",\n  \"E\",\n  \"F\",\n  \"I\",\n  \"NPY\",\n  \"PERF\",\n  \"PGH\",\n  \"PT\",\n  \"SIM\",\n  \"UP\",\n  \"W\",\n]\n\nignore = [\n  # (sub)module shadows standard library module\n  \"A005\",\n  # mutable argument defaults (too many changes)\n  \"B006\",\n  # No function calls in defaults\n  # ignored because np.array() and straight_path()\n  \"B008\",\n  # docstring ignores - mostly stylistic\n  \"D1\",\n  \"D203\",\n  \"D205\",\n  \"D212\",\n  \"D4\",\n  \"E111\",\n  \"E114\",\n  \"E117\",\n  \"E501\",\n  # due to the import * used in manim\n  \"F403\",\n  \"F405\",\n  \"PERF203\",  # try-except-in-loop\n  # Exception too broad (this would require lots of changes + re.escape) for little benefit\n  \"PT011\",\n  # as recommended by https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules\n  \"D206\",\n  \"D300\",\n]\n\n# Allow unused variables when underscore-prefixed.\ndummy-variable-rgx = \"^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$\"\n\n[tool.ruff.lint.per-file-ignores]\n\"tests/*\" = [\n  # flake8-builtins\n  \"A\",\n  # unused expression\n  \"B018\",\n  # unused variable\n  \"F841\",\n  # from __future__ import annotations\n  \"I002\",\n]\n\n\"example_scenes/*\" = [\n  \"I002\",\n]\n\n\"__init__.py\" = [\n  \"F401\",\n  \"F403\",\n]\n\n[tool.ruff.lint.flake8-pytest-style]\nfixture-parentheses = false\nmark-parentheses = false\n\n[tool.ruff.lint.pydocstyle]\nconvention = \"numpy\"\n\n[tool.ruff.format]\ndocstring-code-format = true\n"
  },
  {
    "path": "scripts/TEMPLATE.cff",
    "content": "# YAML 1.2\n---\nauthors:\n  -\n    name: \"The Manim Community Developers\"\ncff-version: \"1.2.0\"\ndate-released: <date_released>\nlicense: MIT\nmessage: \"We acknowledge the importance of good software to support research, and we note that research becomes more valuable when it is communicated effectively. To demonstrate the value of Manim, we ask that you cite Manim in your work.\"\ntitle: Manim – Mathematical Animation Framework\nurl: \"https://www.manim.community/\"\nversion: \"<version>\"\n...\n"
  },
  {
    "path": "scripts/extract_frames.py",
    "content": "from __future__ import annotations\n\nimport pathlib\nimport sys\n\nimport numpy as np\nfrom PIL import Image\n\n\ndef main():\n    if len(sys.argv) != 3:\n        print_usage()\n        sys.exit(1)\n    npz_file = sys.argv[1]\n    output_folder = pathlib.Path(sys.argv[2])\n    output_folder.mkdir(parents=True, exist_ok=True)\n\n    data = np.load(npz_file)\n    if \"frame_data\" not in data:\n        print(\"The given file did not have frame_data.\")\n        print(\"Are you sure this is from a Manim Graphical Unit Test?\")\n        sys.exit(2)\n    frames = data[\"frame_data\"]\n    for i, frame in enumerate(frames):\n        img = Image.fromarray(frame)\n        img.save(output_folder / f\"frame{i}.png\")\n    print(f\"Saved {len(frames)} frames to {output_folder}\")\n\n\ndef print_usage():\n    print(\"Manim Graphical Test Frame Extractor\")\n    print(\n        \"This tool outputs the frames of a Graphical Unit Test \"\n        \"stored within a .npz file, typically found under \"\n        r\"//tests/test_graphical_units/control_data\"\n    )\n    print()\n    print(\"usage:\")\n    print(\"python3 extract_frames.py npz_file output_directory\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/make_and_open_docs.py",
    "content": "from __future__ import annotations\n\nimport subprocess\nimport sys\nimport webbrowser\nfrom pathlib import Path\n\npath_makefile = Path(__file__).resolve().parents[1] / \"docs\"\nsubprocess.run([\"make\", \"html\"], cwd=path_makefile)\n\nwebsite = (path_makefile / \"build\" / \"html\" / \"index.html\").absolute().as_uri()\ntry:  # Allows you to pass a custom browser if you want.\n    webbrowser.get(sys.argv[1]).open_new_tab(f\"{website}\")\nexcept IndexError:\n    webbrowser.open_new_tab(f\"{website}\")\n"
  },
  {
    "path": "scripts/release.py",
    "content": "#!/usr/bin/env python3\n\"\"\"\nRelease management tools for Manim.\n\nThis script provides commands for preparing and managing Manim releases:\n- Generate changelogs from GitHub's release notes API\n- Update CITATION.cff with new version information\n- Fetch existing release notes for documentation\n\nUsage:\n    # Generate changelog for an upcoming release\n    uv run python scripts/release.py changelog --base v0.19.0 --version 0.20.0\n\n    # Also update CITATION.cff at the same time\n    uv run python scripts/release.py changelog --base v0.19.0 --version 0.20.0 --update-citation\n\n    # Update only CITATION.cff\n    uv run python scripts/release.py citation --version 0.20.0\n\n    # Fetch existing release changelogs for documentation\n    uv run python scripts/release.py fetch-releases\n\nRequirements:\n    - gh CLI installed and authenticated\n    - Python 3.11+\n\"\"\"\n\nfrom __future__ import annotations\n\nimport re\nimport subprocess\nimport sys\nfrom datetime import datetime\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING\n\nimport click\n\nif TYPE_CHECKING:\n    from collections.abc import Sequence\n\n# =============================================================================\n# Constants\n# =============================================================================\n\nREPO = \"manimcommunity/manim\"\n\nSCRIPT_DIR = Path(__file__).resolve().parent\nREPO_ROOT = SCRIPT_DIR.parent\nCHANGELOG_DIR = REPO_ROOT / \"docs\" / \"source\" / \"changelog\"\nCITATION_TEMPLATE = SCRIPT_DIR / \"TEMPLATE.cff\"\nCITATION_FILE = REPO_ROOT / \"CITATION.cff\"\n\n# Minimum version for fetching historical releases\nDEFAULT_MIN_VERSION = \"0.18.0\"\n\n\n# =============================================================================\n# GitHub CLI Helpers\n# =============================================================================\n\n\ndef run_gh(\n    args: Sequence[str],\n    *,\n    check: bool = True,\n    suppress_errors: bool = False,\n) -> subprocess.CompletedProcess[str]:\n    \"\"\"\n    Run a gh CLI command.\n\n    Args:\n        args: Arguments to pass to gh\n        check: If True, raise on non-zero exit\n        suppress_errors: If True, don't print errors to stderr\n\n    Returns:\n        CompletedProcess with stdout/stderr\n    \"\"\"\n    result = subprocess.run(\n        [\"gh\", *args],\n        capture_output=True,\n        text=True,\n    )\n    if (\n        result.returncode != 0\n        and not suppress_errors\n        and \"not found\" not in result.stderr.lower()\n    ):\n        click.echo(f\"gh error: {result.stderr}\", err=True)\n    if check and result.returncode != 0:\n        raise click.ClickException(f\"gh command failed: gh {' '.join(args)}\")\n    return result\n\n\ndef get_release_tags() -> list[str]:\n    \"\"\"Get all published release tags from GitHub, newest first.\"\"\"\n    result = run_gh(\n        [\"release\", \"list\", \"--repo\", REPO, \"--limit\", \"100\", \"--json\", \"tagName\"],\n        check=False,\n    )\n    if result.returncode != 0 or not result.stdout.strip():\n        return []\n\n    import json\n\n    try:\n        data = json.loads(result.stdout)\n        return [item[\"tagName\"] for item in data]\n    except (json.JSONDecodeError, KeyError):\n        return []\n\n\ndef get_release_body(tag: str) -> str | None:\n    \"\"\"Get the release body for a published release.\"\"\"\n    result = run_gh(\n        [\"release\", \"view\", tag, \"--repo\", REPO, \"--json\", \"body\", \"--jq\", \".body\"],\n        check=False,\n        suppress_errors=True,\n    )\n    if result.returncode != 0:\n        return None\n    return result.stdout.strip() or None\n\n\ndef get_release_date(tag: str) -> str | None:\n    \"\"\"Get the release date formatted as 'Month DD, YYYY'.\"\"\"\n    result = run_gh(\n        [\n            \"release\",\n            \"view\",\n            tag,\n            \"--repo\",\n            REPO,\n            \"--json\",\n            \"createdAt\",\n            \"--jq\",\n            \".createdAt\",\n        ],\n        check=False,\n    )\n    if result.returncode != 0:\n        return None\n\n    date_str = result.stdout.strip().strip('\"')\n    try:\n        dt = datetime.fromisoformat(date_str.replace(\"Z\", \"+00:00\"))\n        return dt.strftime(\"%B %d, %Y\")\n    except ValueError:\n        return None\n\n\ndef generate_release_notes(head_tag: str, base_tag: str) -> str:\n    \"\"\"\n    Generate release notes using GitHub's API.\n\n    This respects .github/release.yml for PR categorization.\n    \"\"\"\n    result = run_gh(\n        [\n            \"api\",\n            f\"repos/{REPO}/releases/generate-notes\",\n            \"--field\",\n            f\"tag_name={head_tag}\",\n            \"--field\",\n            f\"previous_tag_name={base_tag}\",\n            \"--jq\",\n            \".body\",\n        ]\n    )\n    body = result.stdout.strip()\n    if not body:\n        raise click.ClickException(\"GitHub API returned empty release notes\")\n    return body\n\n\n# =============================================================================\n# Version Utilities\n# =============================================================================\n\n\ndef normalize_tag(tag: str) -> str:\n    \"\"\"Ensure tag has 'v' prefix.\"\"\"\n    return tag if tag.startswith(\"v\") else f\"v{tag}\"\n\n\ndef version_from_tag(tag: str) -> str:\n    \"\"\"Extract version from tag (e.g., 'v0.18.0' -> '0.18.0').\"\"\"\n    return tag[1:] if tag.startswith(\"v\") else tag\n\n\ndef parse_version(version: str) -> tuple[int, ...]:\n    \"\"\"Parse version string into comparable tuple.\"\"\"\n    # Handle post-releases like '0.18.0.post0'\n    version = version.replace(\".post\", \"-post\")\n    parts = []\n    for part in version.replace(\"-\", \".\").split(\".\"):\n        try:\n            parts.append(int(part))\n        except ValueError:\n            continue\n    # Pad to at least 3 components\n    while len(parts) < 3:\n        parts.append(0)\n    return tuple(parts)\n\n\ndef version_gte(version: str, min_version: str) -> bool:\n    \"\"\"Check if version >= min_version.\"\"\"\n    return parse_version(version) >= parse_version(min_version)\n\n\n# =============================================================================\n# Markdown Conversion\n# =============================================================================\n\n\ndef convert_to_myst(body: str) -> str:\n    \"\"\"\n    Convert GitHub markdown to MyST format.\n\n    - PR URLs -> {pr}`NUMBER`\n    - Issue URLs -> {issue}`NUMBER`\n    - @mentions -> {user}`USERNAME`\n    - Strips HTML comments\n    - Ensures proper list spacing\n    \"\"\"\n    lines = body.split(\"\\n\")\n    result = []\n    prev_bullet = False\n\n    for line in lines:\n        # Skip HTML comments\n        if line.strip().startswith(\"<!--\") and line.strip().endswith(\"-->\"):\n            continue\n\n        # Convert URLs to extlinks\n        line = re.sub(\n            r\"https://github\\.com/ManimCommunity/manim/pull/(\\d+)\",\n            r\"{pr}`\\1`\",\n            line,\n        )\n        line = re.sub(\n            r\"https://github\\.com/ManimCommunity/manim/issues/(\\d+)\",\n            r\"{issue}`\\1`\",\n            line,\n        )\n        line = re.sub(r\"@([a-zA-Z0-9_-]+)\", r\"{user}`\\1`\", line)\n\n        if line.startswith(\"**Full Changelog**:\"):\n            _, url = line.split(\":\", 1)\n            url = url.strip().replace(\"vmain\", \"main\")\n            line = f\"**Full Changelog**: [Compare view]({url})\"\n\n        # Handle list spacing\n        is_bullet = line.strip().startswith(\"*\") and not line.strip().startswith(\"**\")\n        if prev_bullet and not is_bullet and line.strip():\n            result.append(\"\")\n\n        result.append(line)\n        prev_bullet = is_bullet\n\n    return \"\\n\".join(result)\n\n\ndef format_changelog(\n    version: str,\n    body: str,\n    date: str | None = None,\n    title: str | None = None,\n) -> str:\n    \"\"\"Create changelog file content with MyST frontmatter.\"\"\"\n    title = title or f\"v{version}\"\n    body = convert_to_myst(body)\n    date_section = f\"Date\\n: {date}\\n\" if date else \"\"\n\n    return f\"\"\"---\nshort-title: {title}\ndescription: Changelog for {title}\n---\n\n# {title}\n\n{date_section}\n{body}\n\"\"\"\n\n\n# =============================================================================\n# File Operations\n# =============================================================================\n\n\ndef get_existing_versions() -> set[str]:\n    \"\"\"Get versions that already have changelog files.\"\"\"\n    if not CHANGELOG_DIR.exists():\n        return set()\n    return {\n        f.stem.replace(\"-changelog\", \"\") for f in CHANGELOG_DIR.glob(\"*-changelog.*\")\n    }\n\n\ndef save_changelog(version: str, content: str) -> Path:\n    \"\"\"Save changelog and return filepath.\"\"\"\n    filepath = CHANGELOG_DIR / f\"{version}-changelog.md\"\n    filepath.write_text(content)\n    return filepath\n\n\ndef update_citation(version: str, date: str | None = None) -> Path:\n    \"\"\"Update CITATION.cff from template.\"\"\"\n    if not CITATION_TEMPLATE.exists():\n        raise click.ClickException(f\"Citation template not found: {CITATION_TEMPLATE}\")\n\n    date = date or datetime.now().strftime(\"%Y-%m-%d\")\n    version_tag = normalize_tag(version)\n\n    content = CITATION_TEMPLATE.read_text()\n    content = content.replace(\"<version>\", version_tag)\n    content = content.replace(\"<date_released>\", date)\n\n    CITATION_FILE.write_text(content)\n    return CITATION_FILE\n\n\n# =============================================================================\n# CLI Commands\n# =============================================================================\n\n\n@click.group()\n@click.option(\n    \"--dry-run\", is_flag=True, help=\"Show what would be done without making changes\"\n)\n@click.pass_context\ndef cli(ctx: click.Context, dry_run: bool) -> None:\n    \"\"\"Release management tools for Manim.\"\"\"\n    ctx.ensure_object(dict)\n    ctx.obj[\"dry_run\"] = dry_run\n\n\n@cli.command()\n@click.option(\"--base\", required=True, help=\"Base tag for comparison (e.g., v0.19.0)\")\n@click.option(\n    \"--version\", \"version\", required=True, help=\"New version number (e.g., 0.20.0)\"\n)\n@click.option(\"--head\", default=\"main\", help=\"Head ref for comparison (default: main)\")\n@click.option(\"--title\", help=\"Custom changelog title (default: vX.Y.Z)\")\n@click.option(\n    \"--update-citation\",\n    \"also_update_citation\",\n    is_flag=True,\n    help=\"Also update CITATION.cff\",\n)\n@click.pass_context\ndef changelog(\n    ctx: click.Context,\n    base: str,\n    version: str,\n    head: str,\n    title: str | None,\n    also_update_citation: bool,\n) -> None:\n    \"\"\"Generate changelog for an upcoming release.\n\n    Uses GitHub's release notes API with .github/release.yml categorization.\n    \"\"\"\n    dry_run = ctx.obj[\"dry_run\"]\n    base_tag = normalize_tag(base)\n    head_tag = normalize_tag(head) if head != \"main\" else normalize_tag(version)\n\n    click.echo(f\"Generating changelog for v{version}...\")\n    click.echo(f\"  Comparing: {base_tag} → {head}\")\n\n    body = generate_release_notes(head_tag, base_tag)\n    date = datetime.now().strftime(\"%B %d, %Y\")\n    content = format_changelog(version, body, date=date, title=title)\n\n    if dry_run:\n        click.echo()\n        click.secho(\"[DRY RUN]\", fg=\"yellow\", bold=True)\n        click.echo(f\"  Would save: {CHANGELOG_DIR / f'{version}-changelog.md'}\")\n        if also_update_citation:\n            click.echo(f\"  Would update: {CITATION_FILE}\")\n        click.echo()\n        click.echo(\"--- Generated changelog ---\")\n        click.echo(content)\n        return\n\n    filepath = save_changelog(version, content)\n    click.secho(f\"  ✓ Saved: {filepath}\", fg=\"green\")\n\n    if also_update_citation:\n        citation_path = update_citation(version)\n        click.secho(f\"  ✓ Updated: {citation_path}\", fg=\"green\")\n\n    click.echo()\n    click.echo(\"Next steps:\")\n    click.echo(\"  • Review and edit the changelog as needed\")\n    click.echo(\"  • Update docs/source/changelog.rst to include the new file\")\n\n\n@cli.command()\n@click.option(\n    \"--version\", \"version\", required=True, help=\"Version number (e.g., 0.20.0)\"\n)\n@click.option(\"--date\", help=\"Release date as YYYY-MM-DD (default: today)\")\n@click.pass_context\ndef citation(ctx: click.Context, version: str, date: str | None) -> None:\n    \"\"\"Update CITATION.cff for a release.\"\"\"\n    dry_run = ctx.obj[\"dry_run\"]\n    display_date = date or datetime.now().strftime(\"%Y-%m-%d\")\n\n    if dry_run:\n        click.secho(\"[DRY RUN]\", fg=\"yellow\", bold=True)\n        click.echo(f\"  Would update: {CITATION_FILE}\")\n        click.echo(f\"  Version: v{version}\")\n        click.echo(f\"  Date: {display_date}\")\n        return\n\n    filepath = update_citation(version, date)\n    click.secho(f\"✓ Updated: {filepath}\", fg=\"green\")\n    click.echo(f\"  Version: v{version}\")\n    click.echo(f\"  Date: {display_date}\")\n\n\n@cli.command(\"fetch-releases\")\n@click.option(\"--tag\", help=\"Fetch a specific release tag\")\n@click.option(\n    \"--min-version\",\n    default=DEFAULT_MIN_VERSION,\n    help=f\"Minimum version to fetch (default: {DEFAULT_MIN_VERSION})\",\n)\n@click.option(\"--force\", is_flag=True, help=\"Overwrite existing changelog files\")\n@click.pass_context\ndef fetch_releases(\n    ctx: click.Context,\n    tag: str | None,\n    min_version: str,\n    force: bool,\n) -> None:\n    \"\"\"Fetch existing release changelogs from GitHub.\n\n    Converts GitHub release notes to documentation-ready MyST markdown.\n    \"\"\"\n    dry_run = ctx.obj[\"dry_run\"]\n    existing = get_existing_versions()\n\n    # Single tag mode\n    if tag:\n        tag = normalize_tag(tag)\n        version = version_from_tag(tag)\n\n        if version in existing and not force:\n            click.echo(\n                f\"Changelog for {version} already exists. Use --force to overwrite.\"\n            )\n            return\n\n        if dry_run:\n            click.secho(\"[DRY RUN]\", fg=\"yellow\", bold=True)\n            click.echo(f\"  Would fetch: {version}\")\n            return\n\n        _fetch_single_release(tag, version)\n        return\n\n    # Batch mode\n    click.echo(f\"Existing versions: {', '.join(sorted(existing)) or '(none)'}\")\n    click.echo(\"Fetching release list...\")\n\n    tags = get_release_tags()\n    click.echo(f\"Found {len(tags)} releases\")\n\n    fetched = 0\n    prev_tag = None\n\n    for tag in reversed(tags):\n        version = version_from_tag(tag)\n\n        if not version_gte(version, min_version):\n            prev_tag = tag\n            continue\n\n        if version in existing and not force:\n            click.echo(f\"  Skipping {version} (exists)\")\n            prev_tag = tag\n            continue\n\n        if dry_run:\n            click.echo(f\"  [DRY RUN] Would fetch {version}\")\n            fetched += 1\n        else:\n            if _fetch_single_release(tag, version, prev_tag):\n                existing.add(version)\n                fetched += 1\n\n        prev_tag = tag\n\n    click.echo()\n    click.echo(f\"Processed {fetched} changelog(s)\")\n\n    if fetched > 0 and not dry_run:\n        click.echo()\n        click.echo(\"Next steps:\")\n        click.echo(\"  • Update docs/source/changelog.rst to include new files\")\n\n\ndef _fetch_single_release(tag: str, version: str, prev_tag: str | None = None) -> bool:\n    \"\"\"Fetch and save a single release changelog.\"\"\"\n    click.echo(f\"  Fetching {version}...\")\n\n    body = get_release_body(tag)\n\n    if not body and prev_tag:\n        click.echo(f\"    No body, generating from {prev_tag}...\")\n        try:\n            body = generate_release_notes(tag, prev_tag)\n        except click.ClickException:\n            body = None\n\n    if not body:\n        click.secho(f\"    ✗ Could not get release notes for {tag}\", fg=\"red\", err=True)\n        return False\n\n    date = get_release_date(tag)\n    content = format_changelog(version, body, date=date)\n\n    filepath = save_changelog(version, content)\n    click.secho(f\"    ✓ Saved: {filepath}\", fg=\"green\")\n    return True\n\n\n# =============================================================================\n# Entry Point\n# =============================================================================\n\n\ndef main() -> None:\n    \"\"\"Entry point.\"\"\"\n    cli()\n\n\nif __name__ == \"__main__\":\n    sys.exit(main() or 0)\n"
  },
  {
    "path": "scripts/template_docsting_with_example.py",
    "content": "# see more documentation guidelines online here: https://github.com/ManimCommunity/manim/wiki/Documentation-guidelines-(WIP)\n\n\nfrom __future__ import annotations\n\n\nclass SomeClass:\n    \"\"\"A one line description of the Class.\n\n    A short paragraph providing more details.\n\n    Extended Summary\n\n    Parameters\n    ----------\n    scale_factor\n        The factor used for scaling.\n\n    Returns\n    -------\n    :class:`~.VMobject`\n        Returns the modified :class:`~.VMobject`.\n\n    Tests\n    -----\n\n    Yields\n    -------\n\n    Receives\n    ----------\n\n    Other Parameters\n    -----------------\n\n    Raises\n    ------\n    :class:`TypeError`\n        If one element of the list is not an instance of VMobject\n\n    Warns\n    -----\n\n    Warnings\n    --------\n\n    Notes\n    -----\n\n    Examples\n    --------\n    .. manim:: AddTextLetterByLetterScene\n        :save_last_frame:\n\n        class AddTextLetterByLetterScene(Scene):\n            def construct(self):\n                t = Text(\"Hello World word by word\")\n                self.play(AddTextWordByWord(t))\n\n\n\n    See Also\n    --------\n    :class:`Create`, :class:`~.ShowPassingFlash`\n\n    References\n    ----------\n\n\n    Other useful directives:\n\n    .. tip::\n\n        This is currently only possible for class:`~.Text` and not for class:`~.MathTex`.\n\n    .. note::\n\n        This is something to note.\n\n    \"\"\"\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/assert_utils.py",
    "content": "from __future__ import annotations\n\nimport os\nfrom pathlib import Path\nfrom pprint import pformat\n\n\ndef assert_file_exists(filepath: str | os.PathLike) -> None:\n    \"\"\"Assert that filepath points to an existing file. Print all the elements (files and dir) of the parent dir of the given filepath.\n\n    This is mostly to have better assert message than using a raw assert filepath.is_file().\n\n    Parameters\n    ----------\n    filepath\n        Filepath to check.\n\n    Raises\n    ------\n    AssertionError\n        If filepath does not point to a file (if the file does not exist or it's a dir).\n    \"\"\"\n    path = Path(filepath)\n    if not path.is_file():\n        elems = pformat([path.name for path in path.parent.iterdir()])\n        message = f\"{path.absolute()} is not a file. Other elements in the parent directory are \\n{elems}\"\n        raise AssertionError(message)\n\n\ndef assert_dir_exists(dirpath: str | os.PathLike) -> None:\n    \"\"\"Assert that directory exists.\n\n    Parameters\n    ----------\n    dirpath\n        Path to directory to check.\n\n    Raises\n    ------\n    AssertionError\n        If dirpath does not point to a directory (if the file does exist or it's a file).\n    \"\"\"\n    path = Path(dirpath)\n    if not path.is_dir():\n        elems = pformat([path.name for path in list(path.parent.iterdir())])\n        message = f\"{path.absolute()} is not a directory. Other elements in the parent directory are \\n{elems}\"\n        raise AssertionError(message)\n\n\ndef assert_dir_filled(dirpath: str | os.PathLike) -> None:\n    \"\"\"Assert that directory exists and contains at least one file or directory (or file like objects like symlinks on Linux).\n\n    Parameters\n    ----------\n    dirpath\n        Path to directory to check.\n\n    Raises\n    ------\n    AssertionError\n        If dirpath does not point to a directory (if the file does exist or it's a file) or the directory is empty.\n    \"\"\"\n    if not any(Path(dirpath).iterdir()):\n        raise AssertionError(f\"{dirpath} is an empty directory.\")\n\n\ndef assert_file_not_exists(filepath: str | os.PathLike) -> None:\n    \"\"\"Assert that filepath does not point to an existing file. Print all the elements (files and dir) of the parent dir of the given filepath.\n\n    This is mostly to have better assert message than using a raw assert filepath.is_file().\n\n    Parameters\n    ----------\n    filepath\n        Filepath to check.\n\n    Raises\n    ------\n    AssertionError\n        If filepath does point to a file.\n    \"\"\"\n    path = Path(filepath)\n    if path.is_file():\n        elems = pformat([path.name for path in path.parent.iterdir()])\n        message = f\"{path.absolute()} is a file. Other elements in the parent directory are \\n{elems}\"\n        raise AssertionError(message)\n\n\ndef assert_dir_not_exists(dirpath: str | os.PathLike) -> None:\n    \"\"\"Assert that directory does not exist.\n\n    Parameters\n    ----------\n    dirpath\n        Path to directory to check.\n\n    Raises\n    ------\n    AssertionError\n        If dirpath points to a directory.\n    \"\"\"\n    path = Path(dirpath)\n    if path.is_dir():\n        elems = pformat([path.name for path in list(path.parent.iterdir())])\n        message = f\"{path.absolute()} is a directory. Other elements in the parent directory are \\n{elems}\"\n        raise AssertionError(message)\n\n\ndef assert_shallow_dict_compare(a: dict, b: dict, message_start: str) -> None:\n    \"\"\"Assert that Directories ``a`` and ``b`` are the same.\n\n    ``b`` is treated as the expected values that ``a`` shall abide by.\n    Print helpful error with custom message start.\n    \"\"\"\n    mismatch: list[str] = []\n\n    for b_key, b_value in b.items():\n        if b_key not in a:\n            mismatch.append(f\"Missing item {b_key}: {b_value}\")\n        elif b_value != a[b_key]:\n            mismatch.append(f\"For {b_key} got {a[b_key]}, expected {b_value}\")\n\n    for a_key, a_value in a.items():\n        if a_key not in b:\n            mismatch.append(f\"Extraneous item {a_key}: {a_value}\")\n\n    mismatch_str = \"\\n\".join(mismatch)\n    assert len(mismatch) == 0, f\"{message_start}\\n{mismatch_str}\"\n"
  },
  {
    "path": "tests/conftest.py",
    "content": "from __future__ import annotations\n\nimport logging\nimport sys\nfrom pathlib import Path\n\nimport cairo\nimport moderngl\nimport pytest\n\nimport manim\n\n\ndef pytest_report_header(config):\n    try:\n        ctx = moderngl.create_standalone_context()\n        info = ctx.info\n        ctx.release()\n    except Exception as e:\n        raise Exception(\"Error while creating moderngl context\") from e\n\n    return (\n        f\"\\nCairo Version: {cairo.cairo_version()}\",\n        \"\\nOpenGL information\",\n        \"------------------\",\n        f\"vendor: {info['GL_VENDOR'].strip()}\",\n        f\"renderer: {info['GL_RENDERER'].strip()}\",\n        f\"version: {info['GL_VERSION'].strip()}\\n\",\n    )\n\n\ndef pytest_addoption(parser):\n    parser.addoption(\n        \"--skip_slow\",\n        action=\"store_true\",\n        default=False,\n        help=\"Will skip all the slow marked tests. Slow tests are arbitrarily marked as such.\",\n    )\n    parser.addoption(\n        \"--show_diff\",\n        action=\"store_true\",\n        default=False,\n        help=\"Will show a visual comparison if a graphical unit test fails.\",\n    )\n    parser.addoption(\n        \"--set_test\",\n        action=\"store_true\",\n        default=False,\n        help=\"Will create the control data for EACH running tests. \",\n    )\n\n\ndef pytest_configure(config):\n    config.addinivalue_line(\"markers\", \"skip_end_to_end: mark test as end_to_end test\")\n\n\ndef pytest_collection_modifyitems(config, items):\n    if not config.getoption(\"--skip_slow\"):\n        return\n    else:\n        slow_skip = pytest.mark.skip(\n            reason=\"Slow test skipped due to --disable_slow flag.\",\n        )\n        for item in items:\n            if \"slow\" in item.keywords:\n                item.add_marker(slow_skip)\n\n\n@pytest.fixture(autouse=True)\ndef temp_media_dir(tmpdir, monkeypatch, request):\n    if isinstance(request.node, pytest.DoctestItem):\n        monkeypatch.chdir(tmpdir)\n        yield tmpdir\n    else:\n        with manim.tempconfig({\"media_dir\": str(tmpdir)}):\n            assert manim.config.media_dir == str(tmpdir)\n            yield tmpdir\n\n\n@pytest.fixture\ndef manim_caplog(caplog):\n    logger = logging.getLogger(\"manim\")\n    logger.propagate = True\n    caplog.set_level(logging.INFO, logger=\"manim\")\n    yield caplog\n    logger.propagate = False\n\n\n@pytest.fixture\ndef config():\n    saved = manim.config.copy()\n    manim.config.renderer = \"cairo\"\n    # we need to return the actual config so that tests\n    # using tempconfig pass\n    yield manim.config\n    manim.config.update(saved)\n\n\n@pytest.fixture\ndef dry_run(config):\n    config.dry_run = True\n\n\n@pytest.fixture(scope=\"session\")\ndef python_version():\n    # use the same python executable as it is running currently\n    # rather than randomly calling using python or python3, which\n    # may create problems.\n    return sys.executable\n\n\n@pytest.fixture\ndef reset_cfg_file():\n    cfgfilepath = Path(__file__).parent / \"test_cli\" / \"manim.cfg\"\n    original = cfgfilepath.read_text()\n    yield\n    cfgfilepath.write_text(original)\n\n\n@pytest.fixture\ndef using_opengl_renderer(config):\n    \"\"\"Standard fixture for running with opengl that makes tests use a standard_config.cfg with a temp dir.\"\"\"\n    config.renderer = \"opengl\"\n    yield\n    # as a special case needed to manually revert back to cairo\n    # due to side effects of setting the renderer\n    config.renderer = \"cairo\"\n"
  },
  {
    "path": "tests/control_data/logs_data/BasicSceneLoggingTest.txt",
    "content": "{\"levelname\": \"INFO\", \"module\": \"logger_utils\", \"message\": \"Log file will be saved in <>\"}\n{\"levelname\": \"DEBUG\", \"module\": \"hashing\", \"message\": \"Hashing ...\"}\n{\"levelname\": \"DEBUG\", \"module\": \"hashing\", \"message\": \"Hashing done in <> s.\"}\n{\"levelname\": \"DEBUG\", \"module\": \"hashing\", \"message\": \"Hash generated :  <>\"}\n{\"levelname\": \"DEBUG\", \"module\": \"cairo_renderer\", \"message\": \"List of the first few animation hashes of the scene: <>\"}\n{\"levelname\": \"INFO\", \"module\": \"scene_file_writer\", \"message\": \"Animation 0 : Partial movie file written in <>\"}\n{\"levelname\": \"INFO\", \"module\": \"scene_file_writer\", \"message\": \"Combining to Movie file.\"}\n{\"levelname\": \"DEBUG\", \"module\": \"scene_file_writer\", \"message\": \"Partial movie files to combine (1 files): <>\"}\n{\"levelname\": \"INFO\", \"module\": \"scene_file_writer\", \"message\": \"\\nFile ready at <>\\n\"}\n{\"levelname\": \"INFO\", \"module\": \"scene\", \"message\": \"Rendered SquareToCircle\\nPlayed 1 animations\"}\n"
  },
  {
    "path": "tests/control_data/logs_data/bad_tex_scene_BadTex.txt",
    "content": "{\"levelname\": \"INFO\", \"module\": \"logger_utils\", \"message\": \"Log file will be saved in <>\"}\n{\"levelname\": \"INFO\", \"module\": \"tex_file_writing\", \"message\": \"Writing <> to <>\"}\n{\"levelname\": \"ERROR\", \"module\": \"tex_file_writing\", \"message\": \"LaTeX compilation error: LaTeX Error: File `notapackage.sty' not found.\\n\"}\n{\"levelname\": \"ERROR\", \"module\": \"tex_file_writing\", \"message\": \"Context of error: \\n\\\\documentclass[preview]{standalone}\\n-> \\\\usepackage{notapackage}\\n\\\\begin{document}\\n\\\\begin{center}\\n\\\\special{dvisvgm:raw <g id='unique000'>}\\\\frac{1}{0}\\\\special{dvisvgm:raw </g>}\\n\"}\n{\"levelname\": \"INFO\", \"module\": \"tex_file_writing\", \"message\": \"You do not have package notapackage.sty installed.\"}\n{\"levelname\": \"INFO\", \"module\": \"tex_file_writing\", \"message\": \"Install notapackage.sty it using your LaTeX package manager, or check for typos.\"}\n{\"levelname\": \"ERROR\", \"module\": \"tex_file_writing\", \"message\": \"LaTeX compilation error: Emergency stop.\\n\"}\n{\"levelname\": \"ERROR\", \"module\": \"tex_file_writing\", \"message\": \"Context of error: \\n\\\\documentclass[preview]{standalone}\\n-> \\\\usepackage{notapackage}\\n\\\\begin{document}\\n\\\\begin{center}\\n\\\\special{dvisvgm:raw <g id='unique000'>}\\\\frac{1}{0}\\\\special{dvisvgm:raw </g>}\\n\"}\n"
  },
  {
    "path": "tests/control_data/videos_data/InputFileViaCfg.json",
    "content": "{\n    \"name\": \"InputFileViaCfg\",\n    \"movie_metadata\": {\n        \"codec_name\": \"h264\",\n        \"width\": 854,\n        \"height\": 480,\n        \"avg_frame_rate\": \"15/1\",\n        \"duration\": \"1.000000\",\n        \"nb_frames\": \"15\",\n        \"pix_fmt\": \"yuv420p\"\n    },\n    \"section_dir_layout\": [],\n    \"section_index\": []\n}\n"
  },
  {
    "path": "tests/control_data/videos_data/SceneWithDisabledSections.json",
    "content": "{\n    \"name\": \"SceneWithDisabledSections\",\n    \"movie_metadata\": {\n        \"codec_name\": \"h264\",\n        \"width\": 854,\n        \"height\": 480,\n        \"avg_frame_rate\": \"15/1\",\n        \"duration\": \"1.000000\",\n        \"nb_frames\": \"15\",\n        \"pix_fmt\": \"yuv420p\"\n    },\n    \"section_dir_layout\": [],\n    \"section_index\": []\n}\n"
  },
  {
    "path": "tests/control_data/videos_data/SceneWithEnabledSections.json",
    "content": "{\n    \"name\": \"SceneWithEnabledSections\",\n    \"movie_metadata\": {\n        \"codec_name\": \"h264\",\n        \"width\": 854,\n        \"height\": 480,\n        \"avg_frame_rate\": \"15/1\",\n        \"duration\": \"1.000000\",\n        \"nb_frames\": \"15\",\n        \"pix_fmt\": \"yuv420p\"\n    },\n    \"section_dir_layout\": [\n        \"SquareToCircle.json\",\n        \"SquareToCircle_0000_autocreated.mp4\",\n        \".\"\n    ],\n    \"section_index\": [\n        {\n            \"name\": \"autocreated\",\n            \"type\": \"default.normal\",\n            \"video\": \"SquareToCircle_0000_autocreated.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"1.000000\",\n            \"nb_frames\": \"15\",\n            \"pix_fmt\": \"yuv420p\"\n        }\n    ]\n}\n"
  },
  {
    "path": "tests/control_data/videos_data/SceneWithMultipleCallsWithNFlag.json",
    "content": "{\n    \"name\": \"SceneWithMultipleCallsWithNFlag\",\n    \"movie_metadata\": {\n        \"codec_name\": \"h264\",\n        \"width\": 854,\n        \"height\": 480,\n        \"avg_frame_rate\": \"15/1\",\n        \"duration\": \"4.000000\",\n        \"nb_frames\": \"60\",\n        \"pix_fmt\": \"yuv420p\"\n    },\n    \"section_dir_layout\": [],\n    \"section_index\": []\n}\n"
  },
  {
    "path": "tests/control_data/videos_data/SceneWithMultiplePlayCallsWithNFlag.json",
    "content": "{\n    \"name\": \"SceneWithMultiplePlayCallsWithNFlag\",\n    \"movie_metadata\": {\n        \"codec_name\": \"h264\",\n        \"width\": 854,\n        \"height\": 480,\n        \"avg_frame_rate\": \"15/1\",\n        \"duration\": \"7.000000\",\n        \"nb_frames\": \"105\",\n        \"pix_fmt\": \"yuv420p\"\n    },\n    \"section_dir_layout\": [],\n    \"section_index\": []\n}\n"
  },
  {
    "path": "tests/control_data/videos_data/SceneWithMultipleWaitCallsWithNFlag.json",
    "content": "{\n    \"name\": \"SceneWithMultipleWaitCallsWithNFlag\",\n    \"movie_metadata\": {\n        \"codec_name\": \"h264\",\n        \"width\": 854,\n        \"height\": 480,\n        \"avg_frame_rate\": \"15/1\",\n        \"duration\": \"5.000000\",\n        \"nb_frames\": \"75\",\n        \"pix_fmt\": \"yuv420p\"\n    },\n    \"section_dir_layout\": [],\n    \"section_index\": []\n}\n"
  },
  {
    "path": "tests/control_data/videos_data/SceneWithSections.json",
    "content": "{\n    \"name\": \"SceneWithSections\",\n    \"movie_metadata\": {\n        \"codec_name\": \"h264\",\n        \"width\": 854,\n        \"height\": 480,\n        \"avg_frame_rate\": \"15/1\",\n        \"duration\": \"7.000000\",\n        \"nb_frames\": \"105\",\n        \"pix_fmt\": \"yuv420p\"\n    },\n    \"section_dir_layout\": [\n        \"SceneWithSections.json\",\n        \"SceneWithSections_0004_unnamed.mp4\",\n        \"SceneWithSections_0003_Prepare For Unforeseen Consequences..mp4\",\n        \"SceneWithSections_0002_test.mp4\",\n        \"SceneWithSections_0001_unnamed.mp4\",\n        \"SceneWithSections_0000_autocreated.mp4\",\n        \".\"\n    ],\n    \"section_index\": [\n        {\n            \"name\": \"autocreated\",\n            \"type\": \"default.normal\",\n            \"video\": \"SceneWithSections_0000_autocreated.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"1.000000\",\n            \"nb_frames\": \"15\",\n            \"pix_fmt\": \"yuv420p\"\n        },\n        {\n            \"name\": \"unnamed\",\n            \"type\": \"default.normal\",\n            \"video\": \"SceneWithSections_0001_unnamed.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"2.000000\",\n            \"nb_frames\": \"30\",\n            \"pix_fmt\": \"yuv420p\"\n        },\n        {\n            \"name\": \"test\",\n            \"type\": \"default.normal\",\n            \"video\": \"SceneWithSections_0002_test.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"1.000000\",\n            \"nb_frames\": \"15\",\n            \"pix_fmt\": \"yuv420p\"\n        },\n        {\n            \"name\": \"Prepare For Unforeseen Consequences.\",\n            \"type\": \"default.normal\",\n            \"video\": \"SceneWithSections_0003_Prepare For Unforeseen Consequences..mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"2.000000\",\n            \"nb_frames\": \"30\",\n            \"pix_fmt\": \"yuv420p\"\n        },\n        {\n            \"name\": \"unnamed\",\n            \"type\": \"presentation.skip\",\n            \"video\": \"SceneWithSections_0004_unnamed.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"1.000000\",\n            \"nb_frames\": \"15\",\n            \"pix_fmt\": \"yuv420p\"\n        }\n    ]\n}\n"
  },
  {
    "path": "tests/control_data/videos_data/SceneWithSkipAnimations.json",
    "content": "{\n    \"name\": \"SceneWithSkipAnimations\",\n    \"movie_metadata\": {\n        \"codec_name\": \"h264\",\n        \"width\": 854,\n        \"height\": 480,\n        \"avg_frame_rate\": \"15/1\",\n        \"duration\": \"6.000000\",\n        \"nb_frames\": \"90\",\n        \"pix_fmt\": \"yuv420p\"\n    },\n    \"section_dir_layout\": [\n        \"ElaborateSceneWithSections.json\",\n        \"ElaborateSceneWithSections_0003_fade out.mp4\",\n        \"ElaborateSceneWithSections_0001_transform to circle.mp4\",\n        \"ElaborateSceneWithSections_0000_create square.mp4\",\n        \".\"\n    ],\n    \"section_index\": [\n        {\n            \"name\": \"create square\",\n            \"type\": \"default.normal\",\n            \"video\": \"ElaborateSceneWithSections_0000_create square.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"2.000000\",\n            \"nb_frames\": \"30\",\n            \"pix_fmt\": \"yuv420p\"\n        },\n        {\n            \"name\": \"transform to circle\",\n            \"type\": \"default.normal\",\n            \"video\": \"ElaborateSceneWithSections_0001_transform to circle.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"2.000000\",\n            \"nb_frames\": \"30\",\n            \"pix_fmt\": \"yuv420p\"\n        },\n        {\n            \"name\": \"fade out\",\n            \"type\": \"default.normal\",\n            \"video\": \"ElaborateSceneWithSections_0003_fade out.mp4\",\n            \"codec_name\": \"h264\",\n            \"width\": 854,\n            \"height\": 480,\n            \"avg_frame_rate\": \"15/1\",\n            \"duration\": \"2.000000\",\n            \"nb_frames\": \"30\",\n            \"pix_fmt\": \"yuv420p\"\n        }\n    ]\n}\n"
  },
  {
    "path": "tests/control_data/videos_data/SquareToCircleWithDefaultValues.json",
    "content": "{\n    \"name\": \"SquareToCircleWithDefaultValues\",\n    \"movie_metadata\": {\n        \"codec_name\": \"h264\",\n        \"width\": 1920,\n        \"height\": 1080,\n        \"avg_frame_rate\": \"60/1\",\n        \"duration\": \"1.000000\",\n        \"nb_frames\": \"60\",\n        \"pix_fmt\": \"yuv420p\"\n    },\n    \"section_dir_layout\": [],\n    \"section_index\": []\n}\n"
  },
  {
    "path": "tests/control_data/videos_data/SquareToCircleWithlFlag.json",
    "content": "{\n    \"name\": \"SquareToCircleWithlFlag\",\n    \"movie_metadata\": {\n        \"codec_name\": \"h264\",\n        \"width\": 854,\n        \"height\": 480,\n        \"avg_frame_rate\": \"15/1\",\n        \"duration\": \"1.000000\",\n        \"nb_frames\": \"15\",\n        \"pix_fmt\": \"yuv420p\"\n    },\n    \"section_dir_layout\": [],\n    \"section_index\": []\n}\n"
  },
  {
    "path": "tests/helpers/__init__.py",
    "content": ""
  },
  {
    "path": "tests/helpers/graphical_units.py",
    "content": "\"\"\"Helpers functions for devs to set up new graphical-units data.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nimport tempfile\nfrom pathlib import Path\n\nimport numpy as np\n\nfrom manim.scene.scene import Scene\n\nlogger = logging.getLogger(\"manim\")\n\n\ndef set_test_scene(scene_object: type[Scene], module_name: str, config):\n    \"\"\"Function used to set up the test data for a new feature. This will basically set up a pre-rendered frame for a scene. This is meant to be used only\n    when setting up tests. Please refer to the wiki.\n\n    Parameters\n    ----------\n    scene_object\n        The scene with which we want to set up a new test.\n    module_name\n        The name of the module in which the functionality tested is contained. For example, ``Write`` is contained in the module ``creation``. This will be used in the folder architecture\n        of ``/tests_data``.\n\n    Examples\n    --------\n    Normal usage::\n        set_test_scene(DotTest, \"geometry\")\n\n    \"\"\"\n    config[\"write_to_movie\"] = False\n    config[\"disable_caching\"] = True\n    config[\"format\"] = \"png\"\n    config[\"pixel_height\"] = 480\n    config[\"pixel_width\"] = 854\n    config[\"frame_rate\"] = 15\n\n    with tempfile.TemporaryDirectory() as tmpdir:\n        temp_path = Path(tmpdir)\n        config[\"text_dir\"] = temp_path / \"text\"\n        config[\"tex_dir\"] = temp_path / \"tex\"\n        scene = scene_object(skip_animations=True)\n        scene.render()\n        data = scene.renderer.get_frame()\n\n    assert not np.all(\n        data == np.array([0, 0, 0, 255]),\n    ), f\"Control data generated for {scene!s} only contains empty pixels.\"\n    assert data.shape == (480, 854, 4)\n    tests_directory = Path(__file__).absolute().parent.parent\n    path_control_data = Path(tests_directory) / \"control_data\" / \"graphical_units_data\"\n    path = Path(path_control_data) / module_name\n    path.mkdir(parents=True, exist_ok=True)\n    np.savez_compressed(path / str(scene), frame_data=data)\n    logger.info(f\"Test data for {str(scene)} saved in {path}\\n\")\n"
  },
  {
    "path": "tests/helpers/path_utils.py",
    "content": "from __future__ import annotations\n\nfrom pathlib import Path\n\n\ndef get_project_root() -> Path:\n    return Path(__file__).parent.parent.parent\n\n\ndef get_svg_resource(filename):\n    return str(\n        get_project_root() / \"tests/test_graphical_units/img_svg_resources\" / filename,\n    )\n"
  },
  {
    "path": "tests/helpers/video_utils.py",
    "content": "\"\"\"Helpers for dev to set up new tests that use videos.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nfrom pathlib import Path\nfrom typing import Any\n\nfrom manim import get_dir_layout, get_video_metadata, logger\n\n\ndef get_section_dir_layout(dirpath: Path) -> list[str]:\n    \"\"\"Return a list of all files in the sections directory.\"\"\"\n    # test if sections have been created in the first place, doesn't work with multiple scene but this isn't an issue with tests\n    if not dirpath.is_dir():\n        return []\n    files = list(get_dir_layout(dirpath))\n    # indicate that the sections directory has been created\n    files.append(\".\")\n    return files\n\n\ndef get_section_index(metapath: Path) -> list[dict[str, Any]]:\n    \"\"\"Return content of sections index file.\"\"\"\n    parent_folder = metapath.parent.absolute()\n    # test if sections have been created in the first place\n    if not parent_folder.is_dir():\n        return []\n    with metapath.open() as file:\n        index = json.load(file)\n    return index\n\n\ndef save_control_data_from_video(path_to_video: Path, name: str) -> None:\n    \"\"\"Helper used to set up a new test that will compare videos.\n\n    This will create a new ``.json`` file in ``control_data/videos_data`` that contains:\n    - the name of the video,\n    - the metadata of the video, like fps and resolution and\n    - the paths of all files in the sections subdirectory (like section videos).\n\n    Refer to the documentation for more information.\n\n    Parameters\n    ----------\n    path_to_video\n        Path to the video to extract information from.\n    name\n        Name of the test. The .json file will be named with it.\n\n    See Also\n    --------\n\n    tests/utils/video_tester.py : read control data and compare with output of test\n    \"\"\"\n    orig_path_to_sections = path_to_video\n    path_to_sections = orig_path_to_sections.parent.absolute() / \"sections\"\n    tests_directory = Path(__file__).absolute().parent.parent\n    path_control_data = Path(tests_directory) / \"control_data\" / \"videos_data\"\n    # this is the name of the section used in the test, not the name of the test itself, it can be found as a parameter of this function\n    scene_name = orig_path_to_sections.stem\n\n    movie_metadata = get_video_metadata(path_to_video)\n    section_dir_layout = get_section_dir_layout(path_to_sections)\n    section_index = get_section_index(path_to_sections / f\"{scene_name}.json\")\n\n    data = {\n        \"name\": name,\n        \"movie_metadata\": movie_metadata,\n        \"section_dir_layout\": section_dir_layout,\n        \"section_index\": section_index,\n    }\n    path_saved = Path(path_control_data) / f\"{name}.json\"\n    with path_saved.open(\"w\") as f:\n        json.dump(data, f, indent=4)\n    logger.info(f\"Data for {name} saved in {path_saved}\")\n"
  },
  {
    "path": "tests/interface/test_commands.py",
    "content": "from __future__ import annotations\n\nimport shutil\nimport sys\nfrom pathlib import Path\nfrom textwrap import dedent\nfrom unittest.mock import patch\n\nfrom click.testing import CliRunner\n\nfrom manim import __version__, capture\nfrom manim.__main__ import main\nfrom manim.cli.checkhealth.checks import HEALTH_CHECKS\n\n\ndef test_manim_version():\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--version\",\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n    assert __version__ in out\n\n\ndef test_manim_cfg_subcommand():\n    command = [\"cfg\"]\n    runner = CliRunner()\n    result = runner.invoke(main, command, prog_name=\"manim\")\n    expected_output = f\"\"\"\\\nManim Community v{__version__}\n\nUsage: manim cfg [OPTIONS] COMMAND [ARGS]...\n\n  Manages Manim configuration files.\n\nOptions:\n  --help  Show this message and exit.\n\nCommands:\n  export\n  show\n  write\n\nMade with <3 by Manim Community developers.\n\"\"\"\n    assert dedent(expected_output) == result.output\n\n\ndef test_manim_plugins_subcommand():\n    command = [\"plugins\"]\n    runner = CliRunner()\n    result = runner.invoke(main, command, prog_name=\"manim\")\n    expected_output = f\"\"\"\\\nManim Community v{__version__}\n\nUsage: manim plugins [OPTIONS]\n\n  Manages Manim plugins.\n\nOptions:\n  -l, --list  List available plugins.\n  --help      Show this message and exit.\n\nMade with <3 by Manim Community developers.\n\"\"\"\n    assert dedent(expected_output) == result.output\n\n\ndef test_manim_checkhealth_subcommand():\n    command = [\"checkhealth\"]\n    runner = CliRunner()\n    result = runner.invoke(main, command)\n    output_lines = result.output.split(\"\\n\")\n    num_passed = len([line for line in output_lines if \"PASSED\" in line])\n    assert num_passed == len(HEALTH_CHECKS), (\n        f\"Some checks failed! Full output:\\n{result.output}\"\n    )\n    assert \"No problems detected, your installation seems healthy!\" in output_lines\n\n\ndef test_manim_checkhealth_failing_subcommand():\n    command = [\"checkhealth\"]\n    runner = CliRunner()\n    true_f = shutil.which\n\n    def mock_f(s):\n        if s == \"latex\":\n            return None\n\n        return true_f(s)\n\n    with patch.object(shutil, \"which\", new=mock_f):\n        result = runner.invoke(main, command)\n\n    output_lines = result.output.split(\"\\n\")\n    assert \"- Checking whether latex is available ... FAILED\" in output_lines\n    assert \"- Checking whether dvisvgm is available ... SKIPPED\" in output_lines\n\n\ndef test_manim_init_subcommand():\n    command = [\"init\"]\n    runner = CliRunner()\n    result = runner.invoke(main, command, prog_name=\"manim\")\n    expected_output = f\"\"\"\\\nManim Community v{__version__}\n\nUsage: manim init [OPTIONS] COMMAND [ARGS]...\n\n  Create a new project or insert a new scene.\n\nOptions:\n  --help  Show this message and exit.\n\nCommands:\n  project  Creates a new project.\n  scene    Inserts a SCENE to an existing FILE or creates a new FILE.\n\nMade with <3 by Manim Community developers.\n\"\"\"\n    assert dedent(expected_output) == result.output\n\n\ndef test_manim_init_project(tmp_path):\n    command = [\"init\", \"project\", \"--default\", \"testproject\"]\n    runner = CliRunner()\n    with runner.isolated_filesystem(temp_dir=tmp_path) as tmp_dir:\n        result = runner.invoke(main, command, prog_name=\"manim\", input=\"Default\\n\")\n        assert not result.exception\n        assert (Path(tmp_dir) / \"testproject/main.py\").exists()\n        assert (Path(tmp_dir) / \"testproject/manim.cfg\").exists()\n\n\ndef test_manim_init_scene(tmp_path):\n    command_named = [\"init\", \"scene\", \"NamedFileTestScene\", \"my_awesome_file.py\"]\n    command_unnamed = [\"init\", \"scene\", \"DefaultFileTestScene\"]\n    runner = CliRunner()\n    with runner.isolated_filesystem(temp_dir=tmp_path) as tmp_dir:\n        result = runner.invoke(\n            main, command_named, prog_name=\"manim\", input=\"Default\\n\"\n        )\n        assert not result.exception\n        assert (Path(tmp_dir) / \"my_awesome_file.py\").exists()\n        file_content = (Path(tmp_dir) / \"my_awesome_file.py\").read_text()\n        assert \"NamedFileTestScene(Scene):\" in file_content\n        result = runner.invoke(\n            main, command_unnamed, prog_name=\"manim\", input=\"Default\\n\"\n        )\n        assert (Path(tmp_dir) / \"main.py\").exists()\n        file_content = (Path(tmp_dir) / \"main.py\").read_text()\n        assert \"DefaultFileTestScene(Scene):\" in file_content\n"
  },
  {
    "path": "tests/miscellaneous/test_version.py",
    "content": "from __future__ import annotations\n\nfrom importlib.metadata import version\n\nfrom manim import __name__, __version__\n\n\ndef test_version():\n    assert __version__ == version(__name__)\n"
  },
  {
    "path": "tests/module/animation/test_animate.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport pytest\n\nfrom manim.animation.creation import Uncreate\nfrom manim.mobject.geometry.arc import Dot\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.geometry.polygram import Square\nfrom manim.mobject.mobject import override_animate\nfrom manim.mobject.types.vectorized_mobject import VGroup\n\n\ndef test_simple_animate():\n    s = Square()\n    scale_factor = 2\n    anim = s.animate.scale(scale_factor).build()\n    assert anim.mobject.target.width == scale_factor * s.width\n\n\ndef test_chained_animate():\n    s = Square()\n    scale_factor = 2\n    direction = np.array((1, 1, 0))\n    anim = s.animate.scale(scale_factor).shift(direction).build()\n    assert anim.mobject.target.width == scale_factor * s.width\n    assert (anim.mobject.target.get_center() == direction).all()\n\n\ndef test_overridden_animate():\n    class DotsWithLine(VGroup):\n        def __init__(self):\n            super().__init__()\n            self.left_dot = Dot().shift((-1, 0, 0))\n            self.right_dot = Dot().shift((1, 0, 0))\n            self.line = Line(self.left_dot, self.right_dot)\n            self.add(self.left_dot, self.right_dot, self.line)\n\n        def remove_line(self):\n            self.remove(self.line)\n\n        @override_animate(remove_line)\n        def _remove_line_animation(self, anim_args=None):\n            if anim_args is None:\n                anim_args = {}\n            self.remove_line()\n            return Uncreate(self.line, **anim_args)\n\n    dots_with_line = DotsWithLine()\n    anim = dots_with_line.animate.remove_line().build()\n    assert len(dots_with_line.submobjects) == 2\n    assert type(anim) is Uncreate\n\n\ndef test_chaining_overridden_animate():\n    class DotsWithLine(VGroup):\n        def __init__(self):\n            super().__init__()\n            self.left_dot = Dot().shift((-1, 0, 0))\n            self.right_dot = Dot().shift((1, 0, 0))\n            self.line = Line(self.left_dot, self.right_dot)\n            self.add(self.left_dot, self.right_dot, self.line)\n\n        def remove_line(self):\n            self.remove(self.line)\n\n        @override_animate(remove_line)\n        def _remove_line_animation(self, anim_args=None):\n            if anim_args is None:\n                anim_args = {}\n            self.remove_line()\n            return Uncreate(self.line, **anim_args)\n\n    with pytest.raises(\n        NotImplementedError,\n        match=\"not supported for overridden animations\",\n    ):\n        DotsWithLine().animate.shift((1, 0, 0)).remove_line()\n\n    with pytest.raises(\n        NotImplementedError,\n        match=\"not supported for overridden animations\",\n    ):\n        DotsWithLine().animate.remove_line().shift((1, 0, 0))\n\n\ndef test_animate_with_args():\n    s = Square()\n    scale_factor = 2\n    run_time = 2\n\n    anim = s.animate(run_time=run_time).scale(scale_factor).build()\n    assert anim.mobject.target.width == scale_factor * s.width\n    assert anim.run_time == run_time\n\n\ndef test_chained_animate_with_args():\n    s = Square()\n    scale_factor = 2\n    direction = np.array((1, 1, 0))\n    run_time = 2\n\n    anim = s.animate(run_time=run_time).scale(scale_factor).shift(direction).build()\n    assert anim.mobject.target.width == scale_factor * s.width\n    assert (anim.mobject.target.get_center() == direction).all()\n    assert anim.run_time == run_time\n\n\ndef test_animate_with_args_misplaced():\n    s = Square()\n    scale_factor = 2\n    run_time = 2\n\n    with pytest.raises(ValueError, match=\"must be passed before\"):\n        s.animate.scale(scale_factor)(run_time=run_time)\n\n    with pytest.raises(ValueError, match=\"must be passed before\"):\n        s.animate(run_time=run_time)(run_time=run_time).scale(scale_factor)\n"
  },
  {
    "path": "tests/module/animation/test_animation.py",
    "content": "from __future__ import annotations\n\nimport pytest\n\nfrom manim import FadeIn, Scene\n\n\ndef test_animation_zero_total_run_time():\n    test_scene = Scene()\n    with pytest.raises(\n        ValueError, match=\"The total run_time must be a positive number.\"\n    ):\n        test_scene.play(FadeIn(None, run_time=0))\n\n\ndef test_single_animation_zero_run_time_with_more_animations():\n    test_scene = Scene()\n    test_scene.play(FadeIn(None, run_time=0), FadeIn(None, run_time=1))\n\n\ndef test_animation_negative_run_time():\n    with pytest.raises(ValueError, match=\"The run_time of FadeIn cannot be negative.\"):\n        FadeIn(None, run_time=-1)\n\n\ndef test_animation_run_time_shorter_than_frame_rate(manim_caplog, config):\n    test_scene = Scene()\n    test_scene.play(FadeIn(None, run_time=1 / (config.frame_rate + 1)))\n    assert \"too short for the current frame rate\" in manim_caplog.text\n\n\n@pytest.mark.parametrize(\"duration\", [0, -1])\ndef test_wait_invalid_duration(duration):\n    test_scene = Scene()\n    with pytest.raises(ValueError, match=\"The duration must be a positive number.\"):\n        test_scene.wait(duration)\n\n\n@pytest.mark.parametrize(\"frozen_frame\", [False, True])\ndef test_wait_duration_shorter_than_frame_rate(manim_caplog, frozen_frame):\n    test_scene = Scene()\n    test_scene.wait(1e-9, frozen_frame=frozen_frame)\n    assert \"too short for the current frame rate\" in manim_caplog.text\n\n\n@pytest.mark.parametrize(\"duration\", [0, -1])\ndef test_pause_invalid_duration(duration):\n    test_scene = Scene()\n    with pytest.raises(ValueError, match=\"The duration must be a positive number.\"):\n        test_scene.pause(duration)\n\n\n@pytest.mark.parametrize(\"max_time\", [0, -1])\ndef test_wait_until_invalid_max_time(max_time):\n    test_scene = Scene()\n    with pytest.raises(ValueError, match=\"The max_time must be a positive number.\"):\n        test_scene.wait_until(lambda: True, max_time)\n"
  },
  {
    "path": "tests/module/animation/test_composition.py",
    "content": "from __future__ import annotations\n\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nfrom manim.animation.animation import Animation, Wait\nfrom manim.animation.composition import AnimationGroup, LaggedStartMap, Succession\nfrom manim.animation.creation import Create, Write\nfrom manim.animation.fading import FadeIn, FadeOut\nfrom manim.constants import DOWN, UP\nfrom manim.mobject.geometry.arc import Circle\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.geometry.polygram import RegularPolygon, Square\nfrom manim.mobject.types.vectorized_mobject import VGroup\nfrom manim.scene.scene import Scene\nfrom manim.utils.rate_functions import linear, there_and_back\n\n\ndef test_succession_timing():\n    \"\"\"Test timing of animations in a succession.\"\"\"\n    line = Line()\n    animation_1s = FadeIn(line, shift=UP, run_time=1.0)\n    animation_4s = FadeOut(line, shift=DOWN, run_time=4.0)\n    succession = Succession(animation_1s, animation_4s)\n    assert succession.get_run_time() == 5.0\n    succession._setup_scene(MagicMock())\n    succession.begin()\n    assert succession.active_index == 0\n    # The first animation takes 20% of the total run time.\n    succession.interpolate(0.199)\n    assert succession.active_index == 0\n    succession.interpolate(0.2)\n    assert succession.active_index == 1\n    succession.interpolate(0.8)\n    assert succession.active_index == 1\n    # At 100% and more, no animation must be active anymore.\n    succession.interpolate(1.0)\n    assert succession.active_index == 2\n    assert succession.active_animation is None\n    succession.interpolate(1.2)\n    assert succession.active_index == 2\n    assert succession.active_animation is None\n\n\ndef test_succession_in_succession_timing():\n    \"\"\"Test timing of nested successions.\"\"\"\n    line = Line()\n    animation_1s = FadeIn(line, shift=UP, run_time=1.0)\n    animation_4s = FadeOut(line, shift=DOWN, run_time=4.0)\n    nested_succession = Succession(animation_1s, animation_4s)\n    succession = Succession(\n        FadeIn(line, shift=UP, run_time=4.0),\n        nested_succession,\n        FadeIn(line, shift=UP, run_time=1.0),\n    )\n    assert nested_succession.get_run_time() == 5.0\n    assert succession.get_run_time() == 10.0\n    succession._setup_scene(MagicMock())\n    succession.begin()\n    succession.interpolate(0.1)\n    assert succession.active_index == 0\n    # The nested succession must not be active yet, and as a result hasn't set active_animation yet.\n    assert not hasattr(nested_succession, \"active_animation\")\n    succession.interpolate(0.39)\n    assert succession.active_index == 0\n    assert not hasattr(nested_succession, \"active_animation\")\n    # The nested succession starts at 40% of total run time\n    succession.interpolate(0.4)\n    assert succession.active_index == 1\n    assert nested_succession.active_index == 0\n    # The nested succession second animation starts at 50% of total run time.\n    succession.interpolate(0.49)\n    assert succession.active_index == 1\n    assert nested_succession.active_index == 0\n    succession.interpolate(0.5)\n    assert succession.active_index == 1\n    assert nested_succession.active_index == 1\n    # The last animation starts at 90% of total run time. The nested succession must be finished at that time.\n    succession.interpolate(0.89)\n    assert succession.active_index == 1\n    assert nested_succession.active_index == 1\n    succession.interpolate(0.9)\n    assert succession.active_index == 2\n    assert nested_succession.active_index == 2\n    assert nested_succession.active_animation is None\n    # After 100%, nothing must be playing anymore.\n    succession.interpolate(1.0)\n    assert succession.active_index == 3\n    assert succession.active_animation is None\n    assert nested_succession.active_index == 2\n    assert nested_succession.active_animation is None\n\n\ndef test_timescaled_succession():\n    s1, s2, s3 = Square(), Square(), Square()\n    anim = Succession(\n        FadeIn(s1, run_time=2),\n        FadeIn(s2),\n        FadeIn(s3),\n    )\n    anim.scene = MagicMock()\n    anim.run_time = 42\n    anim.begin()\n    anim.interpolate(0.2)\n    assert anim.active_index == 0\n    anim.interpolate(0.4)\n    assert anim.active_index == 0\n    anim.interpolate(0.6)\n    assert anim.active_index == 1\n    anim.interpolate(0.8)\n    assert anim.active_index == 2\n\n\ndef test_animationbuilder_in_group():\n    sqr = Square()\n    circ = Circle()\n    animation_group = AnimationGroup(sqr.animate.shift(DOWN).scale(2), FadeIn(circ))\n    assert all(isinstance(anim, Animation) for anim in animation_group.animations)\n    succession = Succession(sqr.animate.shift(DOWN).scale(2), FadeIn(circ))\n    assert all(isinstance(anim, Animation) for anim in succession.animations)\n\n\ndef test_animationgroup_with_wait():\n    sqr = Square()\n    sqr_anim = FadeIn(sqr)\n    wait = Wait()\n    animation_group = AnimationGroup(wait, sqr_anim, lag_ratio=1)\n\n    animation_group.begin()\n    timings = animation_group.anims_with_timings\n\n    assert timings.tolist() == [(wait, 0.0, 1.0), (sqr_anim, 1.0, 2.0)]\n\n\n@pytest.mark.parametrize(\n    (\"animation_remover\", \"animation_group_remover\"),\n    [(False, True), (True, False)],\n)\ndef test_animationgroup_is_passing_remover_to_animations(\n    animation_remover, animation_group_remover\n):\n    scene = Scene()\n    sqr_animation = Create(Square(), remover=animation_remover)\n    circ_animation = Write(Circle(), remover=animation_remover)\n    animation_group = AnimationGroup(\n        sqr_animation, circ_animation, remover=animation_group_remover\n    )\n\n    scene.play(animation_group)\n    scene.wait(0.1)\n\n    assert sqr_animation.remover\n    assert circ_animation.remover\n\n\ndef test_animationgroup_is_passing_remover_to_nested_animationgroups():\n    scene = Scene()\n    sqr_animation = Create(Square())\n    circ_animation = Write(Circle(), remover=True)\n    polygon_animation = Create(RegularPolygon(5))\n    animation_group = AnimationGroup(\n        AnimationGroup(sqr_animation, polygon_animation),\n        circ_animation,\n        remover=True,\n    )\n\n    scene.play(animation_group)\n    scene.wait(0.1)\n\n    assert sqr_animation.remover\n    assert circ_animation.remover\n    assert polygon_animation.remover\n\n\ndef test_animationgroup_calls_finish():\n    class MyAnimation(Animation):\n        def __init__(self, mobject):\n            super().__init__(mobject)\n            self.finished = False\n\n        def finish(self):\n            self.finished = True\n\n    scene = Scene()\n    sqr_animation = MyAnimation(Square())\n    circ_animation = MyAnimation(Circle())\n    animation_group = AnimationGroup(sqr_animation, circ_animation)\n    scene.play(animation_group)\n    assert sqr_animation.finished\n    assert circ_animation.finished\n\n\ndef test_laggedstartmap_only_passes_kwargs_to_subanimations():\n    mobject = VGroup(Square(), Circle())\n    animation = LaggedStartMap(\n        FadeIn,\n        mobject,\n        rate_func=there_and_back,\n        lag_ratio=0.3,\n    )\n\n    assert animation.rate_func is linear\n    assert animation.lag_ratio == 0.3\n    assert all(\n        subanimation.rate_func is there_and_back\n        for subanimation in animation.animations\n    )\n\n\ndef test_empty_animation_group_fails():\n    with pytest.raises(ValueError, match=\"Please add at least one subanimation.\"):\n        AnimationGroup().begin()\n\n\ndef test_empty_succession_fails():\n    with pytest.raises(ValueError, match=\"Please add at least one subanimation.\"):\n        Succession().begin()\n"
  },
  {
    "path": "tests/module/animation/test_creation.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport pytest\n\nfrom manim import AddTextLetterByLetter, Text\n\n\ndef test_non_empty_text_creation():\n    \"\"\"Check if AddTextLetterByLetter works for non-empty text.\"\"\"\n    s = Text(\"Hello\")\n    anim = AddTextLetterByLetter(s)\n    assert anim.mobject.text == \"Hello\"\n\n\ndef test_empty_text_creation():\n    \"\"\"Ensure ValueError is raised for empty text.\"\"\"\n    with pytest.raises(ValueError, match=\"does not seem to contain any characters\"):\n        AddTextLetterByLetter(Text(\"\"))\n\n\ndef test_whitespace_text_creation():\n    \"\"\"Ensure ValueError is raised for whitespace-only text, assuming the whitespace characters have no points.\"\"\"\n    with pytest.raises(ValueError, match=\"does not seem to contain any characters\"):\n        AddTextLetterByLetter(Text(\"    \"))\n\n\ndef test_run_time_for_non_empty_text(config):\n    \"\"\"Ensure the run_time is calculated correctly for non-empty text.\"\"\"\n    s = Text(\"Hello\")\n    run_time_per_char = 0.1\n    expected_run_time = np.max((1 / config.frame_rate, run_time_per_char)) * len(s.text)\n    anim = AddTextLetterByLetter(s, time_per_char=run_time_per_char)\n    assert anim.run_time == expected_run_time\n"
  },
  {
    "path": "tests/module/animation/test_override_animation.py",
    "content": "from __future__ import annotations\n\nimport pytest\n\nfrom manim import Animation, Mobject, override_animation\nfrom manim.utils.exceptions import MultiAnimationOverrideException\n\n\nclass AnimationA1(Animation):\n    pass\n\n\nclass AnimationA2(Animation):\n    pass\n\n\nclass AnimationA3(Animation):\n    pass\n\n\nclass AnimationB1(AnimationA1):\n    pass\n\n\nclass AnimationC1(AnimationB1):\n    pass\n\n\nclass AnimationX(Animation):\n    pass\n\n\nclass MobjectA(Mobject):\n    @override_animation(AnimationA1)\n    def anim_a1(self):\n        return AnimationA2(self)\n\n    @override_animation(AnimationX)\n    def anim_x(self, *args, **kwargs):\n        return args, kwargs\n\n\nclass MobjectB(MobjectA):\n    pass\n\n\nclass MobjectC(MobjectB):\n    @override_animation(AnimationA1)\n    def anim_a1(self):\n        return AnimationA3(self)\n\n\nclass MobjectX(Mobject):\n    @override_animation(AnimationB1)\n    def animation(self):\n        return \"Overridden\"\n\n\ndef test_mobject_inheritance():\n    mob = Mobject()\n    a = MobjectA()\n    b = MobjectB()\n    c = MobjectC()\n\n    assert type(AnimationA1(mob)) is AnimationA1\n    assert type(AnimationA1(a)) is AnimationA2\n    assert type(AnimationA1(b)) is AnimationA2\n    assert type(AnimationA1(c)) is AnimationA3\n\n\ndef test_arguments():\n    a = MobjectA()\n    args = (1, \"two\", {\"three\": 3}, [\"f\", \"o\", \"u\", \"r\"])\n    kwargs = {\"test\": \"manim\", \"keyword\": 42, \"arguments\": []}\n    animA = AnimationX(a, *args, **kwargs)\n\n    assert animA[0] == args\n    assert animA[1] == kwargs\n\n\ndef test_multi_animation_override_exception():\n    with pytest.raises(MultiAnimationOverrideException):\n\n        class MobjectB2(MobjectA):\n            @override_animation(AnimationA1)\n            def anim_a1_different_name(self):\n                pass\n\n\ndef test_animation_inheritance():\n    x = MobjectX()\n\n    assert type(AnimationA1(x)) is AnimationA1\n    assert AnimationB1(x) == \"Overridden\"\n    assert type(AnimationC1(x)) is AnimationC1\n"
  },
  {
    "path": "tests/module/animation/test_transform.py",
    "content": "from __future__ import annotations\n\nfrom manim import Circle, ReplacementTransform, Scene, Square, VGroup\n\n\ndef test_no_duplicate_references():\n    scene = Scene()\n    c = Circle()\n    sq = Square()\n    scene.add(c, sq)\n\n    scene.play(ReplacementTransform(c, sq))\n    assert len(scene.mobjects) == 1\n    assert scene.mobjects[0] is sq\n\n\ndef test_duplicate_references_in_group():\n    scene = Scene()\n    c = Circle()\n    sq = Square()\n    vg = VGroup(c, sq)\n    scene.add(vg)\n\n    scene.play(ReplacementTransform(c, sq))\n    submobs = vg.submobjects\n    assert len(submobs) == 1\n    assert submobs[0] is sq\n"
  },
  {
    "path": "tests/module/animation/test_updaters.py",
    "content": "from __future__ import annotations\n\nfrom manim import UP, Circle, Dot, FadeIn\nfrom manim.animation.updaters.mobject_update_utils import turn_animation_into_updater\n\n\ndef test_turn_animation_into_updater_zero_run_time():\n    \"\"\"Test that turn_animation_into_updater handles zero run_time correctly.\"\"\"\n    # Create a simple mobject and animation\n    mobject = Circle()\n    animation = FadeIn(mobject, run_time=0)\n\n    # Track updater calls\n    update_calls = []\n    original_updaters = mobject.updaters.copy()\n\n    # Call turn_animation_into_updater\n    result = turn_animation_into_updater(animation)\n\n    # Verify mobject is returned\n    assert result is mobject\n\n    # Get the updater that was added\n    assert len(mobject.updaters) == len(original_updaters) + 1\n    updater = mobject.updaters[-1]\n\n    # Simulate calling the updater\n    updater(mobject, dt=0.1)\n\n    # The updater should have finished and removed itself\n    assert len(mobject.updaters) == len(original_updaters)\n    assert updater not in mobject.updaters\n\n    # Animation should be in finished state\n    assert animation.total_time >= 0\n\n\ndef test_turn_animation_into_updater_positive_run_time_persists():\n    \"\"\"Test that updater persists with positive run_time.\"\"\"\n    mobject = Circle()\n    animation = FadeIn(mobject, run_time=1.0)\n\n    original_updaters = mobject.updaters.copy()\n\n    # Call turn_animation_into_updater\n    result = turn_animation_into_updater(animation)\n\n    # Get the updater that was added\n    updater = mobject.updaters[-1]\n\n    # Simulate calling the updater (partial progress)\n    updater(mobject, dt=0.1)\n\n    # The updater should still be present (not finished)\n    assert len(mobject.updaters) == len(original_updaters) + 1\n    assert updater in mobject.updaters\n\n\ndef test_always():\n    d = Dot()\n    circ = Circle()\n    d.always.next_to(circ, UP)\n    assert len(d.updaters) == 1\n    # we should be able to chain updaters\n    d2 = Dot()\n    d.always.next_to(d2, UP).next_to(circ, UP)\n    assert len(d.updaters) == 3\n"
  },
  {
    "path": "tests/module/mobject/geometry/test_unit_geometry.py",
    "content": "from __future__ import annotations\n\nimport logging\n\nimport numpy as np\n\nfrom manim import (\n    DEGREES,\n    DOWN,\n    GREEN,\n    LEFT,\n    ORIGIN,\n    RIGHT,\n    UP,\n    BackgroundRectangle,\n    Circle,\n    Line,\n    Polygram,\n    Sector,\n    Square,\n    SurroundingRectangle,\n    TangentialArc,\n)\n\nlogger = logging.getLogger(__name__)\n\n\ndef test_get_arc_center():\n    np.testing.assert_array_equal(\n        Sector(arc_center=[1, 2, 0]).get_arc_center(), [1, 2, 0]\n    )\n\n\ndef test_Polygram_get_vertex_groups():\n    # Test that, once a Polygram polygram is created with some vertex groups,\n    # polygram.get_vertex_groups() (usually) returns the same vertex groups.\n    vertex_groups_arr = [\n        # 2 vertex groups for polygram 1\n        [\n            # Group 1: Triangle\n            np.array(\n                [\n                    [2, 1, 0],\n                    [0, 2, 0],\n                    [-2, 1, 0],\n                ]\n            ),\n            # Group 2: Square\n            np.array(\n                [\n                    [1, 0, 0],\n                    [0, 1, 0],\n                    [-1, 0, 0],\n                    [0, -1, 0],\n                ]\n            ),\n        ],\n        # 3 vertex groups for polygram 1\n        [\n            # Group 1: Quadrilateral\n            np.array(\n                [\n                    [2, 0, 0],\n                    [0, -1, 0],\n                    [0, 0, -2],\n                    [0, 1, 0],\n                ]\n            ),\n            # Group 2: Triangle\n            np.array(\n                [\n                    [3, 1, 0],\n                    [0, 0, 2],\n                    [2, 0, 0],\n                ]\n            ),\n            # Group 3: Pentagon\n            np.array(\n                [\n                    [1, -1, 0],\n                    [1, 1, 0],\n                    [0, 2, 0],\n                    [-1, 1, 0],\n                    [-1, -1, 0],\n                ]\n            ),\n        ],\n    ]\n\n    for vertex_groups in vertex_groups_arr:\n        polygram = Polygram(*vertex_groups)\n        poly_vertex_groups = polygram.get_vertex_groups()\n        for poly_group, group in zip(poly_vertex_groups, vertex_groups, strict=True):\n            np.testing.assert_array_equal(poly_group, group)\n\n    # If polygram is a Polygram of a vertex group containing the start vertex N times,\n    # then polygram.get_vertex_groups() splits it into N vertex groups.\n    splittable_vertex_group = np.array(\n        [\n            [0, 1, 0],\n            [1, -2, 0],\n            [1, 2, 0],\n            [0, 1, 0],  # same vertex as start\n            [-1, 2, 0],\n            [-1, -2, 0],\n            [0, 1, 0],  # same vertex as start\n            [0.5, 2, 0],\n            [-0.5, 2, 0],\n        ]\n    )\n\n    polygram = Polygram(splittable_vertex_group)\n    assert len(polygram.get_vertex_groups()) == 3\n\n\ndef test_SurroundingRectangle():\n    circle = Circle()\n    square = Square()\n    sr = SurroundingRectangle(circle, square)\n    sr.set_style(fill_opacity=0.42)\n    assert sr.get_fill_opacity() == 0.42\n\n\ndef test_TangentialArc():\n    l1 = Line(start=LEFT, end=RIGHT)\n    l2 = Line(start=DOWN, end=UP)\n    l2.rotate(angle=45 * DEGREES, about_point=ORIGIN)\n    arc = TangentialArc(l1, l2, radius=1.0)\n    assert arc.radius == 1.0\n\n\ndef test_SurroundingRectangle_buff():\n    sq = Square()\n    rect1 = SurroundingRectangle(sq, buff=1)\n    assert rect1.width == sq.width + 2\n    assert rect1.height == sq.height + 2\n\n    rect2 = SurroundingRectangle(sq, buff=(1, 2))\n    assert rect2.width == sq.width + 2\n    assert rect2.height == sq.height + 4\n\n\ndef test_BackgroundRectangle(manim_caplog):\n    circle = Circle()\n    square = Square()\n    bg = BackgroundRectangle(circle, square)\n    bg.set_style(fill_opacity=0.42)\n    assert bg.get_fill_opacity() == 0.42\n    bg.set_style(fill_opacity=1, hello=\"world\")\n    assert (\n        \"Argument {'hello': 'world'} is ignored in BackgroundRectangle.set_style.\"\n        in manim_caplog.text\n    )\n\n\ndef test_BackgroundRectangle_color_access():\n    \"\"\"Test that BackgroundRectangle color access works correctly.\n\n    Regression test for https://github.com/ManimCommunity/manim/issues/4419\n    \"\"\"\n    square = Square()\n    bg_rect = BackgroundRectangle(square, color=GREEN)\n\n    # Should not cause infinite recursion\n    assert bg_rect.color == GREEN\n\n\ndef test_Square_side_length_reflets_correct_width_and_height():\n    sq = Square(side_length=1).scale(3)\n    assert sq.side_length == 3\n    assert sq.height == 3\n    assert sq.width == 3\n\n\ndef test_changing_Square_side_length_updates_the_square_appropriately():\n    sq = Square(side_length=1)\n    sq.side_length = 3\n    assert sq.height == 3\n    assert sq.width == 3\n\n\ndef test_Square_side_length_consistent_after_scale_and_rotation():\n    sq = Square(side_length=1).scale(3).rotate(np.pi / 4)\n    assert np.isclose(sq.side_length, 3)\n\n\ndef test_line_with_buff_and_path_arc():\n    line = Line(LEFT, RIGHT, path_arc=60 * DEGREES, buff=0.3)\n    expected_points = np.array(\n        [\n            [-0.7299265, -0.12999304, 0.0],\n            [-0.6605293, -0.15719695, 0.0],\n            [-0.58965623, -0.18050364, 0.0],\n            [-0.51763809, -0.19980085, 0.0],\n            [-0.51763809, -0.19980085, 0.0],\n            [-0.43331506, -0.22239513, 0.0],\n            [-0.34760317, -0.23944429, 0.0],\n            [-0.26105238, -0.25083892, 0.0],\n            [-0.26105238, -0.25083892, 0.0],\n            [-0.1745016, -0.26223354, 0.0],\n            [-0.08729763, -0.26794919, 0.0],\n            [0.0, -0.26794919, 0.0],\n            [0.0, -0.26794919, 0.0],\n            [0.08729763, -0.26794919, 0.0],\n            [0.1745016, -0.26223354, 0.0],\n            [0.26105238, -0.25083892, 0.0],\n            [0.26105238, -0.25083892, 0.0],\n            [0.34760317, -0.23944429, 0.0],\n            [0.43331506, -0.22239513, 0.0],\n            [0.51763809, -0.19980085, 0.0],\n            [0.51763809, -0.19980085, 0.0],\n            [0.58965623, -0.18050364, 0.0],\n            [0.6605293, -0.15719695, 0.0],\n            [0.7299265, -0.12999304, 0.0],\n        ]\n    )\n    np.testing.assert_allclose(line.points, expected_points)\n\n\ndef test_Circle_point_at_angle():\n    from manim import TAU\n\n    # Test basic angles\n    circle = Circle(radius=1.0)\n    start_point = circle.points[0].copy()\n\n    # Angle 0 should return start point\n    p0 = circle.point_at_angle(0)\n    np.testing.assert_array_almost_equal(p0, start_point, decimal=5)\n\n    # Angle π/2 should return point 90° along arc\n    p90 = circle.point_at_angle(TAU / 4)\n    # Verify it's approximately at top of circle\n    assert p90[1] > 0.9  # Y coordinate close to 1\n\n    # Angle π should return point opposite to start\n    p180 = circle.point_at_angle(TAU / 2)\n    # Verify it's opposite to start point\n    np.testing.assert_array_almost_equal(p180[:2], -start_point[:2], decimal=5)\n\n    # Angle beyond 2π should wrap around\n    p720 = circle.point_at_angle(2 * TAU)\n    np.testing.assert_array_almost_equal(p720[:2], start_point[:2], decimal=5)\n\n    # Negative angles should work\n    p_neg = circle.point_at_angle(-TAU / 4)\n    # Should be same as 3/4 TAU\n    p270 = circle.point_at_angle(3 * TAU / 4)\n    np.testing.assert_array_almost_equal(p_neg, p270, decimal=5)\n\n    # Test with rotated circle\n    rotated_circle = Circle(radius=1.0).rotate(TAU / 8)\n    rotated_start = rotated_circle.points[0].copy()\n\n    # Angle 0 should still return start point after rotation\n    p_rotated_0 = rotated_circle.point_at_angle(0)\n    np.testing.assert_array_almost_equal(p_rotated_0, rotated_start, decimal=5)\n\n    # Test with reflected circle\n    reflected_circle = Circle(radius=1.0).flip()\n    reflected_start = reflected_circle.points[0].copy()\n\n    # Angle 0 should return start point even after reflection\n    p_reflected_0 = reflected_circle.point_at_angle(0)\n    np.testing.assert_array_almost_equal(p_reflected_0, reflected_start, decimal=5)\n"
  },
  {
    "path": "tests/module/mobject/graphing/test_axes_shift.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim.mobject.graphing.coordinate_systems import Axes, ThreeDAxes\nfrom manim.mobject.graphing.scale import LogBase\n\n\ndef test_axes_origin_shift():\n    ax = Axes(x_range=(5, 10, 1), y_range=(40, 45, 0.5))\n    np.testing.assert_allclose(ax.coords_to_point(5, 40), ax.x_axis.number_to_point(5))\n    np.testing.assert_allclose(ax.coords_to_point(5, 40), ax.y_axis.number_to_point(40))\n\n\ndef test_axes_origin_shift_logbase():\n    ax = Axes(\n        x_range=(5, 10, 1),\n        y_range=(3, 8, 1),\n        x_axis_config={\"scaling\": LogBase()},\n        y_axis_config={\"scaling\": LogBase()},\n    )\n    np.testing.assert_allclose(\n        ax.coords_to_point(10**5, 10**3), ax.x_axis.number_to_point(10**5)\n    )\n    np.testing.assert_allclose(\n        ax.coords_to_point(10**5, 10**3), ax.y_axis.number_to_point(10**3)\n    )\n\n\ndef test_3daxes_origin_shift():\n    ax = ThreeDAxes(x_range=(3, 9, 1), y_range=(6, 12, 1), z_range=(-1, 1, 0.5))\n    np.testing.assert_allclose(\n        ax.coords_to_point(3, 6, 0), ax.x_axis.number_to_point(3)\n    )\n    np.testing.assert_allclose(\n        ax.coords_to_point(3, 6, 0), ax.y_axis.number_to_point(6)\n    )\n    np.testing.assert_allclose(\n        ax.coords_to_point(3, 6, 0), ax.z_axis.number_to_point(0)\n    )\n\n\ndef test_3daxes_origin_shift_logbase():\n    ax = ThreeDAxes(\n        x_range=(3, 9, 1),\n        y_range=(6, 12, 1),\n        z_range=(2, 5, 1),\n        x_axis_config={\"scaling\": LogBase()},\n        y_axis_config={\"scaling\": LogBase()},\n        z_axis_config={\"scaling\": LogBase()},\n    )\n    np.testing.assert_allclose(\n        ax.coords_to_point(10**3, 10**6, 10**2),\n        ax.x_axis.number_to_point(10**3),\n    )\n    np.testing.assert_allclose(\n        ax.coords_to_point(10**3, 10**6, 10**2),\n        ax.y_axis.number_to_point(10**6),\n    )\n    np.testing.assert_allclose(\n        ax.coords_to_point(10**3, 10**6, 10**2),\n        ax.z_axis.number_to_point(10**2),\n    )\n"
  },
  {
    "path": "tests/module/mobject/graphing/test_coordinate_system.py",
    "content": "from __future__ import annotations\n\nimport math\n\nimport numpy as np\nimport pytest\n\nfrom manim import (\n    LEFT,\n    ORIGIN,\n    PI,\n    UR,\n    Axes,\n    Circle,\n    ComplexPlane,\n    Dot,\n    NumberPlane,\n    PolarPlane,\n    ThreeDAxes,\n    config,\n    tempconfig,\n)\nfrom manim import CoordinateSystem as CS\n\n\ndef test_initial_config():\n    \"\"\"Check that all attributes are defined properly from the config.\"\"\"\n    cs = CS()\n    assert cs.x_range[0] == round(-config[\"frame_x_radius\"])\n    assert cs.x_range[1] == round(config[\"frame_x_radius\"])\n    assert cs.x_range[2] == 1.0\n    assert cs.y_range[0] == round(-config[\"frame_y_radius\"])\n    assert cs.y_range[1] == round(config[\"frame_y_radius\"])\n    assert cs.y_range[2] == 1.0\n\n    ax = Axes()\n    np.testing.assert_allclose(ax.get_center(), ORIGIN)\n    np.testing.assert_allclose(ax.y_axis_config[\"label_direction\"], LEFT)\n\n    with tempconfig({\"frame_x_radius\": 100, \"frame_y_radius\": 200}):\n        cs = CS()\n        assert cs.x_range[0] == -100\n        assert cs.x_range[1] == 100\n        assert cs.y_range[0] == -200\n        assert cs.y_range[1] == 200\n\n\ndef test_dimension():\n    \"\"\"Check that objects have the correct dimension.\"\"\"\n    assert Axes().dimension == 2\n    assert NumberPlane().dimension == 2\n    assert PolarPlane().dimension == 2\n    assert ComplexPlane().dimension == 2\n    assert ThreeDAxes().dimension == 3\n\n\ndef test_abstract_base_class():\n    \"\"\"Check that CoordinateSystem has some abstract methods.\"\"\"\n    with pytest.raises(NotImplementedError):\n        CS().get_axes()\n\n\ndef test_NumberPlane():\n    \"\"\"Test that NumberPlane generates the correct number of lines when its ranges do not cross 0.\"\"\"\n    pos_x_range = (0, 7)\n    neg_x_range = (-7, 0)\n\n    pos_y_range = (2, 6)\n    neg_y_range = (-6, -2)\n\n    testing_data = [\n        (pos_x_range, pos_y_range),\n        (pos_x_range, neg_y_range),\n        (neg_x_range, pos_y_range),\n        (neg_x_range, neg_y_range),\n    ]\n\n    for test_data in testing_data:\n        x_range, y_range = test_data\n\n        x_start, x_end = x_range\n        y_start, y_end = y_range\n\n        plane = NumberPlane(\n            x_range=x_range,\n            y_range=y_range,\n            # x_length = 7,\n            axis_config={\"include_numbers\": True},\n        )\n\n        # normally these values would be need to be added by one to pass since there's an\n        # overlapping pair of lines at the origin, but since these planes do not cross 0,\n        # this is not needed.\n        num_y_lines = math.ceil(x_end - x_start)\n        num_x_lines = math.floor(y_end - y_start)\n\n        assert len(plane.y_lines) == num_y_lines\n        assert len(plane.x_lines) == num_x_lines\n\n    plane = NumberPlane((-5, 5, 0.5), (-8, 8, 2))  # <- test for different step values\n    # horizontal lines: -6 -4, -2, 0, 2, 4, 6\n    assert len(plane.x_lines) == 7\n    # vertical lines: 0, +-0.5, +-1, +-1.5, +-2, +-2.5,\n    # +-3, +-3.5, +-4, +-4.5\n    assert len(plane.y_lines) == 19\n\n\ndef test_point_to_coords():\n    ax = Axes(x_range=[0, 10, 2])\n    circ = Circle(radius=0.5).shift(UR * 2)\n\n    # get the coordinates of the circle with respect to the axes\n    coords = np.around(ax.point_to_coords(circ.get_right()), decimals=4)\n    np.testing.assert_array_equal(coords, (7.0833, 2.6667))\n\n\ndef test_point_to_coords_vectorized():\n    ax = Axes(x_range=[0, 10, 2])\n    circ = Circle(radius=0.5).shift(UR * 2)\n    points = np.array(\n        [circ.get_right(), circ.get_left(), circ.get_bottom(), circ.get_top()]\n    )\n    # get the coordinates of the circle with respect to the axes\n    expected = [np.around(ax.point_to_coords(point), decimals=4) for point in points]\n    actual = np.around(ax.point_to_coords(points), decimals=4)\n\n    np.testing.assert_array_equal(expected, actual)\n\n\ndef test_coords_to_point():\n    ax = Axes()\n\n    # a point with respect to the axes\n    c2p_coord = np.around(ax.coords_to_point(2, 2), decimals=4)\n    c2p_coord_matmul = np.around(ax @ (2, 2), decimals=4)\n\n    expected = (1.7143, 1.5, 0)\n\n    np.testing.assert_array_equal(c2p_coord, expected)\n    np.testing.assert_array_equal(c2p_coord_matmul, c2p_coord)\n\n    mob = Dot().move_to((2, 2, 0))\n    np.testing.assert_array_equal(np.around(ax @ mob, decimals=4), expected)\n\n\ndef test_coords_to_point_vectorized():\n    plane = NumberPlane(x_range=[2, 4])\n\n    origin = plane.x_axis.number_to_point(\n        plane._origin_shift([plane.x_axis.x_min, plane.x_axis.x_max]),\n    )\n\n    def ref_func(*coords):\n        result = np.array(origin)\n        for axis, number in zip(plane.get_axes(), coords, strict=False):\n            result += axis.number_to_point(number) - origin\n        return result\n\n    coords = [[1], [1, 2], [2, 2], [3, 4]]\n\n    print(f\"\\n\\nTesting coords_to_point {coords}\")\n    expected = np.round([ref_func(*coord) for coord in coords], 4)\n    actual1 = np.round([plane.coords_to_point(*coord) for coord in coords], 4)\n    coords[0] = [\n        1,\n        0,\n    ]  # Extend the first coord because you can't vectorize items with different dimensions\n    actual2 = np.round(\n        plane.coords_to_point(coords), 4\n    )  # Test [x_0,y_0,z_0], [x_1,y_1,z_1], ...\n    actual3 = np.round(\n        plane.coords_to_point(*np.array(coords).T), 4\n    )  # Test [x_0,x_1,...], [y_0,y_1,...], ...\n    print(actual3)\n\n    np.testing.assert_array_equal(expected, actual1)\n    np.testing.assert_array_equal(expected, actual2)\n    np.testing.assert_array_equal(expected, actual3.T)\n\n\ndef test_input_to_graph_point():\n    ax = Axes()\n    curve = ax.plot(lambda x: np.cos(x))\n    line_graph = ax.plot_line_graph([1, 3, 5], [-1, 2, -2], add_vertex_dots=False)[\n        \"line_graph\"\n    ]\n\n    # move a square to PI on the cosine curve.\n    position = np.around(ax.input_to_graph_point(x=PI, graph=curve), decimals=4)\n    np.testing.assert_array_equal(position, (2.6928, -0.75, 0))\n\n    # test the line_graph implementation\n    position = np.around(ax.input_to_graph_point(x=PI, graph=line_graph), decimals=4)\n    np.testing.assert_array_equal(position, (2.6928, 1.2876, 0))\n"
  },
  {
    "path": "tests/module/mobject/graphing/test_number_line.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim import DashedLine, NumberLine\nfrom manim.mobject.text.numbers import Integer\n\n\ndef test_unit_vector():\n    \"\"\"Check if the magnitude of unit vector along\n    the NumberLine is equal to its unit_size.\n    \"\"\"\n    axis1 = NumberLine(unit_size=0.4)\n    axis2 = NumberLine(x_range=[-2, 5], length=12)\n    for axis in (axis1, axis2):\n        assert np.linalg.norm(axis.get_unit_vector()) == axis.unit_size\n\n\ndef test_decimal_determined_by_step():\n    \"\"\"Checks that step size is considered when determining the number of decimal\n    places.\n    \"\"\"\n    axis = NumberLine(x_range=[-2, 2, 0.5])\n    expected_decimal_places = 1\n    actual_decimal_places = axis.decimal_number_config[\"num_decimal_places\"]\n    assert actual_decimal_places == expected_decimal_places, (\n        \"Expected 1 decimal place but got \" + actual_decimal_places\n    )\n\n    axis2 = NumberLine(x_range=[-1, 1, 0.25])\n    expected_decimal_places = 2\n    actual_decimal_places = axis2.decimal_number_config[\"num_decimal_places\"]\n    assert actual_decimal_places == expected_decimal_places, (\n        \"Expected 1 decimal place but got \" + actual_decimal_places\n    )\n\n\ndef test_decimal_config_overrides_defaults():\n    \"\"\"Checks that ``num_decimal_places`` is determined by step size and gets overridden by ``decimal_number_config``.\"\"\"\n    axis = NumberLine(\n        x_range=[-2, 2, 0.5],\n        decimal_number_config={\"num_decimal_places\": 0},\n    )\n    expected_decimal_places = 0\n    actual_decimal_places = axis.decimal_number_config[\"num_decimal_places\"]\n    assert actual_decimal_places == expected_decimal_places, (\n        \"Expected 1 decimal place but got \" + actual_decimal_places\n    )\n\n\ndef test_whole_numbers_step_size_default_to_0_decimal_places():\n    \"\"\"Checks that ``num_decimal_places`` defaults to 0 when a whole number step size is passed.\"\"\"\n    axis = NumberLine(x_range=[-2, 2, 1])\n    expected_decimal_places = 0\n    actual_decimal_places = axis.decimal_number_config[\"num_decimal_places\"]\n    assert actual_decimal_places == expected_decimal_places, (\n        \"Expected 1 decimal place but got \" + actual_decimal_places\n    )\n\n\ndef test_add_labels():\n    expected_label_length = 6\n    num_line = NumberLine(x_range=[-4, 4])\n    num_line.add_labels(\n        dict(zip(list(range(-3, 3)), [Integer(m) for m in range(-1, 5)], strict=True)),\n    )\n    actual_label_length = len(num_line.labels)\n    assert actual_label_length == expected_label_length, (\n        f\"Expected a VGroup with {expected_label_length} integers but got {actual_label_length}.\"\n    )\n\n\ndef test_number_to_point():\n    line = NumberLine()\n    numbers = [1, 2, 3, 4, 5]\n    numbers_np = np.array(numbers)\n    expected = np.array(\n        [\n            [1.0, 0.0, 0.0],\n            [2.0, 0.0, 0.0],\n            [3.0, 0.0, 0.0],\n            [4.0, 0.0, 0.0],\n            [5.0, 0.0, 0.0],\n        ]\n    )\n    vec_1 = np.array([line.number_to_point(x) for x in numbers])\n    vec_2 = line.number_to_point(numbers)\n    vec_3 = line.number_to_point(numbers_np)\n\n    np.testing.assert_equal(\n        np.round(vec_1, 4),\n        np.round(expected, 4),\n        f\"Expected {expected} but got {vec_1} with input as scalar\",\n    )\n    np.testing.assert_equal(\n        np.round(vec_2, 4),\n        np.round(expected, 4),\n        f\"Expected {expected} but got {vec_2} with input as params\",\n    )\n    np.testing.assert_equal(\n        np.round(vec_2, 4),\n        np.round(expected, 4),\n        f\"Expected {expected} but got {vec_3} with input as ndarray\",\n    )\n\n\ndef test_point_to_number():\n    line = NumberLine()\n    points = [\n        [1.0, 0.0, 0.0],\n        [2.0, 0.0, 0.0],\n        [3.0, 0.0, 0.0],\n        [4.0, 0.0, 0.0],\n        [5.0, 0.0, 0.0],\n    ]\n    points_np = np.array(points)\n    expected = [1, 2, 3, 4, 5]\n\n    num_1 = [line.point_to_number(point) for point in points]\n    num_2 = line.point_to_number(points)\n    num_3 = line.point_to_number(points_np)\n\n    np.testing.assert_array_equal(np.round(num_1, 4), np.round(expected, 4))\n    np.testing.assert_array_equal(np.round(num_2, 4), np.round(expected, 4))\n    np.testing.assert_array_equal(np.round(num_3, 4), np.round(expected, 4))\n\n\ndef test_start_and_end_at_same_point():\n    line = DashedLine(np.zeros(3), np.zeros(3))\n    line.put_start_and_end_on(np.zeros(3), np.array([0, 0, 0]))\n\n    np.testing.assert_array_equal(np.round(np.zeros(3), 4), np.round(line.points, 4))\n"
  },
  {
    "path": "tests/module/mobject/graphing/test_ticks.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim import PI, Axes, NumberLine\n\n\ndef test_duplicate_ticks_removed_for_axes():\n    axis = NumberLine(\n        x_range=[-10, 10],\n    )\n    ticks = axis.get_tick_range()\n    assert np.unique(ticks).size == ticks.size\n\n\ndef test_elongated_ticks_float_equality():\n    nline = NumberLine(\n        x_range=[1 + 1e-5, 1 + 2e-5, 1e-6],\n        numbers_with_elongated_ticks=[\n            1 + 12e-6,\n            1 + 17e-6,\n        ],  # Elongate the 3rd and 8th tick\n        include_ticks=True,\n    )\n\n    tick_heights = {tick.height for tick in nline.ticks}\n    default_tick_height, elongated_tick_height = min(tick_heights), max(tick_heights)\n\n    assert all(\n        (\n            tick.height == elongated_tick_height\n            if ind in [2, 7]\n            else tick.height == default_tick_height\n        )\n        for ind, tick in enumerate(nline.ticks)\n    )\n\n\ndef test_ticks_not_generated_on_origin_for_axes():\n    axes = Axes(\n        x_range=[-10, 10],\n        y_range=[-10, 10],\n        axis_config={\"include_ticks\": True},\n    )\n\n    x_axis_range = axes.x_axis.get_tick_range()\n    y_axis_range = axes.y_axis.get_tick_range()\n\n    assert 0 not in x_axis_range\n    assert 0 not in y_axis_range\n\n\ndef test_expected_ticks_generated():\n    axes = Axes(x_range=[-2, 2], y_range=[-2, 2], axis_config={\"include_ticks\": True})\n    x_axis_range = axes.x_axis.get_tick_range()\n    y_axis_range = axes.y_axis.get_tick_range()\n\n    assert 1 in x_axis_range\n    assert 1 in y_axis_range\n    assert -1 in x_axis_range\n    assert -1 in y_axis_range\n\n\ndef test_ticks_generated_from_origin_for_axes():\n    axes = Axes(\n        x_range=[-PI, PI],\n        y_range=[-PI, PI],\n        axis_config={\"include_ticks\": True},\n    )\n    x_axis_range = axes.x_axis.get_tick_range()\n    y_axis_range = axes.y_axis.get_tick_range()\n\n    assert -2 in x_axis_range\n    assert -1 in x_axis_range\n    assert 0 not in x_axis_range\n    assert 1 in x_axis_range\n    assert 2 in x_axis_range\n\n    assert -2 in y_axis_range\n    assert -1 in y_axis_range\n    assert 0 not in y_axis_range\n    assert 1 in y_axis_range\n    assert 2 in y_axis_range\n"
  },
  {
    "path": "tests/module/mobject/mobject/test_copy.py",
    "content": "from __future__ import annotations\n\nfrom pathlib import Path\n\nfrom manim import BraceLabel, Mobject\n\n\ndef test_mobject_copy():\n    \"\"\"Test that a copy is a deepcopy.\"\"\"\n    orig = Mobject()\n    orig.add(*(Mobject() for _ in range(10)))\n    copy = orig.copy()\n\n    assert orig is orig\n    assert orig is not copy\n    assert orig.submobjects is not copy.submobjects\n    for i in range(10):\n        assert orig.submobjects[i] is not copy.submobjects[i]\n\n\ndef test_bracelabel_copy(tmp_path, config):\n    \"\"\"Test that a copy is a deepcopy.\"\"\"\n    # For this test to work, we need to tweak some folders temporarily\n    original_text_dir = config[\"text_dir\"]\n    original_tex_dir = config[\"tex_dir\"]\n    mediadir = Path(tmp_path) / \"deepcopy\"\n    config[\"text_dir\"] = str(mediadir.joinpath(\"Text\"))\n    config[\"tex_dir\"] = str(mediadir.joinpath(\"Tex\"))\n    for el in [\"text_dir\", \"tex_dir\"]:\n        Path(config[el]).mkdir(parents=True, exist_ok=True)\n\n    # Before the refactoring of Mobject.copy(), the class BraceLabel was the\n    # only one to have a non-trivial definition of copy.  Here we test that it\n    # still works after the refactoring.\n    orig = BraceLabel(Mobject(), \"label\")\n    copy = orig.copy()\n\n    assert orig is orig\n    assert orig is not copy\n    assert orig.brace is not copy.brace\n    assert orig.label is not copy.label\n    assert orig.submobjects is not copy.submobjects\n    assert orig.submobjects[0] is orig.brace\n    assert copy.submobjects[0] is copy.brace\n    assert orig.submobjects[0] is not copy.brace\n    assert copy.submobjects[0] is not orig.brace\n\n    # Restore the original folders\n    config[\"text_dir\"] = original_text_dir\n    config[\"tex_dir\"] = original_tex_dir\n"
  },
  {
    "path": "tests/module/mobject/mobject/test_family.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim import RIGHT, Circle, Mobject\n\n\ndef test_family():\n    \"\"\"Check that the family is gathered correctly.\"\"\"\n    # Check that an empty mobject's family only contains itself\n    mob = Mobject()\n    assert mob.get_family() == [mob]\n\n    # Check that all children are in the family\n    mob = Mobject()\n    children = [Mobject() for _ in range(10)]\n    mob.add(*children)\n    family = mob.get_family()\n    assert len(family) == 1 + 10\n    assert mob in family\n    for c in children:\n        assert c in family\n\n    # Nested children should be in the family\n    mob = Mobject()\n    grandchildren = {}\n    for _ in range(10):\n        child = Mobject()\n        grandchildren[child] = [Mobject() for _ in range(10)]\n        child.add(*grandchildren[child])\n    mob.add(*list(grandchildren.keys()))\n    family = mob.get_family()\n    assert len(family) == 1 + 10 + 10 * 10\n    assert mob in family\n    for c in grandchildren:\n        assert c in family\n        for gc in grandchildren[c]:\n            assert gc in family\n\n\ndef test_overlapping_family():\n    \"\"\"Check that each member of the family is only gathered once.\"\"\"\n    (\n        mob,\n        child1,\n        child2,\n    ) = (\n        Mobject(),\n        Mobject(),\n        Mobject(),\n    )\n    gchild1, gchild2, gchild_common = Mobject(), Mobject(), Mobject()\n    child1.add(gchild1, gchild_common)\n    child2.add(gchild2, gchild_common)\n    mob.add(child1, child2)\n    family = mob.get_family()\n    assert mob in family\n    assert len(family) == 6\n    assert family.count(gchild_common) == 1\n\n\ndef test_shift_family():\n    \"\"\"Check that each member of the family is shifted along with the parent.\n\n    Importantly, here we add a common grandchild to each of the children.  So\n    this test will fail if the grandchild moves twice as much as it should.\n\n    \"\"\"\n    # Note shift() needs the mobject to have a non-empty `points` attribute, so\n    # we cannot use a plain Mobject or VMobject.  We use Circle instead.\n    (\n        mob,\n        child1,\n        child2,\n    ) = (\n        Circle(),\n        Circle(),\n        Circle(),\n    )\n    gchild1, gchild2, gchild_common = Circle(), Circle(), Circle()\n\n    child1.add(gchild1, gchild_common)\n    child2.add(gchild2, gchild_common)\n    mob.add(child1, child2)\n    family = mob.get_family()\n\n    positions_before = {m: m.get_center() for m in family}\n    mob.shift(RIGHT)\n    positions_after = {m: m.get_center() for m in family}\n\n    for m in family:\n        np.testing.assert_allclose(positions_before[m] + RIGHT, positions_after[m])\n"
  },
  {
    "path": "tests/module/mobject/mobject/test_get_set.py",
    "content": "from __future__ import annotations\n\nimport types\n\nimport pytest\n\nfrom manim.mobject.mobject import Mobject\n\n\ndef test_generic_set():\n    m = Mobject()\n    m.set(test=0)\n\n    assert m.test == 0\n\n\n@pytest.mark.filterwarnings(\"ignore::DeprecationWarning\")\ndef test_get_compat_layer():\n    m = Mobject()\n\n    assert isinstance(m.get_test, types.MethodType)\n    with pytest.raises(AttributeError):\n        m.get_test()\n\n    m.test = 0\n    assert m.get_test() == 0\n\n\n@pytest.mark.filterwarnings(\"ignore::DeprecationWarning\")\ndef test_set_compat_layer():\n    m = Mobject()\n\n    assert isinstance(m.set_test, types.MethodType)\n    m.set_test(0)\n\n    assert m.test == 0\n\n\ndef test_nonexistent_attr():\n    m = Mobject()\n\n    with pytest.raises(AttributeError, match=\"object has no attribute\"):\n        m.test\n"
  },
  {
    "path": "tests/module/mobject/mobject/test_mobject.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport pytest\n\nfrom manim import DL, PI, UR, Circle, Mobject, Rectangle, Square, Triangle, VGroup\n\n\ndef test_mobject_add():\n    \"\"\"Test Mobject.add().\"\"\"\n    \"\"\"Call this function with a Container instance to test its add() method.\"\"\"\n    # check that obj.submobjects is updated correctly\n    obj = Mobject()\n    assert len(obj.submobjects) == 0\n    obj.add(Mobject())\n    assert len(obj.submobjects) == 1\n    obj.add(*(Mobject() for _ in range(10)))\n    assert len(obj.submobjects) == 11\n\n    # check that adding a mobject twice does not actually add it twice\n    repeated = Mobject()\n    obj.add(repeated)\n    assert len(obj.submobjects) == 12\n    obj.add(repeated)\n    assert len(obj.submobjects) == 12\n\n    # check that Mobject.add() returns the Mobject (for chained calls)\n    assert obj.add(Mobject()) is obj\n    assert len(obj.submobjects) == 13\n\n    obj = Mobject()\n\n    # a Mobject cannot contain itself\n    with pytest.raises(ValueError) as add_self_info:\n        obj.add(Mobject(), obj, Mobject())\n    assert str(add_self_info.value) == (\n        \"Cannot add Mobject as a submobject of itself (at index 1).\"\n    )\n    assert len(obj.submobjects) == 0\n\n    # can only add Mobjects\n    with pytest.raises(TypeError) as add_str_info:\n        obj.add(Mobject(), Mobject(), \"foo\")\n    assert str(add_str_info.value) == (\n        \"Only values of type Mobject can be added as submobjects of Mobject, \"\n        \"but the value foo (at index 2) is of type str.\"\n    )\n    assert len(obj.submobjects) == 0\n\n\ndef test_mobject_remove():\n    \"\"\"Test Mobject.remove().\"\"\"\n    obj = Mobject()\n    to_remove = Mobject()\n    obj.add(to_remove)\n    obj.add(*(Mobject() for _ in range(10)))\n    assert len(obj.submobjects) == 11\n    obj.remove(to_remove)\n    assert len(obj.submobjects) == 10\n    obj.remove(to_remove)\n    assert len(obj.submobjects) == 10\n\n    assert obj.remove(Mobject()) is obj\n\n\ndef test_mobject_dimensions_single_mobject():\n    # A Mobject with no points and no submobjects has no dimensions\n    empty = Mobject()\n    assert empty.width == 0\n    assert empty.height == 0\n    assert empty.depth == 0\n\n    has_points = Mobject()\n    has_points.points = np.array([[-1, -2, -3], [1, 3, 5]])\n    assert has_points.width == 2\n    assert has_points.height == 5\n    assert has_points.depth == 8\n\n    rect = Rectangle(width=3, height=5)\n\n    assert rect.width == 3\n    assert rect.height == 5\n    assert rect.depth == 0\n\n    # Dimensions should be recalculated after scaling\n    rect.scale(2.0)\n    assert rect.width == 6\n    assert rect.height == 10\n    assert rect.depth == 0\n\n    # Dimensions should not be dependent on location\n    rect.move_to([-3, -4, -5])\n    assert rect.width == 6\n    assert rect.height == 10\n    assert rect.depth == 0\n\n    circ = Circle(radius=2)\n\n    assert circ.width == 4\n    assert circ.height == 4\n    assert circ.depth == 0\n\n\ndef is_close(x, y):\n    return abs(x - y) < 0.00001\n\n\ndef test_mobject_dimensions_nested_mobjects():\n    vg = VGroup()\n\n    for x in range(-5, 8, 1):\n        row = VGroup()\n        vg += row\n        for y in range(-17, 2, 1):\n            for z in range(0, 10, 1):\n                s = Square().move_to([x, y, z / 10])\n                row += s\n\n    assert vg.width == 14.0, vg.width\n    assert vg.height == 20.0, vg.height\n    assert is_close(vg.depth, 0.9), vg.depth\n\n    # Dimensions should be recalculated after scaling\n    vg.scale(0.5)\n    assert vg.width == 7.0, vg.width\n    assert vg.height == 10.0, vg.height\n    assert is_close(vg.depth, 0.45), vg.depth\n\n    # Adding a mobject changes the bounds/dimensions\n    rect = Rectangle(width=3, height=5)\n    rect.move_to([9, 3, 1])\n    vg += rect\n    assert vg.width == 13.0, vg.width\n    assert is_close(vg.height, 18.5), vg.height\n    assert is_close(vg.depth, 0.775), vg.depth\n\n\ndef test_mobject_dimensions_mobjects_with_no_points_are_at_origin():\n    rect = Rectangle(width=2, height=3)\n    rect.move_to([-4, -5, 0])\n    outer_group = VGroup(rect)\n\n    # This is as one would expect\n    assert outer_group.width == 2\n    assert outer_group.height == 3\n\n    # Adding a mobject with no points has a quirk of adding a \"point\"\n    # to [0, 0, 0] (the origin). This changes the size of the outer\n    # group because now the bottom left corner is at [-5, -6.5, 0]\n    # but the upper right corner is [0, 0, 0] instead of [-3, -3.5, 0]\n    outer_group.add(VGroup())\n    assert outer_group.width == 5\n    assert outer_group.height == 6.5\n\n\ndef test_mobject_dimensions_has_points_and_children():\n    outer_rect = Rectangle(width=3, height=6)\n    inner_rect = Rectangle(width=2, height=1)\n    inner_rect.align_to(outer_rect.get_corner(UR), DL)\n    outer_rect.add(inner_rect)\n\n    # The width of a mobject should depend both on its points and\n    # the points of all children mobjects.\n    assert outer_rect.width == 5  # 3 from outer_rect, 2 from inner_rect\n    assert outer_rect.height == 7  # 6 from outer_rect, 1 from inner_rect\n    assert outer_rect.depth == 0\n\n    assert inner_rect.width == 2\n    assert inner_rect.height == 1\n    assert inner_rect.depth == 0\n\n\ndef test_rotate_about_vertex_view():\n    \"\"\"Test that rotating about a vertex obtained from get_vertices() works correctly.\n\n    This is a regression test for an issue where get_vertices() returns a view of the points array,\n    and using it as about_point in rotate() would cause the view to be mutated.\n    \"\"\"\n    triangle = Triangle()\n    original_vertices = triangle.get_vertices().copy()\n    first_vertex = original_vertices[0].copy()\n\n    # This should rotate about the first vertex without corrupting it\n    triangle.rotate(PI / 2, about_point=triangle.get_vertices()[0])\n\n    # The first vertex should remain in the same position (within numerical precision)\n    rotated_vertices = triangle.get_vertices()\n    np.testing.assert_allclose(rotated_vertices[0], first_vertex, atol=1e-6)\n\n\ndef test_scale_about_vertex_view():\n    \"\"\"Test that scaling about a vertex obtained from get_vertices() works correctly.\n\n    This is a regression test for an issue where get_vertices() returns a view of the points array,\n    and using it as about_point in scale() would cause the view to be mutated.\n    \"\"\"\n    triangle = Triangle()\n    original_vertices = triangle.get_vertices().copy()\n    first_vertex = original_vertices[0].copy()\n\n    # This should scale about the first vertex without corrupting it\n    triangle.scale(2, about_point=triangle.get_vertices()[0])\n\n    # The first vertex should remain in the same position (within numerical precision)\n    scaled_vertices = triangle.get_vertices()\n    np.testing.assert_allclose(scaled_vertices[0], first_vertex, atol=1e-6)\n\n\ndef test_stretch_about_vertex_view():\n    \"\"\"Test that stretching about a vertex obtained from get_vertices() works correctly.\n\n    This is a regression test for an issue where get_vertices() returns a view of the points array,\n    and using it as about_point in stretch() would cause the view to be mutated.\n    \"\"\"\n    triangle = Triangle()\n    original_vertices = triangle.get_vertices().copy()\n    first_vertex = original_vertices[0].copy()\n\n    # This should stretch about the first vertex without corrupting it\n    triangle.stretch(2, 0, about_point=triangle.get_vertices()[0])\n\n    # The first vertex should remain in the same position (within numerical precision)\n    stretched_vertices = triangle.get_vertices()\n    np.testing.assert_allclose(stretched_vertices[0], first_vertex, atol=1e-6)\n\n\ndef test_apply_matrix_about_vertex_view():\n    \"\"\"Test that apply_matrix about a vertex obtained from get_vertices() works correctly.\n\n    This is a regression test for an issue where get_vertices() returns a view of the points array,\n    and using it as about_point in apply_matrix() would cause the view to be mutated.\n    \"\"\"\n    triangle = Triangle()\n    original_vertices = triangle.get_vertices().copy()\n    first_vertex = original_vertices[0].copy()\n\n    # Define a rotation matrix (90 degrees rotation around z-axis)\n    rotation_matrix = np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]])\n\n    # This should apply the matrix about the first vertex without corrupting it\n    triangle.apply_matrix(rotation_matrix, about_point=triangle.get_vertices()[0])\n\n    # The first vertex should remain in the same position (within numerical precision)\n    transformed_vertices = triangle.get_vertices()\n    np.testing.assert_allclose(transformed_vertices[0], first_vertex, atol=1e-6)\n"
  },
  {
    "path": "tests/module/mobject/mobject/test_opengl_metaclass.py",
    "content": "from __future__ import annotations\n\nfrom manim import Mobject\nfrom manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\n\n\ndef test_metaclass_registry(config):\n    class SomeTestMobject(Mobject, metaclass=ConvertToOpenGL):\n        pass\n\n    assert SomeTestMobject in ConvertToOpenGL._converted_classes\n\n    config.renderer = \"opengl\"\n    assert OpenGLMobject in SomeTestMobject.__bases__\n    assert Mobject not in SomeTestMobject.__bases__\n\n    config.renderer = \"cairo\"\n    assert Mobject in SomeTestMobject.__bases__\n    assert OpenGLMobject not in SomeTestMobject.__bases__\n"
  },
  {
    "path": "tests/module/mobject/mobject/test_set_attr.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim.constants import RIGHT\nfrom manim.mobject.geometry.polygram import Square\n\n\ndef test_Data(using_opengl_renderer):\n    a = Square().move_to(RIGHT)\n    data_bb = a.data[\"bounding_box\"]\n    np.testing.assert_array_equal(\n        data_bb,\n        np.array([[0.0, -1.0, 0.0], [1.0, 0.0, 0.0], [2.0, 1.0, 0.0]]),\n    )\n\n    # test that calling the attribute equals calling it from self.data\n    np.testing.assert_array_equal(a.bounding_box, data_bb)\n\n    # test that the array can be indexed\n    np.testing.assert_array_equal(\n        a.bounding_box[1],\n        np.array(\n            [1.0, 0.0, 0.0],\n        ),\n    )\n\n    # test that a value can be set\n    a.bounding_box[1] = 300\n\n    # test that both the attr and self.data arrays match after adjusting a value\n\n    data_bb = a.data[\"bounding_box\"]\n    np.testing.assert_array_equal(\n        data_bb,\n        np.array([[0.0, -1.0, 0.0], [300.0, 300.0, 300.0], [2.0, 1.0, 0.0]]),\n    )\n\n    np.testing.assert_array_equal(a.bounding_box, data_bb)\n"
  },
  {
    "path": "tests/module/mobject/svg/test_svg_mobject.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom tests.helpers.path_utils import get_svg_resource\n\n\ndef test_set_fill_color():\n    expected_color = \"#FF862F\"\n    svg = SVGMobject(get_svg_resource(\"heart.svg\"), fill_color=expected_color)\n    assert svg.fill_color.to_hex() == expected_color\n\n\ndef test_set_stroke_color():\n    expected_color = \"#FFFDDD\"\n    svg = SVGMobject(get_svg_resource(\"heart.svg\"), stroke_color=expected_color)\n    assert svg.stroke_color.to_hex() == expected_color\n\n\ndef test_set_color_sets_fill_and_stroke():\n    expected_color = \"#EEE777\"\n    svg = SVGMobject(get_svg_resource(\"heart.svg\"), color=expected_color)\n    assert svg.color.to_hex() == expected_color\n    assert svg.fill_color.to_hex() == expected_color\n    assert svg.stroke_color.to_hex() == expected_color\n\n\ndef test_set_fill_opacity():\n    expected_opacity = 0.5\n    svg = SVGMobject(get_svg_resource(\"heart.svg\"), fill_opacity=expected_opacity)\n    assert svg.fill_opacity == expected_opacity\n\n\ndef test_stroke_opacity():\n    expected_opacity = 0.4\n    svg = SVGMobject(get_svg_resource(\"heart.svg\"), stroke_opacity=expected_opacity)\n    assert svg.stroke_opacity == expected_opacity\n\n\ndef test_fill_overrides_color():\n    expected_color = \"#343434\"\n    svg = SVGMobject(\n        get_svg_resource(\"heart.svg\"),\n        color=\"#123123\",\n        fill_color=expected_color,\n    )\n    assert svg.fill_color.to_hex() == expected_color\n\n\ndef test_stroke_overrides_color():\n    expected_color = \"#767676\"\n    svg = SVGMobject(\n        get_svg_resource(\"heart.svg\"),\n        color=\"#334433\",\n        stroke_color=expected_color,\n    )\n    assert svg.stroke_color.to_hex() == expected_color\n\n\ndef test_single_path_turns_into_sequence_of_points():\n    svg = SVGMobject(\n        get_svg_resource(\"cubic_and_lineto.svg\"),\n    )\n    assert len(svg.points) == 0, svg.points\n    assert len(svg.submobjects) == 1, svg.submobjects\n    path = svg.submobjects[0]\n    np.testing.assert_almost_equal(\n        path.points,\n        np.array(\n            [\n                [-0.166666666666666, 0.66666666666666, 0.0],\n                [-0.166666666666666, 0.0, 0.0],\n                [0.5, 0.66666666666666, 0.0],\n                [0.5, 0.0, 0.0],\n                [0.5, 0.0, 0.0],\n                [-0.16666666666666666, 0.0, 0.0],\n                [0.5, -0.6666666666666666, 0.0],\n                [-0.166666666666666, -0.66666666666666, 0.0],\n                [-0.166666666666666, -0.66666666666666, 0.0],\n                [-0.27777777777777, -0.77777777777777, 0.0],\n                [-0.38888888888888, -0.88888888888888, 0.0],\n                [-0.5, -1.0, 0.0],\n                [-0.5, -1.0, 0.0],\n                [-0.5, -0.333333333333, 0.0],\n                [-0.5, 0.3333333333333, 0.0],\n                [-0.5, 1.0, 0.0],\n                [-0.5, 1.0, 0.0],\n                [-0.38888888888888, 0.8888888888888, 0.0],\n                [-0.27777777777777, 0.7777777777777, 0.0],\n                [-0.16666666666666, 0.6666666666666, 0.0],\n            ]\n        ),\n        decimal=5,\n    )\n\n\ndef test_closed_path_does_not_have_extra_point():\n    # This dash.svg is the output of a \"-\" as generated from LaTex.\n    # It ends back where it starts, so we shouldn't see a final line.\n    svg = SVGMobject(\n        get_svg_resource(\"dash.svg\"),\n    )\n    assert len(svg.points) == 0, svg.points\n    assert len(svg.submobjects) == 1, svg.submobjects\n    dash = svg.submobjects[0]\n    np.testing.assert_almost_equal(\n        dash.points,\n        np.array(\n            [\n                [13.524988331417841, -1.0, 0],\n                [14.374988080480586, -1.0, 0],\n                [15.274984567359079, -1.0, 0],\n                [15.274984567359079, 0.0, 0.0],\n                [15.274984567359079, 0.0, 0.0],\n                [15.274984567359079, 1.0, 0.0],\n                [14.374988080480586, 1.0, 0.0],\n                [13.524988331417841, 1.0, 0.0],\n                [13.524988331417841, 1.0, 0.0],\n                [4.508331116720995, 1.0, 0],\n                [-4.508326097975995, 1.0, 0.0],\n                [-13.524983312672841, 1.0, 0.0],\n                [-13.524983312672841, 1.0, 0.0],\n                [-14.374983061735586, 1.0, 0.0],\n                [-15.274984567359079, 1.0, 0.0],\n                [-15.274984567359079, 0.0, 0.0],\n                [-15.274984567359079, 0.0, 0.0],\n                [-15.274984567359079, -1.0, 0],\n                [-14.374983061735586, -1.0, 0],\n                [-13.524983312672841, -1.0, 0],\n                [-13.524983312672841, -1.0, 0],\n                [-4.508326097975995, -1.0, 0],\n                [4.508331116720995, -1.0, 0],\n                [13.524988331417841, -1.0, 0],\n            ]\n        ),\n        decimal=5,\n    )\n\n\ndef test_close_command_closes_last_move_not_the_starting_one():\n    # This A.svg is the output of a Text(\"A\") in some systems\n    # It contains a path that moves from the outer boundary of the A\n    # to the boundary of the inner triangle, and then closes the path\n    # which should close the inner triangle and not the outer boundary.\n    svg = SVGMobject(\n        get_svg_resource(\"A.svg\"),\n    )\n    assert len(svg.points) == 0, svg.points\n    assert len(svg.submobjects) == 1, svg.submobjects\n    capital_A = svg.submobjects[0]\n\n    # The last point should not be the same as the first point\n    assert not all(capital_A.points[0] == capital_A.points[-1])\n    np.testing.assert_almost_equal(\n        capital_A.points,\n        np.array(\n            [\n                [-0.8380339075214888, -1.0, 1.2246467991473532e-16],\n                [-0.6132152047642527, -0.3333333333333336, 4.082155997157847e-17],\n                [-0.388396502007016, 0.3333333333333336, -4.082155997157847e-17],\n                [-0.16357779924977994, 1.0, -1.2246467991473532e-16],\n                [-0.16357779924977994, 1.0, -1.2246467991473532e-16],\n                [-0.05425733591657368, 1.0, -1.2246467991473532e-16],\n                [0.05506312741663405, 1.0, -1.2246467991473532e-16],\n                [0.16438359074984032, 1.0, -1.2246467991473532e-16],\n                [0.16438359074984032, 1.0, -1.2246467991473532e-16],\n                [0.3889336963403905, 0.3333333333333336, -4.082155997157847e-17],\n                [0.6134838019309422, -0.3333333333333336, 4.082155997157847e-17],\n                [0.8380339075214923, -1.0, 1.2246467991473532e-16],\n                [0.8380339075214923, -1.0, 1.2246467991473532e-16],\n                [0.744560897060354, -1.0, 1.2246467991473532e-16],\n                [0.6510878865992157, -1.0, 1.2246467991473532e-16],\n                [0.5576148761380774, -1.0, 1.2246467991473532e-16],\n                [0.5576148761380774, -1.0, 1.2246467991473532e-16],\n                [0.49717968849274957, -0.8138597980824822, 9.966907966764229e-17],\n                [0.4367445008474217, -0.6277195961649644, 7.687347942054928e-17],\n                [0.3763093132020939, -0.4415793942474466, 5.407787917345625e-17],\n                [0.3763093132020939, -0.4415793942474466, 5.407787917345625e-17],\n                [0.12167600863867864, -0.4415793942474466, 5.407787917345625e-17],\n                [-0.13295729592473662, -0.4415793942474466, 5.407787917345625e-17],\n                [-0.38759060048815186, -0.4415793942474466, 5.407787917345625e-17],\n                [-0.38759060048815186, -0.4415793942474466, 5.407787917345625e-17],\n                [-0.4480257881334797, -0.6277195961649644, 7.687347942054928e-17],\n                [-0.5084609757788076, -0.8138597980824822, 9.966907966764229e-17],\n                [-0.5688961634241354, -1.0, 1.2246467991473532e-16],\n                [-0.5688961634241354, -1.0, 1.2246467991473532e-16],\n                [-0.6586087447899202, -1.0, 1.2246467991473532e-16],\n                [-0.7483213261557048, -1.0, 1.2246467991473532e-16],\n                [-0.8380339075214888, -1.0, 1.2246467991473532e-16],\n                [0.3021757525699033, -0.21434317946653003, 2.6249468865275272e-17],\n                [0.1993017037512583, 0.09991949373745423, -1.2236608817799732e-17],\n                [0.09642765493261184, 0.4141821669414385, -5.072268650087473e-17],\n                [-0.006446393886033166, 0.7284448401454228, -8.920876418394973e-17],\n                [-0.006446393886033166, 0.7284448401454228, -8.920876418394973e-17],\n                [-0.10905185929034443, 0.4141821669414385, -5.072268650087473e-17],\n                [-0.2116573246946542, 0.09991949373745423, -1.2236608817799732e-17],\n                [-0.31426279009896546, -0.21434317946653003, 2.6249468865275272e-17],\n                [-0.31426279009896546, -0.21434317946653003, 2.6249468865275272e-17],\n                [-0.10878327587600921, -0.21434317946653003, 2.6249468865275272e-17],\n                [0.09669623834694704, -0.21434317946653003, 2.6249468865275272e-17],\n                [0.3021757525699033, -0.21434317946653003, 2.6249468865275272e-17],\n            ]\n        ),\n        decimal=5,\n    )\n"
  },
  {
    "path": "tests/module/mobject/test_boolean_ops.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport pytest\n\nfrom manim import Circle, Square\nfrom manim.mobject.geometry.boolean_ops import _BooleanOps\n\n\n@pytest.mark.parametrize(\n    (\"test_input\", \"expected\"),\n    [\n        (\n            [(1.0, 2.0), (3.0, 4.0)],\n            [\n                np.array([1.0, 2.0, 0]),\n                np.array([3.0, 4.0, 0]),\n            ],\n        ),\n        (\n            [(1.1, 2.2)],\n            [\n                np.array([1.1, 2.2, 0.0]),\n            ],\n        ),\n    ],\n)\ndef test_convert_2d_to_3d_array(test_input, expected):\n    a = _BooleanOps()\n    result = a._convert_2d_to_3d_array(test_input)\n    assert len(result) == len(expected)\n    for i in range(len(result)):\n        assert (result[i] == expected[i]).all()\n\n\ndef test_convert_2d_to_3d_array_zdim():\n    a = _BooleanOps()\n    result = a._convert_2d_to_3d_array([(1.0, 2.0)], z_dim=1.0)\n    assert (result[0] == np.array([1.0, 2.0, 1.0])).all()\n\n\n@pytest.mark.parametrize(\n    \"test_input\",\n    [\n        Square(),\n        Circle(),\n        Square(side_length=4),\n        Circle(radius=3),\n    ],\n)\ndef test_vmobject_to_skia_path_and_inverse(test_input):\n    a = _BooleanOps()\n    path = a._convert_vmobject_to_skia_path(test_input)\n    assert len(list(path.segments)) > 1\n\n    new_vmobject = a._convert_skia_path_to_vmobject(path)\n    # for some reason there is an extra 4 points in new vmobject than original\n    np.testing.assert_allclose(new_vmobject.points[:-4], test_input.points)\n"
  },
  {
    "path": "tests/module/mobject/test_graph.py",
    "content": "from __future__ import annotations\n\nimport pytest\n\nfrom manim import DiGraph, Graph, LabeledLine, Scene, Text, tempconfig\nfrom manim.mobject.graph import _layouts\n\n\ndef test_graph_creation():\n    vertices = [1, 2, 3, 4]\n    edges = [(1, 2), (2, 3), (3, 4), (4, 1)]\n    layout = {1: [0, 0, 0], 2: [1, 1, 0], 3: [1, -1, 0], 4: [-1, 0, 0]}\n    G_manual = Graph(vertices=vertices, edges=edges, layout=layout)\n    assert str(G_manual) == \"Undirected graph on 4 vertices and 4 edges\"\n    G_spring = Graph(vertices=vertices, edges=edges)\n    assert str(G_spring) == \"Undirected graph on 4 vertices and 4 edges\"\n    G_directed = DiGraph(vertices=vertices, edges=edges)\n    assert str(G_directed) == \"Directed graph on 4 vertices and 4 edges\"\n\n\ndef test_graph_add_vertices():\n    G = Graph([1, 2, 3], [(1, 2), (2, 3)])\n    G.add_vertices(4)\n    assert str(G) == \"Undirected graph on 4 vertices and 2 edges\"\n    G.add_vertices(5, labels={5: Text(\"5\")})\n    assert str(G) == \"Undirected graph on 5 vertices and 2 edges\"\n    assert 5 in G._labels\n    assert 5 in G._vertex_config\n    G.add_vertices(6, 7, 8)\n    assert len(G.vertices) == 8\n    assert len(G._graph.nodes()) == 8\n\n\ndef test_graph_remove_vertices():\n    G = Graph([1, 2, 3, 4, 5], [(1, 2), (2, 3), (3, 4), (4, 5)])\n    removed_mobjects = G.remove_vertices(3)\n    assert len(removed_mobjects) == 3\n    assert str(G) == \"Undirected graph on 4 vertices and 2 edges\"\n    assert list(G.vertices.keys()) == [1, 2, 4, 5]\n    assert list(G.edges.keys()) == [(1, 2), (4, 5)]\n    removed_mobjects = G.remove_vertices(4, 5)\n    assert len(removed_mobjects) == 3\n    assert str(G) == \"Undirected graph on 2 vertices and 1 edges\"\n    assert list(G.vertices.keys()) == [1, 2]\n    assert list(G.edges.keys()) == [(1, 2)]\n\n\ndef test_graph_add_edges():\n    G = Graph([1, 2, 3, 4, 5], [(1, 2), (2, 3)])\n    added_mobjects = G.add_edges((1, 3))\n    assert str(added_mobjects.submobjects) == \"[Line]\"\n    assert str(G) == \"Undirected graph on 5 vertices and 3 edges\"\n    assert set(G.vertices.keys()) == {1, 2, 3, 4, 5}\n    assert set(G.edges.keys()) == {(1, 2), (2, 3), (1, 3)}\n\n    added_mobjects = G.add_edges((1, 42))\n    assert str(added_mobjects.submobjects) == \"[Dot, Line]\"\n    assert str(G) == \"Undirected graph on 6 vertices and 4 edges\"\n    assert set(G.vertices.keys()) == {1, 2, 3, 4, 5, 42}\n    assert set(G.edges.keys()) == {(1, 2), (2, 3), (1, 3), (1, 42)}\n\n    added_mobjects = G.add_edges((4, 5), (5, 6), (6, 7))\n    assert len(added_mobjects) == 5\n    assert str(G) == \"Undirected graph on 8 vertices and 7 edges\"\n    assert set(G.vertices.keys()) == {1, 2, 3, 4, 5, 42, 6, 7}\n    assert set(G._graph.nodes()) == set(G.vertices.keys())\n    assert set(G.edges.keys()) == {\n        (1, 2),\n        (2, 3),\n        (1, 3),\n        (1, 42),\n        (4, 5),\n        (5, 6),\n        (6, 7),\n    }\n    assert set(G._graph.edges()) == set(G.edges.keys())\n\n\ndef test_graph_remove_edges():\n    G = Graph([1, 2, 3, 4, 5], [(1, 2), (2, 3), (3, 4), (4, 5), (1, 5)])\n    removed_mobjects = G.remove_edges((1, 2))\n    assert str(removed_mobjects.submobjects) == \"[Line]\"\n    assert str(G) == \"Undirected graph on 5 vertices and 4 edges\"\n    assert set(G.edges.keys()) == {(2, 3), (3, 4), (4, 5), (1, 5)}\n    assert set(G._graph.edges()) == set(G.edges.keys())\n\n    removed_mobjects = G.remove_edges((2, 3), (3, 4), (4, 5), (1, 5))\n    assert len(removed_mobjects) == 4\n    assert str(G) == \"Undirected graph on 5 vertices and 0 edges\"\n    assert set(G._graph.edges()) == set()\n    assert set(G.edges.keys()) == set()\n\n\ndef test_graph_accepts_labeledline_as_edge_type():\n    vertices = [1, 2, 3, 4]\n    edges = [(1, 2), (2, 3), (3, 4), (4, 1)]\n    edge_config = {\n        (1, 2): {\"label\": \"A\"},\n        (2, 3): {\"label\": \"B\"},\n        (3, 4): {\"label\": \"C\"},\n        (4, 1): {\"label\": \"D\"},\n    }\n    G_manual = Graph(vertices, edges, edge_type=LabeledLine, edge_config=edge_config)\n    G_directed = DiGraph(\n        vertices, edges, edge_type=LabeledLine, edge_config=edge_config\n    )\n\n    for edge_obj in G_manual.edges.values():\n        assert isinstance(edge_obj, LabeledLine)\n        assert hasattr(edge_obj, \"label\")\n\n    for edge_obj in G_directed.edges.values():\n        assert isinstance(edge_obj, LabeledLine)\n        assert hasattr(edge_obj, \"label\")\n\n\ndef test_custom_animation_mobject_list():\n    G = Graph([1, 2, 3], [(1, 2), (2, 3)])\n    scene = Scene()\n    scene.add(G)\n    assert scene.mobjects == [G]\n    with tempconfig({\"dry_run\": True, \"quality\": \"low_quality\"}):\n        scene.play(G.animate.add_vertices(4))\n        assert str(G) == \"Undirected graph on 4 vertices and 2 edges\"\n        assert scene.mobjects == [G]\n        scene.play(G.animate.remove_vertices(2))\n        assert str(G) == \"Undirected graph on 3 vertices and 0 edges\"\n        assert scene.mobjects == [G]\n\n\ndef test_custom_graph_layout_dict():\n    G = Graph(\n        [1, 2, 3], [(1, 2), (2, 3)], layout={1: [0, 0, 0], 2: [1, 1, 0], 3: [1, -1, 0]}\n    )\n    assert str(G) == \"Undirected graph on 3 vertices and 2 edges\"\n    assert all(G.vertices[1].get_center() == [0, 0, 0])\n    assert all(G.vertices[2].get_center() == [1, 1, 0])\n    assert all(G.vertices[3].get_center() == [1, -1, 0])\n\n\ndef test_graph_layouts():\n    for layout in (layout for layout in _layouts if layout not in [\"tree\", \"partite\"]):\n        G = Graph([1, 2, 3], [(1, 2), (2, 3)], layout=layout)\n        assert str(G) == \"Undirected graph on 3 vertices and 2 edges\"\n\n\ndef test_tree_layout():\n    G = Graph([1, 2, 3], [(1, 2), (2, 3)], layout=\"tree\", root_vertex=1)\n    assert str(G) == \"Undirected graph on 3 vertices and 2 edges\"\n\n\ndef test_partite_layout():\n    G = Graph(\n        [1, 2, 3, 4, 5],\n        [(1, 2), (2, 3), (3, 4), (4, 5)],\n        layout=\"partite\",\n        partitions=[[1, 2], [3, 4, 5]],\n    )\n    assert str(G) == \"Undirected graph on 5 vertices and 4 edges\"\n\n\ndef test_custom_graph_layout_function():\n    def layout_func(graph, scale):\n        return {vertex: [vertex, vertex, 0] for vertex in graph}\n\n    G = Graph([1, 2, 3], [(1, 2), (2, 3)], layout=layout_func)\n    assert all(G.vertices[1].get_center() == [1, 1, 0])\n    assert all(G.vertices[2].get_center() == [2, 2, 0])\n    assert all(G.vertices[3].get_center() == [3, 3, 0])\n\n\ndef test_custom_graph_layout_function_with_kwargs():\n    def layout_func(graph, scale, offset):\n        return {\n            vertex: [vertex * scale + offset, vertex * scale + offset, 0]\n            for vertex in graph\n        }\n\n    G = Graph(\n        [1, 2, 3], [(1, 2), (2, 3)], layout=layout_func, layout_config={\"offset\": 1}\n    )\n    assert all(G.vertices[1].get_center() == [3, 3, 0])\n    assert all(G.vertices[2].get_center() == [5, 5, 0])\n    assert all(G.vertices[3].get_center() == [7, 7, 0])\n\n\ndef test_graph_change_layout():\n    for layout in (layout for layout in _layouts if layout not in [\"tree\", \"partite\"]):\n        G = Graph([1, 2, 3], [(1, 2), (2, 3)])\n        G.change_layout(layout=layout)\n        assert str(G) == \"Undirected graph on 3 vertices and 2 edges\"\n\n\ndef test_tree_layout_no_root_error():\n    with pytest.raises(ValueError) as excinfo:\n        G = Graph([1, 2, 3], [(1, 2), (2, 3)], layout=\"tree\")\n    assert str(excinfo.value) == \"The tree layout requires the root_vertex parameter\"\n\n\ndef test_tree_layout_not_tree_error():\n    with pytest.raises(ValueError) as excinfo:\n        G = Graph([1, 2, 3], [(1, 2), (2, 3), (3, 1)], layout=\"tree\", root_vertex=1)\n    assert str(excinfo.value) == \"The tree layout must be used with trees\"\n"
  },
  {
    "path": "tests/module/mobject/test_image.py",
    "content": "import numpy as np\nimport pytest\n\nfrom manim import ImageMobject\n\n\n@pytest.mark.parametrize(\"dtype\", [np.uint8, np.uint16])\ndef test_invert_image(dtype):\n    rng = np.random.default_rng()\n    array = (255 * rng.random((10, 10, 4))).astype(dtype)\n    image = ImageMobject(array, pixel_array_dtype=dtype, invert=True)\n    assert image.pixel_array.dtype == dtype\n\n    array[:, :, :3] = np.iinfo(dtype).max - array[:, :, :3]\n    assert np.allclose(array, image.pixel_array)\n"
  },
  {
    "path": "tests/module/mobject/test_matrix.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport pytest\n\nfrom manim.mobject.matrix import (\n    DecimalMatrix,\n    IntegerMatrix,\n    Matrix,\n)\nfrom manim.mobject.text.tex_mobject import MathTex\nfrom manim.mobject.types.vectorized_mobject import VGroup\n\n\nclass TestMatrix:\n    @pytest.mark.parametrize(\n        (\n            \"matrix_elements\",\n            \"left_bracket\",\n            \"right_bracket\",\n            \"expected_rows\",\n            \"expected_columns\",\n        ),\n        [\n            ([[1, 2], [3, 4]], \"[\", \"]\", 2, 2),\n            ([[1, 2, 3]], \"[\", \"]\", 1, 3),\n            ([[1], [2], [3]], \"[\", \"]\", 3, 1),\n            ([[5]], \"[\", \"]\", 1, 1),\n            ([[1, 0], [0, 1]], \"(\", \")\", 2, 2),\n            ([[\"a\", \"b\"], [\"c\", \"d\"]], \"[\", \"]\", 2, 2),\n            (np.array([[10, 20], [30, 40]]), \"[\", \"]\", 2, 2),\n        ],\n        ids=[\n            \"2x2_default\",\n            \"1x3_default\",\n            \"3x1_default\",\n            \"1x1_default\",\n            \"2x2_parentheses\",\n            \"2x2_strings\",\n            \"2x2_numpy\",\n        ],\n    )\n    def test_matrix_init_valid(\n        self,\n        matrix_elements,\n        left_bracket,\n        right_bracket,\n        expected_rows,\n        expected_columns,\n    ):\n        matrix = Matrix(\n            matrix_elements, left_bracket=left_bracket, right_bracket=right_bracket\n        )\n\n        assert isinstance(matrix, Matrix)\n        assert matrix.left_bracket == left_bracket\n        assert matrix.right_bracket == right_bracket\n        assert len(matrix.get_rows()) == expected_rows\n        assert len(matrix.get_columns()) == expected_columns\n\n    @pytest.mark.parametrize(\n        (\"invalid_elements\", \"expected_error\"),\n        [\n            (10, TypeError),\n            (10.4, TypeError),\n            ([1, 2, 3], TypeError),\n        ],\n        ids=[\n            \"integer\",\n            \"float\",\n            \"flat_list\",\n        ],\n    )\n    def test_matrix_init_invalid(self, invalid_elements, expected_error):\n        with pytest.raises(expected_error):\n            Matrix(invalid_elements)\n\n    @pytest.mark.parametrize(\n        (\"matrix_elements\", \"expected_columns\"),\n        [\n            ([[1, 2], [3, 4]], 2),\n            ([[1, 2, 3]], 3),\n            ([[1], [2], [3]], 1),\n        ],\n        ids=[\"2x2\", \"1x3\", \"3x1\"],\n    )\n    def test_get_columns(self, matrix_elements, expected_columns):\n        matrix = Matrix(matrix_elements)\n\n        assert isinstance(matrix, Matrix)\n        assert len(matrix.get_columns()) == expected_columns\n        for column in matrix.get_columns():\n            assert isinstance(column, VGroup)\n\n    @pytest.mark.parametrize(\n        (\"matrix_elements\", \"expected_rows\"),\n        [\n            ([[1, 2], [3, 4]], 2),\n            ([[1, 2, 3]], 1),\n            ([[1], [2], [3]], 3),\n        ],\n        ids=[\"2x2\", \"1x3\", \"3x1\"],\n    )\n    def test_get_rows(self, matrix_elements, expected_rows):\n        matrix = Matrix(matrix_elements)\n\n        assert isinstance(matrix, Matrix)\n        assert len(matrix.get_rows()) == expected_rows\n        for row in matrix.get_rows():\n            assert isinstance(row, VGroup)\n\n    @pytest.mark.parametrize(\n        (\"matrix_elements\", \"expected_entries_tex_string\", \"expected_entries_count\"),\n        [\n            ([[1, 2], [3, 4]], [\"1\", \"2\", \"3\", \"4\"], 4),\n            ([[1, 2, 3]], [\"1\", \"2\", \"3\"], 3),\n        ],\n        ids=[\"2x2\", \"1x3\"],\n    )\n    def test_get_entries(\n        self, matrix_elements, expected_entries_tex_string, expected_entries_count\n    ):\n        matrix = Matrix(matrix_elements)\n        entries = matrix.get_entries()\n\n        assert isinstance(matrix, Matrix)\n        assert len(entries) == expected_entries_count\n        for index_entry, entry in enumerate(entries):\n            assert isinstance(entry, MathTex)\n            assert expected_entries_tex_string[index_entry] == entry.tex_string\n\n    @pytest.mark.parametrize(\n        (\"matrix_elements\", \"row\", \"column\", \"expected_value_str\"),\n        [\n            ([[1, 2], [3, 4]], 0, 0, \"1\"),\n            ([[1, 2], [3, 4]], 1, 1, \"4\"),\n            ([[1, 2, 3]], 0, 2, \"3\"),\n            ([[1], [2], [3]], 2, 0, \"3\"),\n        ],\n        ids=[\"2x2_00\", \"2x2_11\", \"1x3_02\", \"3x1_20\"],\n    )\n    def test_get_element(self, matrix_elements, row, column, expected_value_str):\n        matrix = Matrix(matrix_elements)\n\n        assert isinstance(matrix.get_columns()[column][row], MathTex)\n        assert isinstance(matrix.get_rows()[row][column], MathTex)\n        assert matrix.get_columns()[column][row].tex_string == expected_value_str\n        assert matrix.get_rows()[row][column].tex_string == expected_value_str\n\n    @pytest.mark.parametrize(\n        (\"matrix_elements\", \"row\", \"column\", \"expected_error\"),\n        [\n            ([[1, 2]], 1, 0, IndexError),\n            ([[1, 2]], 0, 2, IndexError),\n        ],\n        ids=[\"row_out_of_bounds\", \"col_out_of_bounds\"],\n    )\n    def test_get_element_invalid(self, matrix_elements, row, column, expected_error):\n        matrix = Matrix(matrix_elements)\n\n        with pytest.raises(expected_error):\n            matrix.get_columns()[column][row]\n\n        with pytest.raises(expected_error):\n            matrix.get_rows()[row][column]\n\n\nclass TestDecimalMatrix:\n    @pytest.mark.parametrize(\n        (\"matrix_elements\", \"num_decimal_places\", \"expected_elements\"),\n        [\n            ([[1.234, 5.678], [9.012, 3.456]], 2, [[1.234, 5.678], [9.012, 3.456]]),\n            ([[1.0, 2.0], [3.0, 4.0]], 0, [[1, 2], [3, 4]]),\n            ([[1, 2.3], [4.567, 7]], 1, [[1.0, 2.3], [4.567, 7.0]]),\n        ],\n        ids=[\n            \"basic_2_decimal_points\",\n            \"basic_0_decimal_points\",\n            \"mixed_1_decimal_points\",\n        ],\n    )\n    def test_decimal_matrix_init(\n        self, matrix_elements, num_decimal_places, expected_elements\n    ):\n        matrix = DecimalMatrix(\n            matrix_elements,\n            element_to_mobject_config={\"num_decimal_places\": num_decimal_places},\n        )\n\n        assert isinstance(matrix, DecimalMatrix)\n        for column_index, column in enumerate(matrix.get_columns()):\n            for row_index, element in enumerate(column):\n                assert element.number == expected_elements[row_index][column_index]\n                assert element.num_decimal_places == num_decimal_places\n\n\nclass TestIntegerMatrix:\n    @pytest.mark.parametrize(\n        (\"matrix_elements\", \"expected_elements\"),\n        [\n            ([[1, 2], [3, 4]], [[1, 2], [3, 4]]),\n            ([[1.2, 2.8], [3.5, 4]], [[1.2, 2.8], [3.5, 4]]),\n        ],\n        ids=[\"basic_int\", \"mixed_float_int\"],\n    )\n    def test_integer_matrix_init(self, matrix_elements, expected_elements):\n        matrix = IntegerMatrix(matrix_elements)\n\n        assert isinstance(matrix, IntegerMatrix)\n        for row_index, row in enumerate(matrix.get_rows()):\n            for column_index, element in enumerate(row):\n                assert element.number == expected_elements[row_index][column_index]\n"
  },
  {
    "path": "tests/module/mobject/test_table.py",
    "content": "\"\"\"Tests for Table and related mobjects.\"\"\"\n\nfrom __future__ import annotations\n\nfrom manim import Table\nfrom manim.utils.color import GREEN\n\n\ndef test_highlighted_cell_color_access():\n    \"\"\"Test that accessing the color of a highlighted cell doesn't cause infinite recursion.\n\n    Regression test for https://github.com/ManimCommunity/manim/issues/4419\n    \"\"\"\n    table = Table([[\"This\", \"is a\"], [\"simple\", \"table\"]])\n    rect = table.get_highlighted_cell((1, 1), color=GREEN)\n\n    # Should not raise RecursionError\n    color = rect.color\n    assert color == GREEN\n"
  },
  {
    "path": "tests/module/mobject/test_value_tracker.py",
    "content": "from __future__ import annotations\n\nfrom manim.mobject.value_tracker import ComplexValueTracker, ValueTracker\n\n\ndef test_value_tracker_set_value():\n    \"\"\"Test ValueTracker.set_value()\"\"\"\n    tracker = ValueTracker()\n    tracker.set_value(10.0)\n    assert tracker.get_value() == 10.0\n\n\ndef test_value_tracker_get_value():\n    \"\"\"Test ValueTracker.get_value()\"\"\"\n    tracker = ValueTracker(10.0)\n    assert tracker.get_value() == 10.0\n\n\ndef test_value_tracker_interpolate():\n    \"\"\"Test ValueTracker.interpolate()\"\"\"\n    tracker1 = ValueTracker(1.0)\n    tracker2 = ValueTracker(2.5)\n    tracker3 = ValueTracker().interpolate(tracker1, tracker2, 0.7)\n    assert tracker3.get_value() == 2.05\n\n\ndef test_value_tracker_increment_value():\n    \"\"\"Test ValueTracker.increment_value()\"\"\"\n    tracker = ValueTracker(0.0)\n    tracker.increment_value(10.0)\n    assert tracker.get_value() == 10.0\n\n\ndef test_value_tracker_bool():\n    \"\"\"Test ValueTracker.__bool__()\"\"\"\n    tracker = ValueTracker(0.0)\n    assert not tracker\n    tracker.increment_value(1.0)\n    assert tracker\n\n\ndef test_value_tracker_add():\n    \"\"\"Test ValueTracker.__add__()\"\"\"\n    tracker = ValueTracker(0.0)\n    tracker2 = tracker + 10.0\n    assert tracker2.get_value() == 10.0\n\n\ndef test_value_tracker_iadd():\n    \"\"\"Test ValueTracker.__iadd__()\"\"\"\n    tracker = ValueTracker(0.0)\n    tracker += 10.0\n    assert tracker.get_value() == 10.0\n\n\ndef test_value_tracker_floordiv():\n    \"\"\"Test ValueTracker.__floordiv__()\"\"\"\n    tracker = ValueTracker(5.0)\n    tracker2 = tracker // 2.0\n    assert tracker2.get_value() == 2.0\n\n\ndef test_value_tracker_ifloordiv():\n    \"\"\"Test ValueTracker.__ifloordiv__()\"\"\"\n    tracker = ValueTracker(5.0)\n    tracker //= 2.0\n    assert tracker.get_value() == 2.0\n\n\ndef test_value_tracker_mod():\n    \"\"\"Test ValueTracker.__mod__()\"\"\"\n    tracker = ValueTracker(20.0)\n    tracker2 = tracker % 3.0\n    assert tracker2.get_value() == 2.0\n\n\ndef test_value_tracker_imod():\n    \"\"\"Test ValueTracker.__imod__()\"\"\"\n    tracker = ValueTracker(20.0)\n    tracker %= 3.0\n    assert tracker.get_value() == 2.0\n\n\ndef test_value_tracker_mul():\n    \"\"\"Test ValueTracker.__mul__()\"\"\"\n    tracker = ValueTracker(3.0)\n    tracker2 = tracker * 4.0\n    assert tracker2.get_value() == 12.0\n\n\ndef test_value_tracker_imul():\n    \"\"\"Test ValueTracker.__imul__()\"\"\"\n    tracker = ValueTracker(3.0)\n    tracker *= 4.0\n    assert tracker.get_value() == 12.0\n\n\ndef test_value_tracker_pow():\n    \"\"\"Test ValueTracker.__pow__()\"\"\"\n    tracker = ValueTracker(3.0)\n    tracker2 = tracker**3.0\n    assert tracker2.get_value() == 27.0\n\n\ndef test_value_tracker_ipow():\n    \"\"\"Test ValueTracker.__ipow__()\"\"\"\n    tracker = ValueTracker(3.0)\n    tracker **= 3.0\n    assert tracker.get_value() == 27.0\n\n\ndef test_value_tracker_sub():\n    \"\"\"Test ValueTracker.__sub__()\"\"\"\n    tracker = ValueTracker(20.0)\n    tracker2 = tracker - 10.0\n    assert tracker2.get_value() == 10.0\n\n\ndef test_value_tracker_isub():\n    \"\"\"Test ValueTracker.__isub__()\"\"\"\n    tracker = ValueTracker(20.0)\n    tracker -= 10.0\n    assert tracker.get_value() == 10.0\n\n\ndef test_value_tracker_truediv():\n    \"\"\"Test ValueTracker.__truediv__()\"\"\"\n    tracker = ValueTracker(5.0)\n    tracker2 = tracker / 2.0\n    assert tracker2.get_value() == 2.5\n\n\ndef test_value_tracker_itruediv():\n    \"\"\"Test ValueTracker.__itruediv__()\"\"\"\n    tracker = ValueTracker(5.0)\n    tracker /= 2.0\n    assert tracker.get_value() == 2.5\n\n\ndef test_complex_value_tracker_set_value():\n    \"\"\"Test ComplexValueTracker.set_value()\"\"\"\n    tracker = ComplexValueTracker()\n    tracker.set_value(1 + 2j)\n    assert tracker.get_value() == 1 + 2j\n\n\ndef test_complex_value_tracker_get_value():\n    \"\"\"Test ComplexValueTracker.get_value()\"\"\"\n    tracker = ComplexValueTracker(2.0 - 3.0j)\n    assert tracker.get_value() == 2.0 - 3.0j\n"
  },
  {
    "path": "tests/module/mobject/text/test_markup.py",
    "content": "from __future__ import annotations\n\nfrom manim import MarkupText\n\n\ndef test_good_markup():\n    \"\"\"Test creation of valid :class:`MarkupText` object\"\"\"\n    try:\n        text1 = MarkupText(\"<b>foo</b>\")\n        text2 = MarkupText(\"foo\")\n        success = True\n    except ValueError:\n        success = False\n    assert success, \"'<b>foo</b>' and 'foo' should not fail validation\"\n\n\ndef test_special_tags_markup():\n    \"\"\"Test creation of valid :class:`MarkupText` object with unofficial tags\"\"\"\n    try:\n        text1 = MarkupText('<color col=\"RED\">foo</color>')\n        text1 = MarkupText('<gradient from=\"RED\" to=\"YELLOW\">foo</gradient>')\n        success = True\n    except ValueError:\n        success = False\n    assert success, (\n        '\\'<color col=\"RED\">foo</color>\\' and \\'<gradient from=\"RED\" to=\"YELLOW\">foo</gradient>\\' should not fail validation'\n    )\n\n\ndef test_unbalanced_tag_markup():\n    \"\"\"Test creation of invalid :class:`MarkupText` object (unbalanced tag)\"\"\"\n    try:\n        text = MarkupText(\"<b>foo\")\n        success = False\n    except ValueError:\n        success = True\n    assert success, \"'<b>foo' should fail validation\"\n\n\ndef test_invalid_tag_markup():\n    \"\"\"Test creation of invalid :class:`MarkupText` object (invalid tag)\"\"\"\n    try:\n        text = MarkupText(\"<invalidtag>foo</invalidtag>\")\n        success = False\n    except ValueError:\n        success = True\n\n    assert success, \"'<invalidtag>foo</invalidtag>' should fail validation\"\n"
  },
  {
    "path": "tests/module/mobject/text/test_numbers.py",
    "content": "from __future__ import annotations\n\nfrom manim import RED, DecimalNumber, Integer\n\n\ndef test_font_size():\n    \"\"\"Test that DecimalNumber returns the correct font_size value\n    after being scaled.\n    \"\"\"\n    num = DecimalNumber(0).scale(0.3)\n\n    assert round(num.font_size, 5) == 14.4\n\n\ndef test_font_size_vs_scale():\n    \"\"\"Test that scale produces the same results as .scale()\"\"\"\n    num = DecimalNumber(0, font_size=12)\n    num_scale = DecimalNumber(0).scale(1 / 4)\n\n    assert num.height == num_scale.height\n\n\ndef test_changing_font_size():\n    \"\"\"Test that the font_size property properly scales DecimalNumber.\"\"\"\n    num = DecimalNumber(0, font_size=12)\n    num.font_size = 48\n\n    assert num.height == DecimalNumber(0, font_size=48).height\n\n\ndef test_set_value_size():\n    \"\"\"Test that the size of DecimalNumber after set_value is correct.\"\"\"\n    num = DecimalNumber(0).scale(0.3)\n    test_num = num.copy()\n    num.set_value(0)\n\n    # round because the height is off by 1e-17\n    assert round(num.height, 12) == round(test_num.height, 12)\n\n\ndef test_color_when_number_of_digits_changes():\n    \"\"\"Test that all digits of an Integer are colored correctly when\n    the number of digits changes.\n    \"\"\"\n    mob = Integer(color=RED)\n    mob.set_value(42)\n    assert all(\n        submob.stroke_color.to_hex() == RED.to_hex() for submob in mob.submobjects\n    )\n"
  },
  {
    "path": "tests/module/mobject/text/test_texmobject.py",
    "content": "from __future__ import annotations\n\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\n\nfrom manim import MathTex, SingleStringMathTex, Tex, TexTemplate, tempconfig\n\n\ndef test_MathTex(config):\n    MathTex(\"a^2 + b^2 = c^2\")\n    assert Path(config.media_dir, \"Tex\", \"05bb0a41ed575f00.svg\").exists()\n\n\ndef test_SingleStringMathTex(config):\n    SingleStringMathTex(\"test\")\n    assert Path(config.media_dir, \"Tex\", \"8ce17c7f5013209f.svg\").exists()\n\n\n@pytest.mark.parametrize(  # : PT006\n    (\"text_input\", \"length_sub\"),\n    [\n        (\"{{ a }} + {{ b }} = {{ c }}\", 5),\n        (r\"\\frac{1}{a+b\\sqrt{2}}\", 1),\n        # Regression test for https://github.com/ManimCommunity/manim/issues/4601:\n        # a string whose only }} comes from closing two nested LaTeX brace groups\n        # (not from the {{ }} notation) must not be split.\n        (r\"\\\\+\\int_{0}^{\\frac{Mq}{M+m}}\", 1),\n    ],\n)\ndef test_double_braces_testing(text_input, length_sub):\n    t1 = MathTex(text_input)\n    assert len(t1.submobjects) == length_sub\n\n\n# ---------------------------------------------------------------------------\n# Unit tests for MathTex._split_double_braces — no LaTeX compilation needed.\n# ---------------------------------------------------------------------------\n\n\n@pytest.mark.parametrize(\n    (\"tex_string\", \"expected_segments\"),\n    [\n        # ---- intended notation ----\n        # Basic split: each {{ }} group and the text between become segments.\n        (\n            \"{{ a }} + {{ b }}\",\n            [\"\", \" a \", \" + \", \" b \", \"\"],\n        ),\n        # {{ }} at the very start of the string (no preceding character).\n        (\n            \"{{x}}\",\n            [\"\", \"x\", \"\"],\n        ),\n        # Content with arbitrarily nested LaTeX braces: inner }} must NOT close\n        # the Manim group early.\n        (\n            r\"{{ a^{b^{c}} }}\",\n            [\"\", r\" a^{b^{c}} \", \"\"],\n        ),\n        # \\frac inside a Manim group — the }} from {1}{a} are at inner_depth > 0.\n        (\n            r\"{{ \\frac{1}{a} }}\",\n            [\"\", r\" \\frac{1}{a} \", \"\"],\n        ),\n        # ---- false-positive guards: {{ not preceded by whitespace ----\n        # \\text{{word}}: {{ preceded by {, must not split.\n        (\n            r\"\\text{{word}}\",\n            [r\"\\text{{word}}\"],\n        ),\n        # ^{{\\alpha}}: {{ preceded by {, must not split.\n        (\n            r\"^{{\\alpha}}\",\n            [r\"^{{\\alpha}}\"],\n        ),\n        # +{{a}}: {{ preceded by non-whitespace, must not split.\n        (\n            r\"+{{a}}\",\n            [r\"+{{a}}\"],\n        ),\n        # ---- bug case: }} without any {{ must not split ----\n        (\n            r\"\\\\+\\int_{0}^{\\frac{Mq}{M+m}}\",\n            [r\"\\\\+\\int_{0}^{\\frac{Mq}{M+m}}\"],\n        ),\n        # ---- backslash escape handling ----\n        # \\}} — \\} consumed as unit, remaining } is a lone close, not }}.\n        (\n            r\"\\}}\",\n            [r\"\\}}\"],\n        ),\n        # \\\\}} — \\\\ consumed as unit, leaving real }} which is not inside any\n        # Manim group so it passes through unchanged.\n        (\n            r\"\\\\}}\",\n            [r\"\\\\}}\"],\n        ),\n        # \\\\\\}} — \\\\ consumed, then \\} consumed; lone } passes through.\n        (\n            r\"\\\\\\}}\",\n            [r\"\\\\\\}}\"],\n        ),\n        # \\\\\\\\}} — two \\\\ consumed; lone }} passes through (no Manim group open).\n        (\n            r\"\\\\\\\\}}\",\n            [r\"\\\\\\\\}}\"],\n        ),\n        # Same backslash cases *inside* a Manim group.\n        # The escape sequence is placed right before the Manim }} close.\n        #\n        # {{ a \\}}} — \\} consumed as escaped brace (content), }} closes the group.\n        (\n            r\"{{ a \\}}}\",\n            [\"\", r\" a \\}\", \"\"],\n        ),\n        # {{ a \\\\}} — \\\\ consumed as escaped backslash (content), }} closes.\n        (\n            r\"{{ a \\\\}}\",\n            [\"\", r\" a \\\\\", \"\"],\n        ),\n        # {{ a \\\\\\}}} — \\\\ then \\} consumed (content), }} closes.\n        (\n            r\"{{ a \\\\\\}}}\",\n            [\"\", r\" a \\\\\\}\", \"\"],\n        ),\n        # {{ a \\\\\\\\}} — \\\\ then \\\\ consumed (content), }} closes.\n        (\n            r\"{{ a \\\\\\\\}}\",\n            [\"\", r\" a \\\\\\\\\", \"\"],\n        ),\n    ],\n)\ndef test_split_double_braces(tex_string, expected_segments):\n    assert MathTex._split_double_braces(tex_string) == expected_segments\n\n\ndef test_tex(config):\n    Tex(\"The horse does not eat cucumber salad.\")\n    assert Path(config.media_dir, \"Tex\", \"5384b41741a246bd.svg\").exists()\n\n\ndef test_tex_temp_directory(tmpdir, monkeypatch):\n    # Adds a test for #3060\n    # It's not possible to reproduce the issue normally, because we use\n    # tempconfig to change media directory to temporary directory by default\n    # we partially, revert that change here.\n    monkeypatch.chdir(tmpdir)\n    Path(tmpdir, \"media\").mkdir(exist_ok=True)\n    with tempconfig({\"media_dir\": \"media\"}):\n        Tex(\"The horse does not eat cucumber salad.\")\n        assert Path(\"media\", \"Tex\").exists()\n        assert Path(\"media\", \"Tex\", \"5384b41741a246bd.svg\").exists()\n\n\ndef test_percent_char_rendering(config):\n    Tex(r\"\\%\")\n    assert Path(config.media_dir, \"Tex\", \"32509dd0ea993961.tex\").exists()\n\n\ndef test_tex_whitespace_arg():\n    \"\"\"Check that correct number of submobjects are created per string with whitespace separator\"\"\"\n    separator = \"\\t\"\n    str_part_1 = \"Hello\"\n    str_part_2 = \"world\"\n    str_part_3 = \"It is\"\n    str_part_4 = \"me!\"\n    tex = Tex(str_part_1, str_part_2, str_part_3, str_part_4, arg_separator=separator)\n    assert len(tex) == 4\n    assert len(tex[0]) == len(\"\".join((str_part_1 + separator).split()))\n    assert len(tex[1]) == len(\"\".join((str_part_2 + separator).split()))\n    assert len(tex[2]) == len(\"\".join((str_part_3 + separator).split()))\n    assert len(tex[3]) == len(\"\".join(str_part_4.split()))\n\n\ndef test_tex_non_whitespace_arg():\n    \"\"\"Check that correct number of submobjects are created per string with non_whitespace characters\"\"\"\n    separator = \",\"\n    str_part_1 = \"Hello\"\n    str_part_2 = \"world\"\n    str_part_3 = \"It is\"\n    str_part_4 = \"me!\"\n    tex = Tex(str_part_1, str_part_2, str_part_3, str_part_4, arg_separator=separator)\n    assert len(tex) == 4\n    assert len(tex[0]) == len(\"\".join((str_part_1 + separator).split()))\n    assert len(tex[1]) == len(\"\".join((str_part_2 + separator).split()))\n    assert len(tex[2]) == len(\"\".join((str_part_3 + separator).split()))\n    assert len(tex[3]) == len(\"\".join(str_part_4.split()))\n\n\ndef test_tex_white_space_and_non_whitespace_args():\n    \"\"\"Check that correct number of submobjects are created per string when mixing characters with whitespace\"\"\"\n    separator = \", \\n . \\t\\t\"\n    str_part_1 = \"Hello\"\n    str_part_2 = \"world\"\n    str_part_3 = \"It is\"\n    str_part_4 = \"me!\"\n    tex = Tex(str_part_1, str_part_2, str_part_3, str_part_4, arg_separator=separator)\n    assert len(tex) == 4\n    assert len(tex[0]) == len(\"\".join((str_part_1 + separator).split()))\n    assert len(tex[1]) == len(\"\".join((str_part_2 + separator).split()))\n    assert len(tex[2]) == len(\"\".join((str_part_3 + separator).split()))\n    assert len(tex[3]) == len(\"\".join(str_part_4.split()))\n\n\ndef test_multi_part_tex_with_empty_parts():\n    \"\"\"Check that if a Tex or MathTex Mobject with multiple\n    string arguments is created where some of the parts render\n    as empty SVGs, then the number of family members with points\n    should still be the same as the snipped in one singular part.\n    \"\"\"\n    tex_parts = [\"(-1)\", \"^{\", \"0}\"]\n    one_part_fomula = MathTex(\"\".join(tex_parts))\n    multi_part_formula = MathTex(*tex_parts)\n\n    for one_part_glyph, multi_part_glyph in zip(\n        one_part_fomula.family_members_with_points(),\n        multi_part_formula.family_members_with_points(),\n        strict=True,\n    ):\n        np.testing.assert_allclose(one_part_glyph.points, multi_part_glyph.points)\n\n\ndef test_tex_size():\n    \"\"\"Check that the size of a :class:`Tex` string is not changed.\"\"\"\n    text = Tex(\"what\").center()\n    vertical = text.get_top() - text.get_bottom()\n    horizontal = text.get_right() - text.get_left()\n    assert round(vertical[1], 4) == 0.3512\n    assert round(horizontal[0], 4) == 1.0420\n\n\ndef test_font_size():\n    \"\"\"Test that tex_mobject classes return\n    the correct font_size value after being scaled.\n    \"\"\"\n    string = MathTex(0).scale(0.3)\n\n    assert round(string.font_size, 5) == 14.4\n\n\ndef test_font_size_vs_scale():\n    \"\"\"Test that scale produces the same results as .scale()\"\"\"\n    num = MathTex(0, font_size=12)\n    num_scale = MathTex(0).scale(1 / 4)\n\n    assert num.height == num_scale.height\n\n\ndef test_changing_font_size():\n    \"\"\"Test that the font_size property properly scales tex_mobject.py classes.\"\"\"\n    num = Tex(\"0\", font_size=12)\n    num.font_size = 48\n\n    assert num.height == Tex(\"0\", font_size=48).height\n\n\ndef test_log_error_context(capsys):\n    \"\"\"Test that the environment context of an error is correctly logged if it exists\"\"\"\n    invalid_tex = r\"\"\"\n        some text that is fine\n\n        \\begin{unbalanced_braces}{\n        not fine\n        \\end{not_even_the_right_env}\n        \"\"\"\n\n    with pytest.raises(ValueError) as err:\n        Tex(invalid_tex)\n\n    # validate useful TeX error logged to user\n    assert \"unbalanced_braces\" in str(capsys.readouterr().out)\n    # validate useful error message raised\n    assert \"See log output above or the log file\" in str(err.value)\n\n\ndef test_log_error_no_relevant_context(capsys):\n    \"\"\"Test that an error with no environment context contains no environment context\"\"\"\n    failing_preamble = r\"\"\"\\usepackage{fontspec}\n    \\setmainfont[Ligatures=TeX]{not_a_font}\"\"\"\n\n    with pytest.raises(ValueError) as err:\n        Tex(\n            \"The template uses a non-existent font\",\n            tex_template=TexTemplate(preamble=failing_preamble),\n        )\n\n    # validate useless TeX error not logged for user\n    assert \"Context\" not in str(capsys.readouterr().out)\n    # validate useful error message raised\n    # this won't happen if an error is raised while formatting the message\n    assert \"See log output above or the log file\" in str(err.value)\n\n\ndef test_error_in_nested_context(capsys):\n    \"\"\"Test that displayed error context is not excessively large\"\"\"\n    invalid_tex = r\"\"\"\n    \\begin{align}\n      \\begin{tabular}{ c }\n        no need to display \\\\\n        this correct text \\\\\n      \\end{tabular}\n      \\notacontrolsequence\n    \\end{align}\n    \"\"\"\n\n    with pytest.raises(ValueError):\n        Tex(invalid_tex)\n\n    stdout = str(capsys.readouterr().out)\n    # validate useless context is not included\n    assert r\"\\begin{frame}\" not in stdout\n\n\ndef test_tempconfig_resetting_tex_template(config):\n    my_template = TexTemplate()\n    my_template.preamble = \"Custom preamble!\"\n    with tempconfig({\"tex_template\": my_template}):\n        assert config.tex_template.preamble == \"Custom preamble!\"\n\n    assert config.tex_template.preamble != \"Custom preamble!\"\n\n\ndef test_tex_garbage_collection(tmpdir, monkeypatch, config):\n    monkeypatch.chdir(tmpdir)\n    Path(tmpdir, \"media\").mkdir(exist_ok=True)\n    config.media_dir = \"media\"\n\n    tex_without_log = Tex(\"Hello World!\")  # 058a4e242c57db6d.tex\n    assert Path(\"media\", \"Tex\", \"058a4e242c57db6d.tex\").exists()\n    assert not Path(\"media\", \"Tex\", \"058a4e242c57db6d.log\").exists()\n\n    config.no_latex_cleanup = True\n\n    tex_with_log = Tex(\"Hello World, again!\")  # 45b4e7819cc20cb1.tex\n    assert Path(\"media\", \"Tex\", \"45b4e7819cc20cb1.log\").exists()\n"
  },
  {
    "path": "tests/module/mobject/text/test_text_mobject.py",
    "content": "from __future__ import annotations\n\nfrom contextlib import redirect_stdout\nfrom io import StringIO\n\nfrom manim.mobject.text.text_mobject import MarkupText, Text\n\n\ndef test_font_size():\n    \"\"\"Test that Text and MarkupText return the\n    correct font_size value after being scaled.\n    \"\"\"\n    text_string = Text(\"0\").scale(0.3)\n    markuptext_string = MarkupText(\"0\").scale(0.3)\n\n    assert round(text_string.font_size, 5) == 14.4\n    assert round(markuptext_string.font_size, 5) == 14.4\n\n\ndef test_font_warnings():\n    def warning_printed(font: str, **kwargs) -> bool:\n        io = StringIO()\n        with redirect_stdout(io):\n            Text(\"hi!\", font=font, **kwargs)\n        txt = io.getvalue()\n        return \"Font\" in txt and \"not in\" in txt\n\n    # check for normal fonts (no warning)\n    assert not warning_printed(\"System-ui\", warn_missing_font=True)\n    # should be converted to sans before checking\n    assert not warning_printed(\"Sans-serif\", warn_missing_font=True)\n\n    # check random string (should be warning)\n    assert warning_printed(\"Manim!\" * 3, warn_missing_font=True)\n"
  },
  {
    "path": "tests/module/mobject/types/vectorized_mobject/test_dashed_vmobject.py",
    "content": "from manim import ORIGIN, UR, Arrow, DashedLine, DashedVMobject, VGroup\nfrom manim.mobject.geometry.tips import ArrowTip, StealthTip\n\n\ndef _collect_tips(mobject):\n    return [mob for mob in mobject.get_family() if isinstance(mob, ArrowTip)]\n\n\ndef test_dashed_arrow_has_single_tip():\n    dashed = DashedVMobject(Arrow(ORIGIN, 2 * UR))\n    tips = _collect_tips(dashed)\n\n    assert len(tips) == 1\n\n\ndef test_dashed_arrow_tip_not_duplicated_in_group_opacity():\n    base_arrow = Arrow(ORIGIN, 2 * UR)\n    faded_arrow = base_arrow.copy().set_fill(opacity=0.4).set_stroke(opacity=0.4)\n\n    dashed_group = (\n        VGroup(DashedVMobject(faded_arrow))\n        .set_fill(opacity=0.4, family=True)\n        .set_stroke(opacity=0.4, family=True)\n    )\n\n    tips = _collect_tips(dashed_group)\n\n    assert len(tips) == 1\n\n\ndef test_dashed_arrow_custom_tip_shape_has_single_tip():\n    dashed = DashedVMobject(Arrow(ORIGIN, 2 * UR, tip_shape=StealthTip))\n    tips = _collect_tips(dashed)\n\n    assert len(tips) == 1\n    assert isinstance(tips[0], StealthTip)\n\n\ndef test_dashed_arrow_with_start_tip_has_two_tips():\n    dashed = DashedVMobject(Arrow(ORIGIN, 2 * UR).add_tip(at_start=True))\n    tips = _collect_tips(dashed)\n\n    assert len(tips) == 2\n\n\ndef test_zero_length_dashed_line_submobjects_have_2d_points():\n    \"\"\"Submobjects of a zero-length DashedLine must have 2-D point arrays.\"\"\"\n    line = DashedLine(ORIGIN, ORIGIN)\n    for sub in line.submobjects:\n        assert sub.points.ndim == 2, (\n            f\"Expected 2-D points array, got shape {sub.points.shape}\"\n        )\n\n\ndef test_become_nonzero_to_zero_dashed_line_does_not_crash():\n    \"\"\"become() from a normal DashedLine to a zero-length one should not crash.\"\"\"\n    normal = DashedLine(ORIGIN, 2 * UR)\n    zero = DashedLine(ORIGIN, ORIGIN)\n    normal.become(zero)\n"
  },
  {
    "path": "tests/module/mobject/types/vectorized_mobject/test_stroke.py",
    "content": "from __future__ import annotations\n\nimport manim.utils.color as C\nfrom manim import VMobject\nfrom manim.mobject.vector_field import StreamLines\n\n\ndef test_stroke_props_in_ctor():\n    m = VMobject(stroke_color=C.ORANGE, stroke_width=10)\n    assert m.stroke_color.to_hex() == C.ORANGE.to_hex()\n    assert m.stroke_width == 10\n\n\ndef test_set_stroke():\n    m = VMobject()\n    m.set_stroke(color=C.ORANGE, width=2, opacity=0.8)\n    assert m.stroke_width == 2\n    assert m.stroke_opacity == 0.8\n    assert m.stroke_color.to_hex() == C.ORANGE.to_hex()\n\n\ndef test_set_background_stroke():\n    m = VMobject()\n    m.set_stroke(color=C.ORANGE, width=2, opacity=0.8, background=True)\n    assert m.background_stroke_width == 2\n    assert m.background_stroke_opacity == 0.8\n    assert m.background_stroke_color.to_hex() == C.ORANGE.to_hex()\n\n\ndef test_streamline_attributes_for_single_color():\n    vector_field = StreamLines(\n        lambda x: x,  # It is not important what this function is.\n        x_range=[-1, 1, 0.1],\n        y_range=[-1, 1, 0.1],\n        padding=0.1,\n        stroke_width=1.0,\n        opacity=0.2,\n        color=C.BLUE_D,\n    )\n    assert vector_field[0].stroke_width == 1.0\n    assert vector_field[0].stroke_opacity == 0.2\n\n\ndef test_stroke_scale():\n    a = VMobject()\n    b = VMobject()\n    a.set_stroke(width=50)\n    b.set_stroke(width=50)\n    a.scale(0.5)\n    b.scale(0.5, scale_stroke=True)\n    assert a.get_stroke_width() == 50\n    assert b.get_stroke_width() == 25\n\n\ndef test_background_stroke_scale():\n    a = VMobject()\n    b = VMobject()\n    a.set_stroke(width=50, background=True)\n    b.set_stroke(width=50, background=True)\n    a.scale(0.5)\n    b.scale(0.5, scale_stroke=True)\n    assert a.get_stroke_width(background=True) == 50\n    assert b.get_stroke_width(background=True) == 25\n"
  },
  {
    "path": "tests/module/mobject/types/vectorized_mobject/test_vectorized_mobject.py",
    "content": "from math import cos, sin\n\nimport numpy as np\nimport pytest\n\nfrom manim import (\n    Circle,\n    CurvesAsSubmobjects,\n    Line,\n    Mobject,\n    Polygon,\n    RegularPolygon,\n    Square,\n    VDict,\n    VGroup,\n    VMobject,\n)\nfrom manim.constants import PI\n\n\ndef test_vmobject_add():\n    \"\"\"Test the VMobject add method.\"\"\"\n    obj = VMobject()\n    assert len(obj.submobjects) == 0\n\n    obj.add(VMobject())\n    assert len(obj.submobjects) == 1\n\n    # Can't add non-VMobject values to a VMobject.\n    with pytest.raises(TypeError) as add_int_info:\n        obj.add(3)\n    assert str(add_int_info.value) == (\n        \"Only values of type VMobject can be added as submobjects of VMobject, \"\n        \"but the value 3 (at index 0) is of type int.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    # Plain Mobjects can't be added to a VMobject if they're not\n    # VMobjects. Suggest adding them into a Group instead.\n    with pytest.raises(TypeError) as add_mob_info:\n        obj.add(Mobject())\n    assert str(add_mob_info.value) == (\n        \"Only values of type VMobject can be added as submobjects of VMobject, \"\n        \"but the value Mobject (at index 0) is of type Mobject. You can try \"\n        \"adding this value into a Group instead.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    with pytest.raises(TypeError) as add_vmob_and_mob_info:\n        # If only one of the added objects is not an instance of VMobject, none of them should be added\n        obj.add(VMobject(), Mobject())\n    assert str(add_vmob_and_mob_info.value) == (\n        \"Only values of type VMobject can be added as submobjects of VMobject, \"\n        \"but the value Mobject (at index 1) is of type Mobject. You can try \"\n        \"adding this value into a Group instead.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    # A VMobject or VGroup cannot contain itself.\n    with pytest.raises(ValueError) as add_self_info:\n        obj.add(obj)\n    assert str(add_self_info.value) == (\n        \"Cannot add VMobject as a submobject of itself (at index 0).\"\n    )\n    assert len(obj.submobjects) == 1\n\n\ndef test_vmobject_add_points_as_corners():\n    points = np.array(\n        [\n            [2, 0, 0],\n            [1, 1, 0],\n            [-1, 1, 0],\n            [-2, 0, 0],\n            [-1, -1, 0],\n            [1, -1, 0],\n            [2, 0, 0],\n        ]\n    )\n\n    # Test that add_points_as_corners(points) is equivalent to calling\n    # add_line_to(point) for every point in points.\n    obj1 = VMobject().start_new_path(points[0]).add_points_as_corners(points[1:])\n    obj2 = VMobject().start_new_path(points[0])\n    for point in points[1:]:\n        obj2.add_line_to(point)\n    np.testing.assert_allclose(obj1.points, obj2.points)\n\n    # Test that passing an array with no points does nothing.\n    obj3 = VMobject().start_new_path(points[0])\n    points3_old = obj3.points.copy()\n    obj3.add_points_as_corners([])\n    np.testing.assert_allclose(points3_old, obj3.points)\n\n    obj3.add_points_as_corners(points[1:]).add_points_as_corners([])\n    np.testing.assert_allclose(obj1.points, obj3.points)\n\n\ndef test_vmobject_point_from_proportion():\n    obj = VMobject()\n\n    # One long line, one short line\n    obj.set_points_as_corners(\n        [\n            np.array([0, 0, 0]),\n            np.array([4, 0, 0]),\n            np.array([4, 2, 0]),\n        ],\n    )\n\n    # Total length of 6, so halfway along the object\n    # would be at length 3, which lands in the first, long line.\n    np.testing.assert_array_equal(obj.point_from_proportion(0.5), np.array([3, 0, 0]))\n\n    with pytest.raises(ValueError, match=\"between 0 and 1\"):\n        obj.point_from_proportion(2)\n\n    obj.clear_points()\n    with pytest.raises(Exception, match=\"with no points\"):\n        obj.point_from_proportion(0)\n\n\ndef test_curves_as_submobjects_point_from_proportion():\n    obj = CurvesAsSubmobjects(VGroup())\n\n    with pytest.raises(ValueError, match=\"between 0 and 1\"):\n        obj.point_from_proportion(2)\n    with pytest.raises(Exception, match=\"with no submobjects\"):\n        obj.point_from_proportion(0)\n\n    obj.add(VMobject())\n    with pytest.raises(Exception, match=\"have no points\"):\n        obj.point_from_proportion(0)\n\n    # submobject[0] is a line of length 4\n    obj.submobjects[0].set_points_as_corners(\n        [\n            np.array([0, 0, 0]),\n            np.array([4, 0, 0]),\n        ],\n    )\n    obj.add(VMobject())\n    # submobject[1] is a line of length 2\n    obj.submobjects[1].set_points_as_corners(\n        [\n            np.array([4, 0, 0]),\n            np.array([4, 2, 0]),\n        ],\n    )\n\n    # point at proportion 0.5 should be at length 3, point [3, 0, 0]\n    np.testing.assert_array_equal(obj.point_from_proportion(0.5), np.array([3, 0, 0]))\n\n\ndef test_vgroup_init():\n    \"\"\"Test the VGroup instantiation.\"\"\"\n    VGroup()\n    VGroup(VMobject())\n    VGroup(VMobject(), VMobject())\n\n    # A VGroup cannot contain non-VMobject values.\n    with pytest.raises(TypeError) as init_with_float_info:\n        VGroup(3.0)\n    assert str(init_with_float_info.value) == (\n        \"Only values of type VMobject can be added as submobjects of VGroup, \"\n        \"but the value 3.0 (at index 0 of parameter 0) is of type float.\"\n    )\n\n    with pytest.raises(TypeError) as init_with_mob_info:\n        VGroup(Mobject())\n    assert str(init_with_mob_info.value) == (\n        \"Only values of type VMobject can be added as submobjects of VGroup, \"\n        \"but the value Mobject (at index 0 of parameter 0) is of type Mobject. You can try \"\n        \"adding this value into a Group instead.\"\n    )\n\n    with pytest.raises(TypeError) as init_with_vmob_and_mob_info:\n        VGroup(VMobject(), Mobject())\n    assert str(init_with_vmob_and_mob_info.value) == (\n        \"Only values of type VMobject can be added as submobjects of VGroup, \"\n        \"but the value Mobject (at index 0 of parameter 1) is of type Mobject. You can try \"\n        \"adding this value into a Group instead.\"\n    )\n\n\ndef test_vgroup_init_with_iterable():\n    \"\"\"Test VGroup instantiation with an iterable type.\"\"\"\n\n    def type_generator(type_to_generate, n):\n        return (type_to_generate() for _ in range(n))\n\n    def mixed_type_generator(major_type, minor_type, minor_type_positions, n):\n        return (\n            minor_type() if i in minor_type_positions else major_type()\n            for i in range(n)\n        )\n\n    obj = VGroup(VMobject())\n    assert len(obj.submobjects) == 1\n\n    obj = VGroup(type_generator(VMobject, 38))\n    assert len(obj.submobjects) == 38\n\n    obj = VGroup(VMobject(), [VMobject(), VMobject()], type_generator(VMobject, 38))\n    assert len(obj.submobjects) == 41\n\n    # A VGroup cannot be initialised with an iterable containing a Mobject\n    with pytest.raises(TypeError) as init_with_mob_iterable:\n        VGroup(type_generator(Mobject, 5))\n    assert str(init_with_mob_iterable.value) == (\n        \"Only values of type VMobject can be added as submobjects of VGroup, \"\n        \"but the value Mobject (at index 0 of parameter 0) is of type Mobject.\"\n    )\n\n    # A VGroup cannot be initialised with an iterable containing a Mobject in any position\n    with pytest.raises(TypeError) as init_with_mobs_and_vmobs_iterable:\n        VGroup(mixed_type_generator(VMobject, Mobject, [3, 5], 7))\n    assert str(init_with_mobs_and_vmobs_iterable.value) == (\n        \"Only values of type VMobject can be added as submobjects of VGroup, \"\n        \"but the value Mobject (at index 3 of parameter 0) is of type Mobject.\"\n    )\n\n    # A VGroup cannot be initialised with an iterable containing non VMobject's in any position\n    with pytest.raises(TypeError) as init_with_float_and_vmobs_iterable:\n        VGroup(mixed_type_generator(VMobject, float, [6, 7], 9))\n    assert str(init_with_float_and_vmobs_iterable.value) == (\n        \"Only values of type VMobject can be added as submobjects of VGroup, \"\n        \"but the value 0.0 (at index 6 of parameter 0) is of type float.\"\n    )\n\n\ndef test_vgroup_add():\n    \"\"\"Test the VGroup add method.\"\"\"\n    obj = VGroup()\n    assert len(obj.submobjects) == 0\n\n    obj.add(VMobject())\n    assert len(obj.submobjects) == 1\n\n    # Can't add non-VMobject values to a VMobject or VGroup.\n    with pytest.raises(TypeError) as add_int_info:\n        obj.add(3)\n    assert str(add_int_info.value) == (\n        \"Only values of type VMobject can be added as submobjects of VGroup, \"\n        \"but the value 3 (at index 0 of parameter 0) is of type int.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    # Plain Mobjects can't be added to a VMobject or VGroup if they're not\n    # VMobjects. Suggest adding them into a Group instead.\n    with pytest.raises(TypeError) as add_mob_info:\n        obj.add(Mobject())\n    assert str(add_mob_info.value) == (\n        \"Only values of type VMobject can be added as submobjects of VGroup, \"\n        \"but the value Mobject (at index 0 of parameter 0) is of type Mobject. You can try \"\n        \"adding this value into a Group instead.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    with pytest.raises(TypeError) as add_vmob_and_mob_info:\n        # If only one of the added objects is not an instance of VMobject, none of them should be added\n        obj.add(VMobject(), Mobject())\n    assert str(add_vmob_and_mob_info.value) == (\n        \"Only values of type VMobject can be added as submobjects of VGroup, \"\n        \"but the value Mobject (at index 0 of parameter 1) is of type Mobject. You can try \"\n        \"adding this value into a Group instead.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    # A VMobject or VGroup cannot contain itself.\n    with pytest.raises(ValueError) as add_self_info:\n        obj.add(obj)\n    assert str(add_self_info.value) == (\n        \"Cannot add VGroup as a submobject of itself (at index 0).\"\n    )\n    assert len(obj.submobjects) == 1\n\n\ndef test_vgroup_add_dunder():\n    \"\"\"Test the VGroup __add__ magic method.\"\"\"\n    obj = VGroup()\n    assert len(obj.submobjects) == 0\n    obj + VMobject()\n    assert len(obj.submobjects) == 0\n    obj += VMobject()\n    assert len(obj.submobjects) == 1\n    with pytest.raises(TypeError):\n        obj += Mobject()\n    assert len(obj.submobjects) == 1\n    with pytest.raises(TypeError):\n        # If only one of the added object is not an instance of VMobject, none of them should be added\n        obj += (VMobject(), Mobject())\n    assert len(obj.submobjects) == 1\n    with pytest.raises(ValueError):\n        # a Mobject cannot contain itself\n        obj += obj\n\n\ndef test_vgroup_remove():\n    \"\"\"Test the VGroup remove method.\"\"\"\n    a = VMobject()\n    c = VMobject()\n    b = VGroup(c)\n    obj = VGroup(a, b)\n    assert len(obj.submobjects) == 2\n    assert len(b.submobjects) == 1\n    obj.remove(a)\n    b.remove(c)\n    assert len(obj.submobjects) == 1\n    assert len(b.submobjects) == 0\n    obj.remove(b)\n    assert len(obj.submobjects) == 0\n\n\ndef test_vgroup_remove_dunder():\n    \"\"\"Test the VGroup __sub__ magic method.\"\"\"\n    a = VMobject()\n    c = VMobject()\n    b = VGroup(c)\n    obj = VGroup(a, b)\n    assert len(obj.submobjects) == 2\n    assert len(b.submobjects) == 1\n    assert len(obj - a) == 1\n    assert len(obj.submobjects) == 2\n    obj -= a\n    b -= c\n    assert len(obj.submobjects) == 1\n    assert len(b.submobjects) == 0\n    obj -= b\n    assert len(obj.submobjects) == 0\n\n\ndef test_vmob_add_to_back():\n    \"\"\"Test the Mobject add_to_back method.\"\"\"\n    a = VMobject()\n    b = Line()\n    c = \"text\"\n    with pytest.raises(ValueError):\n        # Mobject cannot contain self\n        a.add_to_back(a)\n    with pytest.raises(TypeError):\n        # All submobjects must be of type Mobject\n        a.add_to_back(c)\n\n    # No submobject gets added twice\n    a.add_to_back(b)\n    a.add_to_back(b, b)\n    assert len(a.submobjects) == 1\n    a.submobjects.clear()\n    a.add_to_back(b, b, b)\n    a.add_to_back(b, b)\n    assert len(a.submobjects) == 1\n    a.submobjects.clear()\n\n    # Make sure the ordering has not changed\n    o1, o2, o3 = Square(), Line(), Circle()\n    a.add_to_back(o1, o2, o3)\n    assert a.submobjects.pop() == o3\n    assert a.submobjects.pop() == o2\n    assert a.submobjects.pop() == o1\n\n\ndef test_vdict_init():\n    \"\"\"Test the VDict instantiation.\"\"\"\n    # Test empty VDict\n    VDict()\n    # Test VDict made from list of pairs\n    VDict([(\"a\", VMobject()), (\"b\", VMobject()), (\"c\", VMobject())])\n    # Test VDict made from a python dict\n    VDict({\"a\": VMobject(), \"b\": VMobject(), \"c\": VMobject()})\n    # Test VDict made using zip\n    VDict(zip([\"a\", \"b\", \"c\"], [VMobject(), VMobject(), VMobject()], strict=True))\n    # If the value is of type Mobject, must raise a TypeError\n    with pytest.raises(TypeError):\n        VDict({\"a\": Mobject()})\n\n\ndef test_vdict_add():\n    \"\"\"Test the VDict add method.\"\"\"\n    obj = VDict()\n    assert len(obj.submob_dict) == 0\n    obj.add([(\"a\", VMobject())])\n    assert len(obj.submob_dict) == 1\n    with pytest.raises(TypeError):\n        obj.add([(\"b\", Mobject())])\n\n\ndef test_vdict_remove():\n    \"\"\"Test the VDict remove method.\"\"\"\n    obj = VDict([(\"a\", VMobject())])\n    assert len(obj.submob_dict) == 1\n    obj.remove(\"a\")\n    assert len(obj.submob_dict) == 0\n    with pytest.raises(KeyError):\n        obj.remove(\"a\")\n\n\ndef test_vgroup_supports_item_assigment():\n    \"\"\"Test VGroup supports array-like assignment for VMObjects\"\"\"\n    a = VMobject()\n    b = VMobject()\n    vgroup = VGroup(a)\n    assert vgroup[0] == a\n    vgroup[0] = b\n    assert vgroup[0] == b\n    assert len(vgroup) == 1\n\n\ndef test_vgroup_item_assignment_at_correct_position():\n    \"\"\"Test VGroup item-assignment adds to correct position for VMobjects\"\"\"\n    n_items = 10\n    vgroup = VGroup()\n    for _i in range(n_items):\n        vgroup.add(VMobject())\n    new_obj = VMobject()\n    vgroup[6] = new_obj\n    assert vgroup[6] == new_obj\n    assert len(vgroup) == n_items\n\n\ndef test_vgroup_item_assignment_only_allows_vmobjects():\n    \"\"\"Test VGroup item-assignment raises TypeError when invalid type is passed\"\"\"\n    vgroup = VGroup(VMobject())\n    with pytest.raises(TypeError) as assign_str_info:\n        vgroup[0] = \"invalid object\"\n    assert str(assign_str_info.value) == (\n        \"Only values of type VMobject can be added as submobjects of VGroup, \"\n        \"but the value invalid object (at index 0) is of type str.\"\n    )\n\n\ndef test_trim_dummy():\n    o = VMobject()\n    o.start_new_path(np.array([0, 0, 0]))\n    o.add_line_to(np.array([1, 0, 0]))\n    o.add_line_to(np.array([2, 0, 0]))\n    o.add_line_to(np.array([2, 0, 0]))  # Dummy point, will be stripped from points\n    o.start_new_path(np.array([0, 1, 0]))\n    o.add_line_to(np.array([1, 2, 0]))\n\n    o2 = VMobject()\n    o2.start_new_path(np.array([0, 0, 0]))\n    o2.add_line_to(np.array([0, 1, 0]))\n    o2.start_new_path(np.array([1, 0, 0]))\n    o2.add_line_to(np.array([1, 1, 0]))\n    o2.add_line_to(np.array([1, 2, 0]))\n\n    def path_length(p):\n        return len(p) // o.n_points_per_cubic_curve\n\n    assert tuple(map(path_length, o.get_subpaths())) == (3, 1)\n    assert tuple(map(path_length, o2.get_subpaths())) == (1, 2)\n\n    o.align_points(o2)\n\n    assert tuple(map(path_length, o.get_subpaths())) == (2, 2)\n    assert tuple(map(path_length, o2.get_subpaths())) == (2, 2)\n\n\ndef test_bounded_become():\n    \"\"\"Tests that align_points generates a bounded number of points.\n    https://github.com/ManimCommunity/manim/issues/1959\n    \"\"\"\n    o = VMobject()\n\n    def draw_circle(m: VMobject, n_points, x=0, y=0, r=1):\n        center = np.array([x, y, 0])\n        m.start_new_path(center + [r, 0, 0])\n        for i in range(1, n_points + 1):\n            theta = 2 * PI * i / n_points\n            m.add_line_to(center + [cos(theta) * r, sin(theta) * r, 0])\n\n    # o must contain some points, or else become behaves differently\n    draw_circle(o, 2)\n\n    for _ in range(20):\n        # Alternate between calls to become with different subpath sizes\n        a = VMobject()\n        draw_circle(a, 20)\n        o.become(a)\n        b = VMobject()\n        draw_circle(b, 15)\n        draw_circle(b, 15, x=3)\n        o.become(b)\n\n    # The number of points should be similar to the size of a and b\n    assert len(o.points) <= (20 + 15 + 15) * 4\n\n\ndef test_vmobject_same_points_become():\n    a = Square()\n    b = Circle()\n    a.become(b)\n    np.testing.assert_array_equal(a.points, b.points)\n    assert len(a.submobjects) == len(b.submobjects)\n\n\ndef test_vmobject_same_num_submobjects_become():\n    a = Square()\n    b = RegularPolygon(n=6)\n    a.become(b)\n    np.testing.assert_array_equal(a.points, b.points)\n    assert len(a.submobjects) == len(b.submobjects)\n\n\ndef test_vmobject_different_num_points_and_submobjects_become():\n    a = Square()\n    b = VGroup(Circle(), Square())\n    a.become(b)\n    np.testing.assert_array_equal(a.points, b.points)\n    assert len(a.submobjects) == len(b.submobjects)\n\n\ndef test_vmobject_point_at_angle():\n    a = Circle()\n    p = a.point_at_angle(4 * PI)\n    np.testing.assert_array_equal(a.points[0], p)\n\n\ndef test_proportion_from_point():\n    A = np.sqrt(3) * np.array([0, 1, 0])\n    B = np.array([-1, 0, 0])\n    C = np.array([1, 0, 0])\n    abc = Polygon(A, B, C)\n    abc.shift(np.array([-1, 0, 0]))\n    abc.scale(0.8)\n    props = [abc.proportion_from_point(p) for p in abc.get_vertices()]\n    np.testing.assert_allclose(props, [0, 1 / 3, 2 / 3])\n\n\ndef test_pointwise_become_partial_where_vmobject_is_self():\n    sq = Square()\n    sq.pointwise_become_partial(vmobject=sq, a=0.2, b=0.7)\n    expected_points = np.array(\n        [\n            [-0.6, 1.0, 0.0],\n            [-0.73333333, 1.0, 0.0],\n            [-0.86666667, 1.0, 0.0],\n            [-1.0, 1.0, 0.0],\n            [-1.0, 1.0, 0.0],\n            [-1.0, 0.33333333, 0.0],\n            [-1.0, -0.33333333, 0.0],\n            [-1.0, -1.0, 0.0],\n            [-1.0, -1.0, 0.0],\n            [-0.46666667, -1.0, 0.0],\n            [0.06666667, -1.0, 0.0],\n            [0.6, -1.0, 0.0],\n        ]\n    )\n    np.testing.assert_allclose(sq.points, expected_points)\n"
  },
  {
    "path": "tests/module/scene/test_auto_zoom.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\n\n\ndef test_zoom():\n    s1 = Square()\n    s1.set_x(-10)\n    s2 = Square()\n    s2.set_x(10)\n\n    with tempconfig({\"dry_run\": True, \"quality\": \"low_quality\"}):\n        scene = MovingCameraScene()\n        scene.add(s1, s2)\n        scene.play(scene.camera.auto_zoom([s1, s2]))\n\n    assert scene.camera.frame_width == abs(\n        s1.get_left()[0] - s2.get_right()[0],\n    )\n    assert scene.camera.frame.get_center()[0] == (\n        abs(s1.get_center()[0] + s2.get_center()[0]) / 2\n    )\n"
  },
  {
    "path": "tests/module/scene/test_scene.py",
    "content": "from __future__ import annotations\n\nimport datetime\n\nimport pytest\n\nfrom manim import Circle, Dot, FadeIn, Group, Mobject, Scene, Square\nfrom manim.animation.animation import Wait\n\n\ndef test_scene_add_remove(dry_run):\n    scene = Scene()\n    assert len(scene.mobjects) == 0\n    scene.add(Mobject())\n    assert len(scene.mobjects) == 1\n    scene.add(*(Mobject() for _ in range(10)))\n    assert len(scene.mobjects) == 11\n\n    # Check that adding a mobject twice does not actually add it twice\n    repeated = Mobject()\n    scene.add(repeated)\n    assert len(scene.mobjects) == 12\n    scene.add(repeated)\n    assert len(scene.mobjects) == 12\n\n    # Check that Scene.add() returns the Scene (for chained calls)\n    assert scene.add(Mobject()) is scene\n    to_remove = Mobject()\n    scene = Scene()\n    scene.add(to_remove)\n    scene.add(*(Mobject() for _ in range(10)))\n    assert len(scene.mobjects) == 11\n    scene.remove(to_remove)\n    assert len(scene.mobjects) == 10\n    scene.remove(to_remove)\n    assert len(scene.mobjects) == 10\n\n    # Check that Scene.remove() returns the instance (for chained calls)\n    assert scene.add(Mobject()) is scene\n\n\ndef test_scene_time(dry_run):\n    scene = Scene()\n    assert scene.time == 0\n    scene.wait(2)\n    assert scene.time == 2\n    scene.play(FadeIn(Circle()), run_time=0.5)\n    assert pytest.approx(scene.time) == 2.5\n    scene.renderer._original_skipping_status = True\n    scene.play(FadeIn(Square()), run_time=5)  # this animation gets skipped.\n    assert pytest.approx(scene.time) == 7.5\n\n\ndef test_subcaption(dry_run):\n    scene = Scene()\n    scene.add_subcaption(\"Testing add_subcaption\", duration=1, offset=0)\n    scene.wait()\n    scene.play(\n        Wait(),\n        run_time=2,\n        subcaption=\"Testing Scene.play subcaption interface\",\n        subcaption_duration=1.5,\n        subcaption_offset=0.5,\n    )\n    subcaptions = scene.renderer.file_writer.subcaptions\n    assert len(subcaptions) == 2\n    assert subcaptions[0].start == datetime.timedelta(seconds=0)\n    assert subcaptions[0].end == datetime.timedelta(seconds=1)\n    assert subcaptions[0].content == \"Testing add_subcaption\"\n    assert subcaptions[1].start == datetime.timedelta(seconds=1.5)\n    assert subcaptions[1].end == datetime.timedelta(seconds=3)\n    assert subcaptions[1].content == \"Testing Scene.play subcaption interface\"\n\n\ndef test_replace(dry_run):\n    def assert_names(mobjs, names):\n        assert len(mobjs) == len(names)\n        for i in range(0, len(mobjs)):\n            assert mobjs[i].name == names[i]\n\n    scene = Scene()\n\n    first = Mobject(name=\"first\")\n    second = Mobject(name=\"second\")\n    third = Mobject(name=\"third\")\n    fourth = Mobject(name=\"fourth\")\n\n    scene.add(first)\n    scene.add(Group(second, third, name=\"group\"))\n    scene.add(fourth)\n    assert_names(scene.mobjects, [\"first\", \"group\", \"fourth\"])\n    assert_names(scene.mobjects[1], [\"second\", \"third\"])\n\n    alpha = Mobject(name=\"alpha\")\n    beta = Mobject(name=\"beta\")\n\n    scene.replace(first, alpha)\n    assert_names(scene.mobjects, [\"alpha\", \"group\", \"fourth\"])\n    assert_names(scene.mobjects[1], [\"second\", \"third\"])\n\n    scene.replace(second, beta)\n    assert_names(scene.mobjects, [\"alpha\", \"group\", \"fourth\"])\n    assert_names(scene.mobjects[1], [\"beta\", \"third\"])\n\n\ndef test_reproducible_scene(dry_run):\n    import numpy as np\n\n    scene = Scene(random_seed=42)\n    dots1 = []\n    for _ in range(10):\n        dot = Dot(np.random.uniform(-3, 3, size=3))  # noqa: NPY002\n        dots1.append(dot)\n    scene.add(*dots1)\n\n    scene2 = Scene(random_seed=42)\n    dots2 = []\n    for _ in range(5):\n        dot = Dot(np.random.uniform(-3, 3, size=3))  # noqa: NPY002\n        dots2.append(dot)\n    scene2.add(*dots2)\n\n    for d1, d2 in zip(dots1, dots2, strict=False):\n        np.testing.assert_allclose(d1.get_center(), d2.get_center())\n\n\ndef test_random_color_reproducibility_with_seed(dry_run):\n    from manim import random_color, tempconfig\n\n    with tempconfig({\"seed\": 123}):\n        # First run: create scene (which seeds global random state) and generate colors\n        scene1 = Scene()\n        colors_first_run = [random_color() for _ in range(5)]\n\n        # Interrupt with a scene that has an explicit different seed\n        scene_explicit = Scene(random_seed=999)\n        colors_interrupted = [random_color() for _ in range(3)]\n\n        # Second run: create a new scene without explicit seed (should use config.seed)\n        scene2 = Scene()\n        colors_second_run = [random_color() for _ in range(5)]\n\n        # The colors from the first and second run should match\n        # because both scenes were seeded with config.seed=123\n        assert colors_first_run == colors_second_run\n\n        # The interrupted colors should be different (seeded with 999)\n        assert colors_interrupted != colors_first_run[:3]\n"
  },
  {
    "path": "tests/module/scene/test_sound.py",
    "content": "from __future__ import annotations\n\nimport struct\nimport wave\nfrom pathlib import Path\n\nfrom manim import Scene\n\n\ndef test_add_sound(tmpdir):\n    # create sound file\n    sound_loc = Path(tmpdir, \"noise.wav\")\n    with wave.open(str(sound_loc), \"w\") as f:\n        f.setparams((2, 2, 44100, 0, \"NONE\", \"not compressed\"))\n        for _ in range(22050):  # half a second of sound\n            packed_value = struct.pack(\"h\", 14242)\n            f.writeframes(packed_value)\n            f.writeframes(packed_value)\n\n    scene = Scene()\n    scene.add_sound(sound_loc)\n"
  },
  {
    "path": "tests/module/scene/test_threed_scene.py",
    "content": "from manim import Circle, Square, ThreeDScene\n\n\ndef test_fixed_mobjects():\n    scene = ThreeDScene()\n    s = Square()\n    c = Circle()\n    scene.add_fixed_in_frame_mobjects(s, c)\n    assert set(scene.mobjects) == {s, c}\n    assert set(scene.camera.fixed_in_frame_mobjects) == {s, c}\n    scene.remove_fixed_in_frame_mobjects(s)\n    assert set(scene.mobjects) == {s, c}\n    assert set(scene.camera.fixed_in_frame_mobjects) == {c}\n    scene.add_fixed_orientation_mobjects(s)\n    assert set(scene.camera.fixed_orientation_mobjects) == {s}\n    scene.remove_fixed_orientation_mobjects(s)\n    assert len(scene.camera.fixed_orientation_mobjects) == 0\n"
  },
  {
    "path": "tests/module/utils/_split_matrices.py",
    "content": "import numpy as np\n\n# Defined because pre-commit is inserting an unacceptable line-break\n# between the \"1\" (or \"2\") and the \"/ 3\"\none_third = 1 / 3\ntwo_thirds = 2 / 3\n\n\n# Expected values for matrices in split_bezier\nSPLIT_MATRICES = {\n    # For 0-degree Béziers\n    0: {\n        0: np.array([[1], [1]]),\n        one_third: np.array([[1], [1]]),\n        two_thirds: np.array([[1], [1]]),\n        1: np.array([[1], [1]]),\n    },\n    # For linear Béziers\n    1: {\n        0: np.array(\n            [\n                [1, 0],\n                [1, 0],\n                [1, 0],\n                [0, 1],\n            ]\n        ),\n        one_third: np.array(\n            [\n                [3, 0],\n                [2, 1],\n                [2, 1],\n                [0, 3],\n            ]\n        )\n        / 3,\n        two_thirds: np.array(\n            [\n                [3, 0],\n                [1, 2],\n                [1, 2],\n                [0, 3],\n            ]\n        )\n        / 3,\n        1: np.array(\n            [\n                [1, 0],\n                [0, 1],\n                [0, 1],\n                [0, 1],\n            ]\n        ),\n    },\n    # For quadratic Béziers\n    2: {\n        0: np.array(\n            [\n                [1, 0, 0],\n                [1, 0, 0],\n                [1, 0, 0],\n                [1, 0, 0],\n                [0, 1, 0],\n                [0, 0, 1],\n            ]\n        ),\n        one_third: np.array(\n            [\n                [9, 0, 0],\n                [6, 3, 0],\n                [4, 4, 1],\n                [4, 4, 1],\n                [0, 6, 3],\n                [0, 0, 9],\n            ]\n        )\n        / 9,\n        two_thirds: np.array(\n            [\n                [9, 0, 0],\n                [3, 6, 0],\n                [1, 4, 4],\n                [1, 4, 4],\n                [0, 3, 6],\n                [0, 0, 9],\n            ]\n        )\n        / 9,\n        1: np.array(\n            [\n                [1, 0, 0],\n                [0, 1, 0],\n                [0, 0, 1],\n                [0, 0, 1],\n                [0, 0, 1],\n                [0, 0, 1],\n            ]\n        ),\n    },\n    # For cubic Béziers\n    3: {\n        0: np.array(\n            [\n                [1, 0, 0, 0],\n                [1, 0, 0, 0],\n                [1, 0, 0, 0],\n                [1, 0, 0, 0],\n                [1, 0, 0, 0],\n                [0, 1, 0, 0],\n                [0, 0, 1, 0],\n                [0, 0, 0, 1],\n            ]\n        ),\n        one_third: np.array(\n            [\n                [27, 0, 0, 0],\n                [18, 9, 0, 0],\n                [12, 12, 3, 0],\n                [8, 12, 6, 1],\n                [8, 12, 6, 1],\n                [0, 12, 12, 3],\n                [0, 0, 18, 9],\n                [0, 0, 0, 27],\n            ]\n        )\n        / 27,\n        two_thirds: np.array(\n            [\n                [27, 0, 0, 0],\n                [9, 18, 0, 0],\n                [3, 12, 12, 0],\n                [1, 6, 12, 8],\n                [1, 6, 12, 8],\n                [0, 3, 12, 12],\n                [0, 0, 9, 18],\n                [0, 0, 0, 27],\n            ]\n        )\n        / 27,\n        1: np.array(\n            [\n                [1, 0, 0, 0],\n                [0, 1, 0, 0],\n                [0, 0, 1, 0],\n                [0, 0, 0, 1],\n                [0, 0, 0, 1],\n                [0, 0, 0, 1],\n                [0, 0, 0, 1],\n                [0, 0, 0, 1],\n            ]\n        ),\n    },\n    # Test case with a quartic Bézier\n    # to check if the fallback algorithms work\n    4: {\n        0: np.array(\n            [\n                [1, 0, 0, 0, 0],\n                [1, 0, 0, 0, 0],\n                [1, 0, 0, 0, 0],\n                [1, 0, 0, 0, 0],\n                [1, 0, 0, 0, 0],\n                [1, 0, 0, 0, 0],\n                [0, 1, 0, 0, 0],\n                [0, 0, 1, 0, 0],\n                [0, 0, 0, 1, 0],\n                [0, 0, 0, 0, 1],\n            ]\n        ),\n        one_third: np.array(\n            [\n                [81, 0, 0, 0, 0],\n                [54, 27, 0, 0, 0],\n                [36, 36, 9, 0, 0],\n                [24, 36, 18, 3, 0],\n                [16, 32, 24, 8, 1],\n                [16, 32, 24, 8, 1],\n                [0, 24, 36, 18, 3],\n                [0, 0, 36, 36, 9],\n                [0, 0, 0, 54, 27],\n                [0, 0, 0, 0, 81],\n            ]\n        )\n        / 81,\n        two_thirds: np.array(\n            [\n                [81, 0, 0, 0, 0],\n                [27, 54, 0, 0, 0],\n                [9, 36, 36, 0, 0],\n                [3, 18, 36, 24, 0],\n                [1, 8, 24, 32, 16],\n                [1, 8, 24, 32, 16],\n                [0, 3, 18, 36, 24],\n                [0, 0, 9, 36, 36],\n                [0, 0, 0, 27, 54],\n                [0, 0, 0, 0, 81],\n            ]\n        )\n        / 81,\n        1: np.array(\n            [\n                [1, 0, 0, 0, 0],\n                [0, 1, 0, 0, 0],\n                [0, 0, 1, 0, 0],\n                [0, 0, 0, 1, 0],\n                [0, 0, 0, 0, 1],\n                [0, 0, 0, 0, 1],\n                [0, 0, 0, 0, 1],\n                [0, 0, 0, 0, 1],\n                [0, 0, 0, 0, 1],\n                [0, 0, 0, 0, 1],\n            ]\n        ),\n    },\n}\n"
  },
  {
    "path": "tests/module/utils/_subdivision_matrices.py",
    "content": "import numpy as np\n\n# Expected values for matrices in subdivide_bezier and others\n# Note that in bezier.py this is a list of dicts,\n# not a dict of dicts!\nSUBDIVISION_MATRICES = {\n    # For 0-degree Béziers\n    0: {\n        2: np.array([[1], [1]]),\n        3: np.array([[1], [1], [1]]),\n        4: np.array([[1], [1], [1], [1]]),\n    },\n    # For linear Béziers\n    1: {\n        2: np.array(\n            [\n                [2, 0],\n                [1, 1],\n                [1, 1],\n                [0, 2],\n            ]\n        )\n        / 2,\n        3: np.array(\n            [\n                [3, 0],\n                [2, 1],\n                [2, 1],\n                [1, 2],\n                [1, 2],\n                [0, 3],\n            ]\n        )\n        / 3,\n        4: np.array(\n            [\n                [4, 0],\n                [3, 1],\n                [3, 1],\n                [2, 2],\n                [2, 2],\n                [1, 3],\n                [1, 3],\n                [0, 4],\n            ]\n        )\n        / 4,\n    },\n    # For quadratic Béziers\n    2: {\n        2: np.array(\n            [\n                [4, 0, 0],\n                [2, 2, 0],\n                [1, 2, 1],\n                [1, 2, 1],\n                [0, 2, 2],\n                [0, 0, 4],\n            ]\n        )\n        / 4,\n        3: np.array(\n            [\n                [9, 0, 0],\n                [6, 3, 0],\n                [4, 4, 1],\n                [4, 4, 1],\n                [2, 5, 2],\n                [1, 4, 4],\n                [1, 4, 4],\n                [0, 3, 6],\n                [0, 0, 9],\n            ]\n        )\n        / 9,\n        4: np.array(\n            [\n                [16, 0, 0],\n                [12, 4, 0],\n                [9, 6, 1],\n                [9, 6, 1],\n                [6, 8, 2],\n                [4, 8, 4],\n                [4, 8, 4],\n                [2, 8, 6],\n                [1, 6, 9],\n                [1, 6, 9],\n                [0, 4, 12],\n                [0, 0, 16],\n            ]\n        )\n        / 16,\n    },\n    # For cubic Béziers\n    3: {\n        2: np.array(\n            [\n                [8, 0, 0, 0],\n                [4, 4, 0, 0],\n                [2, 4, 2, 0],\n                [1, 3, 3, 1],\n                [1, 3, 3, 1],\n                [0, 2, 4, 2],\n                [0, 0, 4, 4],\n                [0, 0, 0, 8],\n            ]\n        )\n        / 8,\n        3: np.array(\n            [\n                [27, 0, 0, 0],\n                [18, 9, 0, 0],\n                [12, 12, 3, 0],\n                [8, 12, 6, 1],\n                [8, 12, 6, 1],\n                [4, 12, 9, 2],\n                [2, 9, 12, 4],\n                [1, 6, 12, 8],\n                [1, 6, 12, 8],\n                [0, 3, 12, 12],\n                [0, 0, 9, 18],\n                [0, 0, 0, 27],\n            ]\n        )\n        / 27,\n        4: np.array(\n            [\n                [64, 0, 0, 0],\n                [48, 16, 0, 0],\n                [36, 24, 4, 0],\n                [27, 27, 9, 1],\n                [27, 27, 9, 1],\n                [18, 30, 14, 2],\n                [12, 28, 20, 4],\n                [8, 24, 24, 8],\n                [8, 24, 24, 8],\n                [4, 20, 28, 12],\n                [2, 14, 30, 18],\n                [1, 9, 27, 27],\n                [1, 9, 27, 27],\n                [0, 4, 24, 36],\n                [0, 0, 16, 48],\n                [0, 0, 0, 64],\n            ]\n        )\n        / 64,\n    },\n    # Test case with a quartic Bézier\n    # to check if the fallback algorithms work\n    4: {\n        2: np.array(\n            [\n                [16, 0, 0, 0, 0],\n                [8, 8, 0, 0, 0],\n                [4, 8, 4, 0, 0],\n                [2, 6, 6, 2, 0],\n                [1, 4, 6, 4, 1],\n                [1, 4, 6, 4, 1],\n                [0, 2, 6, 6, 2],\n                [0, 0, 4, 8, 4],\n                [0, 0, 0, 8, 8],\n                [0, 0, 0, 0, 16],\n            ]\n        )\n        / 16,\n    },\n}\n"
  },
  {
    "path": "tests/module/utils/test_bezier.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport numpy.testing as nt\nfrom _split_matrices import SPLIT_MATRICES\nfrom _subdivision_matrices import SUBDIVISION_MATRICES\n\nfrom manim.typing import ManimFloat\nfrom manim.utils.bezier import (\n    _get_subdivision_matrix,\n    get_quadratic_approximation_of_cubic,\n    get_smooth_cubic_bezier_handle_points,\n    interpolate,\n    partial_bezier_points,\n    split_bezier,\n    subdivide_bezier,\n)\n\nQUARTIC_BEZIER = np.array(\n    [\n        [-1, -1, 0],\n        [-1, 0, 0],\n        [0, 1, 0],\n        [1, 0, 0],\n        [1, -1, 0],\n    ],\n    dtype=float,\n)\n\n\ndef test_partial_bezier_points() -> None:\n    \"\"\"Test that :func:`partial_bezierpoints`, both in the\n    portion-matrix-building algorithm (degrees up to 3) and the\n    fallback algorithm (degree 4), works correctly.\n    \"\"\"\n    for degree, degree_dict in SUBDIVISION_MATRICES.items():\n        n_points = degree + 1\n        points = QUARTIC_BEZIER[:n_points]\n        for n_divisions, subdivision_matrix in degree_dict.items():\n            for i in range(n_divisions):\n                a = i / n_divisions\n                b = (i + 1) / n_divisions\n                portion_matrix = subdivision_matrix[n_points * i : n_points * (i + 1)]\n                nt.assert_allclose(\n                    partial_bezier_points(points, a, b),\n                    portion_matrix @ points,\n                    atol=1e-15,  # Needed because of floating-point errors\n                )\n\n\ndef test_split_bezier() -> None:\n    \"\"\"Test that :func:`split_bezier`, both in the\n    split-matrix-building algorithm (degrees up to 3) and the\n    fallback algorithm (degree 4), works correctly.\n    \"\"\"\n    for degree, degree_dict in SPLIT_MATRICES.items():\n        n_points = degree + 1\n        points = QUARTIC_BEZIER[:n_points]\n        for t, split_matrix in degree_dict.items():\n            nt.assert_allclose(\n                split_bezier(points, t), split_matrix @ points, atol=1e-15\n            )\n\n    for degree, degree_dict in SUBDIVISION_MATRICES.items():\n        n_points = degree + 1\n        points = QUARTIC_BEZIER[:n_points]\n        # Split in half\n        split_matrix = degree_dict[2]\n        nt.assert_allclose(\n            split_bezier(points, 0.5),\n            split_matrix @ points,\n        )\n\n\ndef test_get_subdivision_matrix() -> None:\n    \"\"\"Test that the memos in .:meth:`_get_subdivision_matrix`\n    are being correctly generated.\n    \"\"\"\n    # Only for degrees up to 3!\n    for degree in range(4):\n        degree_dict = SUBDIVISION_MATRICES[degree]\n        for n_divisions, subdivision_matrix in degree_dict.items():\n            nt.assert_allclose(\n                _get_subdivision_matrix(degree + 1, n_divisions),\n                subdivision_matrix,\n            )\n\n\ndef test_subdivide_bezier() -> None:\n    \"\"\"Test that :func:`subdivide_bezier`, both in the memoized cases\n    (degrees up to 3) and the fallback algorithm (degree 4), works\n    correctly.\n    \"\"\"\n    for degree, degree_dict in SUBDIVISION_MATRICES.items():\n        n_points = degree + 1\n        points = QUARTIC_BEZIER[:n_points]\n        for n_divisions, subdivision_matrix in degree_dict.items():\n            nt.assert_allclose(\n                subdivide_bezier(points, n_divisions),\n                subdivision_matrix @ points,\n            )\n\n\ndef test_get_smooth_cubic_bezier_handle_points() -> None:\n    \"\"\"Test that :func:`.get_smooth_cubic_bezier_handle_points` returns the\n    correct handles, both for open and closed Bézier splines.\n    \"\"\"\n    open_curve_corners = np.array(\n        [\n            [1, 1, 0],\n            [-1, 1, 1],\n            [-1, -1, 2],\n            [1, -1, 1],\n        ],\n        dtype=ManimFloat,\n    )\n    h1, h2 = get_smooth_cubic_bezier_handle_points(open_curve_corners)\n    assert np.allclose(\n        h1,\n        np.array(\n            [\n                [1 / 5, 11 / 9, 13 / 45],\n                [-7 / 5, 5 / 9, 64 / 45],\n                [-3 / 5, -13 / 9, 91 / 45],\n            ]\n        ),\n    )\n    assert np.allclose(\n        h2,\n        np.array(\n            [\n                [-3 / 5, 13 / 9, 26 / 45],\n                [-7 / 5, -5 / 9, 89 / 45],\n                [1 / 5, -11 / 9, 68 / 45],\n            ]\n        ),\n    )\n\n    closed_curve_corners = np.array(\n        [\n            [1, 1, 0],\n            [-1, 1, 1],\n            [-1, -1, 2],\n            [1, -1, 1],\n            [1, 1, 0],\n        ],\n        dtype=ManimFloat,\n    )\n    h1, h2 = get_smooth_cubic_bezier_handle_points(closed_curve_corners)\n    assert np.allclose(\n        h1,\n        np.array(\n            [\n                [1 / 2, 3 / 2, 0],\n                [-3 / 2, 1 / 2, 3 / 2],\n                [-1 / 2, -3 / 2, 2],\n                [3 / 2, -1 / 2, 1 / 2],\n            ]\n        ),\n    )\n    assert np.allclose(\n        h2,\n        np.array(\n            [\n                [-1 / 2, 3 / 2, 1 / 2],\n                [-3 / 2, -1 / 2, 2],\n                [1 / 2, -3 / 2, 3 / 2],\n                [3 / 2, 1 / 2, 0],\n            ]\n        ),\n    )\n\n\ndef test_get_quadratic_approximation_of_cubic() -> None:\n    C = np.array(\n        [\n            [-5, 2, 0],\n            [-4, 2, 0],\n            [-3, 2, 0],\n            [-2, 2, 0],\n            [-2, 2, 0],\n            [-7 / 3, 4 / 3, 0],\n            [-8 / 3, 2 / 3, 0],\n            [-3, 0, 0],\n            [-3, 0, 0],\n            [-1 / 3, -1, 0],\n            [7 / 3, -2, 0],\n            [5, -3, 0],\n        ]\n    )\n    a0, h0, h1, a1 = C[::4], C[1::4], C[2::4], C[3::4]\n\n    Q = get_quadratic_approximation_of_cubic(a0, h0, h1, a1)\n    assert np.allclose(\n        Q,\n        np.array(\n            [\n                [-5, 2, 0],\n                [-17 / 4, 2, 0],\n                [-7 / 2, 2, 0],\n                [-7 / 2, 2, 0],\n                [-11 / 4, 2, 0],\n                [-2, 2, 0],\n                [-2, 2, 0],\n                [-9 / 4, 3 / 2, 0],\n                [-5 / 2, 1, 0],\n                [-5 / 2, 1, 0],\n                [-11 / 4, 1 / 2, 0],\n                [-3, 0, 0],\n                [-3, 0, 0],\n                [-1, -3 / 4, 0],\n                [1, -3 / 2, 0],\n                [1, -3 / 2, 0],\n                [3, -9 / 4, 0],\n                [5, -3, 0],\n            ]\n        ),\n    )\n\n\ndef test_interpolate() -> None:\n    \"\"\"Test that :func:`interpolate` handles interpolation of both float and uint8 values.\"\"\"\n    start = 127.0\n    end = 25.0\n    alpha = 0.2\n    val = interpolate(start, end, alpha)\n    assert np.allclose(val, 106.6000000)\n\n    start = np.array(127, dtype=np.uint8)\n    end = np.array(25, dtype=np.uint8)\n    alpha = 0.09739\n    val = interpolate(start, end, alpha)\n    assert np.allclose(val, np.array([117.06622]))\n"
  },
  {
    "path": "tests/module/utils/test_color.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim import BLACK, RED, WHITE, ManimColor, Mobject, Scene, VMobject\n\n\ndef test_import_color():\n    import manim.utils.color as C\n\n    C.WHITE\n\n\ndef test_background_color():\n    S = Scene()\n    S.camera.background_color = \"#ff0000\"\n    S.renderer.update_frame(S)\n    np.testing.assert_array_equal(\n        S.renderer.get_frame()[0, 0], np.array([255, 0, 0, 255])\n    )\n\n    S.camera.background_color = \"#436f80\"\n    S.renderer.update_frame(S)\n    np.testing.assert_array_equal(\n        S.renderer.get_frame()[0, 0], np.array([67, 111, 128, 255])\n    )\n\n    S.camera.background_color = \"#ffffff\"\n    S.renderer.update_frame(S)\n    np.testing.assert_array_equal(\n        S.renderer.get_frame()[0, 0], np.array([255, 255, 255, 255])\n    )\n\n    S.camera.background_color = \"#bbffbb\"\n    S.camera.background_opacity = 0.5\n    S.renderer.update_frame(S)\n    np.testing.assert_array_equal(\n        S.renderer.get_frame()[0, 0], np.array([187, 255, 187, 127])\n    )\n\n\ndef test_set_color():\n    m = Mobject()\n    assert m.color.to_hex() == \"#FFFFFF\"\n    m.set_color(BLACK)\n    assert m.color.to_hex() == \"#000000\"\n\n    m = VMobject()\n    assert m.color.to_hex() == \"#FFFFFF\"\n    m.set_color(BLACK)\n    assert m.color.to_hex() == \"#000000\"\n\n\ndef test_color_hash():\n    assert hash(WHITE) == hash(ManimColor([1.0, 1.0, 1.0, 1.0]))\n    assert hash(WHITE) == hash(\"#FFFFFFFF\")\n    assert hash(WHITE) != hash(RED)\n"
  },
  {
    "path": "tests/module/utils/test_deprecation.py",
    "content": "from __future__ import annotations\n\nfrom manim.utils.deprecation import deprecated, deprecated_params\n\n\ndef _get_caplog_record_msg(manim_caplog):\n    logger_name, level, message = manim_caplog.record_tuples[0]\n    return message\n\n\n@deprecated\nclass Foo:\n    def __init__(self):\n        pass\n\n\n@deprecated(since=\"v0.6.0\")\nclass Bar:\n    \"\"\"The Bar class.\"\"\"\n\n    def __init__(self):\n        pass\n\n\n@deprecated(until=\"06/01/2021\")\nclass Baz:\n    \"\"\"The Baz class.\"\"\"\n\n    def __init__(self):\n        pass\n\n\n@deprecated(since=\"0.7.0\", until=\"0.9.0-rc2\")\nclass Qux:\n    def __init__(self):\n        pass\n\n\n@deprecated(message=\"Use something else.\")\nclass Quux:\n    def __init__(self):\n        pass\n\n\n@deprecated(replacement=\"ReplaceQuuz\")\nclass Quuz:\n    def __init__(self):\n        pass\n\n\nclass ReplaceQuuz:\n    def __init__(self):\n        pass\n\n\n@deprecated(\n    since=\"0.7.0\",\n    until=\"1.2.1\",\n    replacement=\"ReplaceQuuz\",\n    message=\"Don't use this please.\",\n)\nclass QuuzAll:\n    def __init__(self):\n        pass\n\n\ndoc_admonition = \"\\n\\n.. attention:: Deprecated\\n  \"\n\n\ndef test_deprecate_class_no_args(manim_caplog):\n    \"\"\"Test the deprecation of a class (decorator with no arguments).\"\"\"\n    f = Foo()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The class Foo has been deprecated and may be removed in a later version.\"\n    )\n    assert f.__doc__ == f\"{doc_admonition}{msg}\"\n\n\ndef test_deprecate_class_since(manim_caplog):\n    \"\"\"Test the deprecation of a class (decorator with since argument).\"\"\"\n    b = Bar()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The class Bar has been deprecated since v0.6.0 and may be removed in a later version.\"\n    )\n    assert b.__doc__ == f\"The Bar class.{doc_admonition}{msg}\"\n\n\ndef test_deprecate_class_until(manim_caplog):\n    \"\"\"Test the deprecation of a class (decorator with until argument).\"\"\"\n    bz = Baz()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The class Baz has been deprecated and is expected to be removed after 06/01/2021.\"\n    )\n    assert bz.__doc__ == f\"The Baz class.{doc_admonition}{msg}\"\n\n\ndef test_deprecate_class_since_and_until(manim_caplog):\n    \"\"\"Test the deprecation of a class (decorator with since and until arguments).\"\"\"\n    qx = Qux()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The class Qux has been deprecated since 0.7.0 and is expected to be removed after 0.9.0-rc2.\"\n    )\n    assert qx.__doc__ == f\"{doc_admonition}{msg}\"\n\n\ndef test_deprecate_class_msg(manim_caplog):\n    \"\"\"Test the deprecation of a class (decorator with msg argument).\"\"\"\n    qu = Quux()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The class Quux has been deprecated and may be removed in a later version. Use something else.\"\n    )\n    assert qu.__doc__ == f\"{doc_admonition}{msg}\"\n\n\ndef test_deprecate_class_replacement(manim_caplog):\n    \"\"\"Test the deprecation of a class (decorator with replacement argument).\"\"\"\n    qz = Quuz()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The class Quuz has been deprecated and may be removed in a later version. Use ReplaceQuuz instead.\"\n    )\n    doc_msg = \"The class Quuz has been deprecated and may be removed in a later version. Use :class:`~.ReplaceQuuz` instead.\"\n    assert qz.__doc__ == f\"{doc_admonition}{doc_msg}\"\n\n\ndef test_deprecate_class_all(manim_caplog):\n    \"\"\"Test the deprecation of a class (decorator with all arguments).\"\"\"\n    qza = QuuzAll()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The class QuuzAll has been deprecated since 0.7.0 and is expected to be removed after 1.2.1. Use ReplaceQuuz instead. Don't use this please.\"\n    )\n    doc_msg = \"The class QuuzAll has been deprecated since 0.7.0 and is expected to be removed after 1.2.1. Use :class:`~.ReplaceQuuz` instead. Don't use this please.\"\n    assert qza.__doc__ == f\"{doc_admonition}{doc_msg}\"\n\n\n@deprecated\ndef useless(**kwargs):\n    pass\n\n\nclass Top:\n    def __init__(self):\n        pass\n\n    @deprecated(since=\"0.8.0\", message=\"This method is useless.\")\n    def mid_func(self):\n        \"\"\"Middle function in Top.\"\"\"\n        pass\n\n    @deprecated(until=\"1.4.0\", replacement=\"Top.NewNested\")\n    class Nested:\n        def __init__(self):\n            pass\n\n    class NewNested:\n        def __init__(self):\n            pass\n\n        @deprecated(since=\"1.0.0\", until=\"12/25/2025\")\n        def nested_func(self):\n            \"\"\"Nested function in Top.NewNested.\"\"\"\n            pass\n\n    class Bottom:\n        def __init__(self):\n            pass\n\n        def normal_func(self):\n            @deprecated\n            def nested_func(self):\n                pass\n\n            return nested_func\n\n    @deprecated_params(params=\"a, b, c\", message=\"Use something else.\")\n    def foo(self, **kwargs):\n        pass\n\n    @deprecated_params(params=\"a\", since=\"v0.2\", until=\"v0.4\")\n    def bar(self, **kwargs):\n        pass\n\n    @deprecated_params(redirections=[(\"old_param\", \"new_param\")])\n    def baz(self, **kwargs):\n        return kwargs\n\n    @deprecated_params(\n        redirections=[lambda runtime_in_ms: {\"run_time\": runtime_in_ms / 1000}],\n    )\n    def qux(self, **kwargs):\n        return kwargs\n\n    @deprecated_params(\n        redirections=[\n            lambda point2D_x=1, point2D_y=1: {\"point2D\": (point2D_x, point2D_y)},\n        ],\n    )\n    def quux(self, **kwargs):\n        return kwargs\n\n    @deprecated_params(\n        redirections=[\n            lambda point2D=1: (\n                {\"x\": point2D[0], \"y\": point2D[1]}\n                if isinstance(point2D, tuple)\n                else {\"x\": point2D, \"y\": point2D}\n            ),\n        ],\n    )\n    def quuz(self, **kwargs):\n        return kwargs\n\n\ndef test_deprecate_func_no_args(manim_caplog):\n    \"\"\"Test the deprecation of a method (decorator with no arguments).\"\"\"\n    useless()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The function useless has been deprecated and may be removed in a later version.\"\n    )\n    assert useless.__doc__ == f\"{doc_admonition}{msg}\"\n\n\ndef test_deprecate_func_in_class_since_and_message(manim_caplog):\n    \"\"\"Test the deprecation of a method within a class (decorator with since and message arguments).\"\"\"\n    t = Top()\n    t.mid_func()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The method Top.mid_func has been deprecated since 0.8.0 and may be removed in a later version. This method is useless.\"\n    )\n    assert t.mid_func.__doc__ == f\"Middle function in Top.{doc_admonition}{msg}\"\n\n\ndef test_deprecate_nested_class_until_and_replacement(manim_caplog):\n    \"\"\"Test the deprecation of a nested class (decorator with until and replacement arguments).\"\"\"\n    n = Top().Nested()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The class Top.Nested has been deprecated and is expected to be removed after 1.4.0. Use Top.NewNested instead.\"\n    )\n    doc_msg = \"The class Top.Nested has been deprecated and is expected to be removed after 1.4.0. Use :class:`~.Top.NewNested` instead.\"\n    assert n.__doc__ == f\"{doc_admonition}{doc_msg}\"\n\n\ndef test_deprecate_nested_class_func_since_and_until(manim_caplog):\n    \"\"\"Test the deprecation of a method within a nested class (decorator with since and until arguments).\"\"\"\n    n = Top().NewNested()\n    n.nested_func()\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The method Top.NewNested.nested_func has been deprecated since 1.0.0 and is expected to be removed after 12/25/2025.\"\n    )\n    assert (\n        n.nested_func.__doc__\n        == f\"Nested function in Top.NewNested.{doc_admonition}{msg}\"\n    )\n\n\ndef test_deprecate_nested_func(manim_caplog):\n    \"\"\"Test the deprecation of a nested method (decorator with no arguments).\"\"\"\n    b = Top().Bottom()\n    answer = b.normal_func()\n    answer(1)\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The method Top.Bottom.normal_func.<locals>.nested_func has been deprecated and may be removed in a later version.\"\n    )\n    assert answer.__doc__ == f\"{doc_admonition}{msg}\"\n\n\ndef test_deprecate_func_params(manim_caplog):\n    \"\"\"Test the deprecation of method parameters (decorator with params argument).\"\"\"\n    t = Top()\n    t.foo(a=2, b=3, z=4)\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The parameters a and b of method Top.foo have been deprecated and may be removed in a later version. Use something else.\"\n    )\n\n\ndef test_deprecate_func_single_param_since_and_until(manim_caplog):\n    \"\"\"Test the deprecation of a single method parameter (decorator with since and until arguments).\"\"\"\n    t = Top()\n    t.bar(a=1, b=2)\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The parameter a of method Top.bar has been deprecated since v0.2 and is expected to be removed after v0.4.\"\n    )\n\n\ndef test_deprecate_func_param_redirect_tuple(manim_caplog):\n    \"\"\"Test the deprecation of a method parameter and redirecting it to a new one using tuple.\"\"\"\n    t = Top()\n    obj = t.baz(x=1, old_param=2)\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The parameter old_param of method Top.baz has been deprecated and may be removed in a later version.\"\n    )\n    assert obj == {\"x\": 1, \"new_param\": 2}\n\n\ndef test_deprecate_func_param_redirect_lambda(manim_caplog):\n    \"\"\"Test the deprecation of a method parameter and redirecting it to a new one using lambda function.\"\"\"\n    t = Top()\n    obj = t.qux(runtime_in_ms=500)\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The parameter runtime_in_ms of method Top.qux has been deprecated and may be removed in a later version.\"\n    )\n    assert obj == {\"run_time\": 0.5}\n\n\ndef test_deprecate_func_param_redirect_many_to_one(manim_caplog):\n    \"\"\"Test the deprecation of multiple method parameters and redirecting them to one.\"\"\"\n    t = Top()\n    obj = t.quux(point2D_x=3, point2D_y=5)\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The parameters point2D_x and point2D_y of method Top.quux have been deprecated and may be removed in a later version.\"\n    )\n    assert obj == {\"point2D\": (3, 5)}\n\n\ndef test_deprecate_func_param_redirect_one_to_many(manim_caplog):\n    \"\"\"Test the deprecation of one method parameter and redirecting it to many.\"\"\"\n    t = Top()\n    obj1 = t.quuz(point2D=0)\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The parameter point2D of method Top.quuz has been deprecated and may be removed in a later version.\"\n    )\n    assert obj1 == {\"x\": 0, \"y\": 0}\n\n    manim_caplog.clear()\n\n    obj2 = t.quuz(point2D=(2, 3))\n    assert len(manim_caplog.record_tuples) == 1\n    msg = _get_caplog_record_msg(manim_caplog)\n    assert (\n        msg\n        == \"The parameter point2D of method Top.quuz has been deprecated and may be removed in a later version.\"\n    )\n    assert obj2 == {\"x\": 2, \"y\": 3}\n"
  },
  {
    "path": "tests/module/utils/test_file_ops.py",
    "content": "from __future__ import annotations\n\nfrom pathlib import Path\n\nfrom manim import *\nfrom tests.assert_utils import assert_dir_exists, assert_file_not_exists\nfrom tests.utils.video_tester import *\n\n\ndef test_guarantee_existence(tmp_path: Path):\n    test_dir = tmp_path / \"test\"\n    guarantee_existence(test_dir)\n    # test if file dir got created\n    assert_dir_exists(test_dir)\n    with (test_dir / \"test.txt\").open(\"x\") as f:\n        pass\n    # test if file didn't get deleted\n    guarantee_existence(test_dir)\n\n\ndef test_guarantee_empty_existence(tmp_path: Path):\n    test_dir = tmp_path / \"test\"\n    test_dir.mkdir()\n    with (test_dir / \"test.txt\").open(\"x\"):\n        pass\n\n    guarantee_empty_existence(test_dir)\n    # test if dir got created\n    assert_dir_exists(test_dir)\n    # test if dir got cleaned\n    assert_file_not_exists(test_dir / \"test.txt\")\n"
  },
  {
    "path": "tests/module/utils/test_hashing.py",
    "content": "from __future__ import annotations\n\nimport json\nfrom zlib import crc32\n\nimport pytest\n\nimport manim.utils.hashing as hashing\nfrom manim import Square\n\nALREADY_PROCESSED_PLACEHOLDER = hashing._Memoizer.ALREADY_PROCESSED_PLACEHOLDER\n\n\n@pytest.fixture(autouse=True)\ndef reset_already_processed():\n    hashing._Memoizer.reset_already_processed()\n\n\ndef test_JSON_basic():\n    o = {\"test\": 1, 2: 4, 3: 2.0}\n    o_serialized = hashing.get_json(o)\n    assert isinstance(o_serialized, str)\n    assert o_serialized == str({\"test\": 1, \"2\": 4, \"3\": 2.0}).replace(\"'\", '\"')\n\n\ndef test_JSON_with_object():\n    class Obj:\n        def __init__(self, a):\n            self.a = a\n            self.b = 3.0\n            self.c = [1, 2, \"test\", [\"nested list\"]]\n            self.d = {2: 3, \"2\": \"salut\"}\n\n    o = Obj(2)\n    o_serialized = hashing.get_json(o)\n    assert (\n        str(o_serialized)\n        == '{\"a\": 2, \"b\": 3.0, \"c\": [1, 2, \"test\", [\"nested list\"]], \"d\": {\"2\": 3, \"2\": \"salut\"}}'\n    )\n\n\ndef test_JSON_with_function():\n    def test(uhu):\n        uhu += 2\n        return uhu\n\n    o_serialized = hashing.get_json(test)\n    dict_o = json.loads(o_serialized)\n    assert \"code\" in dict_o\n    assert \"nonlocals\" in dict_o\n    assert (\n        str(o_serialized)\n        == r'{\"code\": \"    def test(uhu):\\n        uhu += 2\\n        return uhu\\n\", \"nonlocals\": {}}'\n    )\n\n\ndef test_JSON_with_function_and_external_val():\n    external = 2\n\n    def test(uhu):\n        uhu += external\n        return uhu\n\n    o_ser = hashing.get_json(test)\n    external = 3\n    o_ser2 = hashing.get_json(test)\n    assert json.loads(o_ser2)[\"nonlocals\"] == {\"external\": 3}\n    assert o_ser != o_ser2\n\n\ndef test_JSON_with_method():\n    class A:\n        def __init__(self):\n            self.a = self.method\n            self.b = 3\n\n        def method(self, b):\n            b += 3\n            return b\n\n    o_ser = hashing.get_json(A())\n    dict_o = json.loads(o_ser)\n    assert dict_o[\"a\"][\"nonlocals\"] == {}\n\n\ndef test_JSON_with_wrong_keys():\n    def test():\n        return 3\n\n    class Test:\n        def __init__(self):\n            self.a = 2\n\n    a = {(1, 2): 3}\n    b = {Test(): 3}\n    c = {test: 3}\n    for el in [a, b, c]:\n        o_ser = hashing.get_json(el)\n        dict_o = json.loads(o_ser)\n        # check if this is an int (it meant that the lkey has been hashed)\n        assert int(list(dict_o.keys())[0])\n\n\ndef test_JSON_with_circular_references():\n    B = {1: 2}\n\n    class A:\n        def __init__(self):\n            self.b = B\n\n    B[\"circular_ref\"] = A()\n    o_ser = hashing.get_json(B)\n    dict_o = json.loads(o_ser)\n    assert dict_o[\"circular_ref\"][\"b\"] == ALREADY_PROCESSED_PLACEHOLDER\n\n\ndef test_JSON_with_big_np_array():\n    import numpy as np\n\n    a = np.zeros((1000, 1000))\n    o_ser = hashing.get_json(a)\n    assert \"TRUNCATED ARRAY\" in o_ser\n\n\ndef test_JSON_with_tuple():\n    o = [(1, [1])]\n    o_ser = hashing.get_json(o)\n    assert o_ser == \"[[1, [1]]]\"\n\n\ndef test_JSON_with_object_that_is_itself_circular_reference():\n    class T:\n        def __init__(self) -> None:\n            self.a = None\n\n    o = T()\n    o.a = o\n    hashing.get_json(o)\n\n\ndef test_hash_consistency():\n    def assert_two_objects_produce_same_hash(obj1, obj2, debug=False):\n        \"\"\"\n        When debug is True, if the hashes differ an assertion comparing (element-wise) the two objects will be raised,\n        and pytest will display a nice difference summary making it easier to debug.\n        \"\"\"\n        json1 = hashing.get_json(obj1)\n        hashing._Memoizer.reset_already_processed()\n        json2 = hashing.get_json(obj2)\n        hashing._Memoizer.reset_already_processed()\n        hash1 = crc32(repr(json1).encode())\n        hash2 = crc32(repr(json2).encode())\n        if hash1 != hash2 and debug:\n            dict1 = json.loads(json1)\n            dict2 = json.loads(json2)\n            assert dict1 == dict2\n        assert hash1 == hash2, f\"{obj1} and {obj2} have different hashes.\"\n\n    assert_two_objects_produce_same_hash(Square(), Square())\n    s = Square()\n    assert_two_objects_produce_same_hash(s, s.copy())\n"
  },
  {
    "path": "tests/module/utils/test_manim_color.py",
    "content": "from __future__ import annotations\n\nimport colorsys\n\nimport numpy as np\nimport numpy.testing as nt\n\nfrom manim.utils.color import (\n    BLACK,\n    HSV,\n    RED,\n    WHITE,\n    YELLOW,\n    ManimColor,\n    ManimColorDType,\n)\nfrom manim.utils.color.XKCD import GREEN\n\n\ndef test_init_with_int() -> None:\n    color = ManimColor(0x123456, 0.5)\n    nt.assert_array_equal(\n        color._internal_value,\n        np.array([0x12, 0x34, 0x56, 0.5 * 255], dtype=ManimColorDType) / 255,\n    )\n    color = BLACK\n    nt.assert_array_equal(\n        color._internal_value, np.array([0, 0, 0, 1.0], dtype=ManimColorDType)\n    )\n    color = WHITE\n    nt.assert_array_equal(\n        color._internal_value, np.array([1.0, 1.0, 1.0, 1.0], dtype=ManimColorDType)\n    )\n\n\ndef test_init_with_hex() -> None:\n    color = ManimColor(\"0xFF0000\")\n    nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 1]))\n    color = ManimColor(\"0xFF000000\")\n    nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 0]))\n\n    color = ManimColor(\"#FF0000\")\n    nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 1]))\n    color = ManimColor(\"#FF000000\")\n    nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 0]))\n\n\ndef test_init_with_hex_short() -> None:\n    color = ManimColor(\"#F00\")\n    nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 1]))\n    color = ManimColor(\"0xF00\")\n    nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 1]))\n\n    color = ManimColor(\"#F000\")\n    nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 0]))\n    color = ManimColor(\"0xF000\")\n    nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 0]))\n\n\ndef test_init_with_string() -> None:\n    color = ManimColor(\"BLACK\")\n    nt.assert_array_equal(color._internal_value, BLACK._internal_value)\n\n\ndef test_init_with_tuple_int() -> None:\n    color = ManimColor((50, 10, 50))\n    nt.assert_array_equal(\n        color._internal_value, np.array([50 / 255, 10 / 255, 50 / 255, 1.0])\n    )\n\n    color = ManimColor((50, 10, 50, 50))\n    nt.assert_array_equal(\n        color._internal_value, np.array([50 / 255, 10 / 255, 50 / 255, 50 / 255])\n    )\n\n\ndef test_init_with_tuple_float() -> None:\n    color = ManimColor((0.5, 0.6, 0.7))\n    nt.assert_array_equal(color._internal_value, np.array([0.5, 0.6, 0.7, 1.0]))\n\n    color = ManimColor((0.5, 0.6, 0.7, 0.1))\n    nt.assert_array_equal(color._internal_value, np.array([0.5, 0.6, 0.7, 0.1]))\n\n\ndef test_to_integer() -> None:\n    color = ManimColor((0x1, 0x2, 0x3, 0x4))\n    nt.assert_equal(color.to_integer(), 0x010203)\n\n\ndef test_to_rgb() -> None:\n    color = ManimColor((0x1, 0x2, 0x3, 0x4))\n    nt.assert_array_equal(color.to_rgb(), (0x1 / 255, 0x2 / 255, 0x3 / 255))\n    nt.assert_array_equal(color.to_int_rgb(), (0x1, 0x2, 0x3))\n    nt.assert_array_equal(color.to_rgba(), (0x1 / 255, 0x2 / 255, 0x3 / 255, 0x4 / 255))\n    nt.assert_array_equal(color.to_int_rgba(), (0x1, 0x2, 0x3, 0x4))\n    nt.assert_array_equal(\n        color.to_rgba_with_alpha(0.5), (0x1 / 255, 0x2 / 255, 0x3 / 255, 0.5)\n    )\n    nt.assert_array_equal(\n        color.to_int_rgba_with_alpha(0.5), (0x1, 0x2, 0x3, int(0.5 * 255))\n    )\n\n\ndef test_to_hex() -> None:\n    color = ManimColor((0x1, 0x2, 0x3, 0x4))\n    nt.assert_equal(color.to_hex(), \"#010203\")\n    nt.assert_equal(color.to_hex(True), \"#01020304\")\n\n\ndef test_to_hsv() -> None:\n    color = ManimColor((0x1, 0x2, 0x3, 0x4))\n    nt.assert_array_equal(\n        color.to_hsv(), colorsys.rgb_to_hsv(0x1 / 255, 0x2 / 255, 0x3 / 255)\n    )\n\n\ndef test_to_hsl() -> None:\n    color = ManimColor((0x1, 0x2, 0x3, 0x4))\n    hls = colorsys.rgb_to_hls(0x1 / 255, 0x2 / 255, 0x3 / 255)\n\n    nt.assert_array_equal(color.to_hsl(), np.array([hls[0], hls[2], hls[1]]))\n\n\ndef test_from_hsl() -> None:\n    hls = colorsys.rgb_to_hls(0x1 / 255, 0x2 / 255, 0x3 / 255)\n    hsl = np.array([hls[0], hls[2], hls[1]])\n\n    color = ManimColor.from_hsl(hsl)\n    rgb = np.array([0x1 / 255, 0x2 / 255, 0x3 / 255])\n\n    nt.assert_allclose(color.to_rgb(), rgb)\n\n\ndef test_invert() -> None:\n    color = ManimColor((0x1, 0x2, 0x3, 0x4))\n    rgba = color._internal_value\n    inverted = color.invert()\n    nt.assert_array_equal(\n        inverted._internal_value, (1 - rgba[0], 1 - rgba[1], 1 - rgba[2], rgba[3])\n    )\n\n\ndef test_invert_with_alpha() -> None:\n    color = ManimColor((0x1, 0x2, 0x3, 0x4))\n    rgba = color._internal_value\n    inverted = color.invert(True)\n    nt.assert_array_equal(\n        inverted._internal_value, (1 - rgba[0], 1 - rgba[1], 1 - rgba[2], 1 - rgba[3])\n    )\n\n\ndef test_interpolate() -> None:\n    r1 = RED._internal_value\n    r2 = YELLOW._internal_value\n    nt.assert_array_equal(\n        RED.interpolate(YELLOW, 0.5)._internal_value, 0.5 * r1 + 0.5 * r2\n    )\n\n\ndef test_opacity() -> None:\n    nt.assert_equal(RED.opacity(0.5)._internal_value[3], 0.5)\n\n\ndef test_parse() -> None:\n    nt.assert_equal(ManimColor.parse([RED, YELLOW]), [RED, YELLOW])\n\n\ndef test_mc_operators() -> None:\n    c1 = RED\n    c2 = GREEN\n    halfway1 = 0.5 * c1 + 0.5 * c2\n    halfway2 = c1.interpolate(c2, 0.5)\n    nt.assert_equal(halfway1, halfway2)\n    nt.assert_array_equal((WHITE / 2.0)._internal_value, np.array([0.5, 0.5, 0.5, 0.5]))\n\n\ndef test_mc_from_functions() -> None:\n    color = ManimColor.from_hex(\"#ff00a0\")\n    nt.assert_equal(color.to_hex(), \"#FF00A0\")\n\n    color = ManimColor.from_rgb((1.0, 1.0, 0.0))\n    nt.assert_equal(color.to_hex(), \"#FFFF00\")\n\n    color = ManimColor.from_rgba((1.0, 1.0, 0.0, 1.0))\n    nt.assert_equal(color.to_hex(True), \"#FFFF00FF\")\n\n    color = ManimColor.from_hsv((1.0, 1.0, 1.0), alpha=0.0)\n    nt.assert_equal(color.to_hex(True), \"#FF000000\")\n\n\ndef test_hsv_init() -> None:\n    color = HSV((0.25, 1, 1))\n    nt.assert_array_equal(color._internal_value, np.array([0.5, 1.0, 0.0, 1.0]))\n\n\ndef test_into_HSV() -> None:\n    nt.assert_equal(RED.into(HSV).into(ManimColor), RED)\n\n\ndef test_contrasting() -> None:\n    nt.assert_equal(BLACK.contrasting(), WHITE)\n    nt.assert_equal(WHITE.contrasting(), BLACK)\n    nt.assert_equal(RED.contrasting(0.1), BLACK)\n    nt.assert_equal(RED.contrasting(0.9), WHITE)\n    nt.assert_equal(BLACK.contrasting(dark=GREEN, light=RED), RED)\n    nt.assert_equal(WHITE.contrasting(dark=GREEN, light=RED), GREEN)\n\n\ndef test_lighter() -> None:\n    c = RED.opacity(0.42)\n    cl = c.lighter(0.2)\n    nt.assert_array_equal(\n        cl._internal_value[:3],\n        0.8 * c._internal_value[:3] + 0.2 * WHITE._internal_value[:3],\n    )\n    nt.assert_equal(cl[-1], c[-1])\n\n\ndef test_darker() -> None:\n    c = RED.opacity(0.42)\n    cd = c.darker(0.2)\n    nt.assert_array_equal(\n        cd._internal_value[:3],\n        0.8 * c._internal_value[:3] + 0.2 * BLACK._internal_value[:3],\n    )\n    nt.assert_equal(cd[-1], c[-1])\n"
  },
  {
    "path": "tests/module/utils/test_space_ops.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport pytest\n\nfrom manim.utils.space_ops import *\nfrom manim.utils.space_ops import shoelace\n\n\ndef test_rotate_vector():\n    vec = np.array([0, 1, 0])\n    rotated = rotate_vector(vec, np.pi / 2)\n    assert np.round(rotated[0], 5) == -1.0\n    assert not np.round(rotated[1:], 5).any()\n    np.testing.assert_array_equal(rotate_vector(np.zeros(3), np.pi / 4), np.zeros(3))\n\n\ndef test_rotation_matrices():\n    ang = np.pi / 6\n    ax = np.array([1, 1, 1])\n    np.testing.assert_array_equal(\n        np.round(rotation_matrix(ang, ax, True), 5),\n        np.round(\n            np.array(\n                [\n                    [0.91068, -0.24402, 0.33333, 0.0],\n                    [0.33333, 0.91068, -0.24402, 0.0],\n                    [-0.24402, 0.33333, 0.91068, 0.0],\n                    [0.0, 0.0, 0.0, 1.0],\n                ]\n            ),\n            5,\n        ),\n    )\n    np.testing.assert_array_equal(\n        np.round(rotation_about_z(np.pi / 3), 5),\n        np.array(\n            [\n                [0.5, -0.86603, 0.0],\n                [0.86603, 0.5, 0.0],\n                [0.0, 0.0, 1.0],\n            ]\n        ),\n    )\n    np.testing.assert_array_equal(\n        np.round(z_to_vector(np.array([1, 2, 3])), 5),\n        np.array(\n            [\n                [0.96362, 0.0, 0.26726],\n                [-0.14825, 0.83205, 0.53452],\n                [-0.22237, -0.5547, 0.80178],\n            ]\n        ),\n    )\n\n\ndef test_angle_of_vector():\n    assert angle_of_vector(np.array([1, 1, 1])) == np.pi / 4\n    assert (\n        np.round(angle_between_vectors(np.array([1, 1, 1]), np.array([-1, 1, 1])), 5)\n        == 1.23096\n    )\n    np.testing.assert_equal(angle_of_vector(np.zeros(3)), 0.0)\n\n\ndef test_angle_of_vector_vectorized():\n    rng = np.random.default_rng()\n    vec = rng.standard_normal((4, 10))\n    ref = [np.angle(complex(*v[:2])) for v in vec.T]\n    np.testing.assert_array_equal(ref, angle_of_vector(vec))\n\n\ndef test_center_of_mass():\n    np.testing.assert_array_equal(\n        center_of_mass([[0, 0, 0], [1, 2, 3]]), np.array([0.5, 1.0, 1.5])\n    )\n\n\ndef test_line_intersection():\n    np.testing.assert_array_equal(\n        line_intersection(\n            [[0, 0, 0], [3, 3, 0]],\n            [[0, 3, 0], [3, 0, 0]],\n        ),\n        np.array([1.5, 1.5, 0.0]),\n    )\n    with pytest.raises(ValueError):\n        line_intersection(  # parallel lines\n            [[0, 1, 0], [5, 1, 0]],\n            [[0, 6, 0], [5, 6, 0]],\n        )\n    with pytest.raises(ValueError):\n        line_intersection(  # lines not in xy-plane\n            [[0, 0, 3], [3, 3, 3]],\n            [[0, 3, 3], [3, 0, 3]],\n        )\n    with pytest.raises(ValueError):\n        line_intersection(  # lines are equal\n            [[2, 2, 0], [3, 1, 0]],\n            [[2, 2, 0], [3, 1, 0]],\n        )\n    np.testing.assert_array_equal(\n        line_intersection(  # lines with ends out of bounds\n            [[0, 0, 0], [1, 1, 0]],\n            [[0, 4, 0], [1, 3, 0]],\n        ),\n        np.array([2, 2, 0]),\n    )\n\n\ndef test_shoelace():\n    assert shoelace(np.array([[1, 2], [3, 4]])) == 6\n\n\ndef test_polar_coords():\n    a = np.array([1, 1, 0])\n    b = (2, np.pi / 2, np.pi / 2)\n    np.testing.assert_array_equal(\n        np.round(cartesian_to_spherical(a), 4),\n        np.round([2**0.5, np.pi / 4, np.pi / 2], 4),\n    )\n    np.testing.assert_array_equal(\n        np.round(spherical_to_cartesian(b), 4), np.array([0, 2, 0])\n    )\n"
  },
  {
    "path": "tests/module/utils/test_tex.py",
    "content": "import pytest\n\nfrom manim.utils.tex import TexTemplate, _texcode_for_environment\n\nDEFAULT_BODY = r\"\"\"\\documentclass[preview]{standalone}\n\\usepackage[english]{babel}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\n\\begin{document}\nYourTextHere\n\\end{document}\"\"\"\n\nBODY_WITH_ADDED_PREAMBLE = r\"\"\"\\documentclass[preview]{standalone}\n\\usepackage[english]{babel}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\n\\usepackage{testpackage}\n\\begin{document}\nYourTextHere\n\\end{document}\"\"\"\n\nBODY_WITH_PREPENDED_PREAMBLE = r\"\"\"\\documentclass[preview]{standalone}\n\\usepackage{testpackage}\n\\usepackage[english]{babel}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\n\\begin{document}\nYourTextHere\n\\end{document}\"\"\"\n\nBODY_WITH_ADDED_DOCUMENT = r\"\"\"\\documentclass[preview]{standalone}\n\\usepackage[english]{babel}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\n\\begin{document}\n\\boldmath\nYourTextHere\n\\end{document}\"\"\"\n\nBODY_REPLACE = r\"\"\"\\documentclass[preview]{standalone}\n\\usepackage[english]{babel}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\n\\begin{document}\n\\sqrt{2}\n\\end{document}\"\"\"\n\nBODY_REPLACE_IN_ENV = r\"\"\"\\documentclass[preview]{standalone}\n\\usepackage[english]{babel}\n\\usepackage{amsmath}\n\\usepackage{amssymb}\n\\begin{document}\n\\begin{align}\n\\sqrt{2}\n\\end{align}\n\\end{document}\"\"\"\n\n\ndef test_tex_template_default_body():\n    template = TexTemplate()\n    assert template.body == DEFAULT_BODY\n\n\ndef test_tex_template_preamble():\n    template = TexTemplate()\n\n    template.add_to_preamble(r\"\\usepackage{testpackage}\")\n    assert template.body == BODY_WITH_ADDED_PREAMBLE\n\n\ndef test_tex_template_preprend_preamble():\n    template = TexTemplate()\n\n    template.add_to_preamble(r\"\\usepackage{testpackage}\", prepend=True)\n    assert template.body == BODY_WITH_PREPENDED_PREAMBLE\n\n\ndef test_tex_template_document():\n    template = TexTemplate()\n\n    template.add_to_document(r\"\\boldmath\")\n    assert template.body == BODY_WITH_ADDED_DOCUMENT\n\n\ndef test_tex_template_texcode_for_expression():\n    template = TexTemplate()\n\n    assert template.get_texcode_for_expression(r\"\\sqrt{2}\") == BODY_REPLACE\n\n\ndef test_tex_template_texcode_for_expression_in_env():\n    template = TexTemplate()\n\n    assert (\n        template.get_texcode_for_expression_in_env(r\"\\sqrt{2}\", environment=\"align\")\n        == BODY_REPLACE_IN_ENV\n    )\n\n\ndef test_tex_template_fixed_body():\n    template = TexTemplate()\n\n    # Usually set when calling `from_file`\n    template.body = \"dummy\"\n\n    assert template.body == \"dummy\"\n\n    with pytest.warns(\n        UserWarning,\n        match=\"This TeX template was created with a fixed body, trying to add text the preamble will have no effect.\",\n    ):\n        template.add_to_preamble(\"dummys\")\n\n    with pytest.warns(\n        UserWarning,\n        match=\"This TeX template was created with a fixed body, trying to add text the document will have no effect.\",\n    ):\n        template.add_to_document(\"dummy\")\n\n\ndef test_texcode_for_environment():\n    \"\"\"Test that the environment is correctly extracted from the input\"\"\"\n    # environment without arguments\n    assert _texcode_for_environment(\"align*\") == (r\"\\begin{align*}\", r\"\\end{align*}\")\n    assert _texcode_for_environment(\"{align*}\") == (r\"\\begin{align*}\", r\"\\end{align*}\")\n    assert _texcode_for_environment(r\"\\begin{align*}\") == (\n        r\"\\begin{align*}\",\n        r\"\\end{align*}\",\n    )\n    # environment with arguments\n    assert _texcode_for_environment(\"{tabular}[t]{cccl}\") == (\n        r\"\\begin{tabular}[t]{cccl}\",\n        r\"\\end{tabular}\",\n    )\n    assert _texcode_for_environment(\"tabular}{cccl\") == (\n        r\"\\begin{tabular}{cccl}\",\n        r\"\\end{tabular}\",\n    )\n    assert _texcode_for_environment(r\"\\begin{tabular}[t]{cccl}\") == (\n        r\"\\begin{tabular}[t]{cccl}\",\n        r\"\\end{tabular}\",\n    )\n"
  },
  {
    "path": "tests/module/utils/test_units.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport pytest\n\nfrom manim import PI, X_AXIS, Y_AXIS, Z_AXIS\nfrom manim.utils.unit import Degrees, Munits, Percent, Pixels\n\n\ndef test_units(config):\n    # make sure we are using the right frame geometry\n    config.pixel_width = 1920\n\n    np.testing.assert_allclose(config.frame_height, 8.0)\n\n    # Munits should be equivalent to the internal logical units\n    np.testing.assert_allclose(8.0 * Munits, config.frame_height)\n\n    # Pixels should convert from pixels to Munits\n    np.testing.assert_allclose(1920 * Pixels, config.frame_width)\n\n    # Percent should give the fractional length of the frame\n    np.testing.assert_allclose(50 * Percent(X_AXIS), config.frame_width / 2)\n    np.testing.assert_allclose(50 * Percent(Y_AXIS), config.frame_height / 2)\n\n    # The length of the Z axis is not defined\n    with pytest.raises(NotImplementedError):\n        Percent(Z_AXIS)\n\n    # Degrees should convert from degrees to radians\n    np.testing.assert_allclose(180 * Degrees, PI)\n"
  },
  {
    "path": "tests/opengl/__init__.py",
    "content": ""
  },
  {
    "path": "tests/opengl/test_animate_opengl.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport pytest\n\nfrom manim.animation.creation import Uncreate\nfrom manim.mobject.geometry.arc import Dot\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.geometry.polygram import Square\nfrom manim.mobject.mobject import override_animate\nfrom manim.mobject.types.vectorized_mobject import VGroup\n\n\ndef test_simple_animate(using_opengl_renderer):\n    s = Square()\n    scale_factor = 2\n    anim = s.animate.scale(scale_factor).build()\n    assert anim.mobject.target.width == scale_factor * s.width\n\n\ndef test_chained_animate(using_opengl_renderer):\n    s = Square()\n    scale_factor = 2\n    direction = np.array((1, 1, 0))\n    anim = s.animate.scale(scale_factor).shift(direction).build()\n    assert anim.mobject.target.width == scale_factor * s.width\n    assert (anim.mobject.target.get_center() == direction).all()\n\n\ndef test_overridden_animate(using_opengl_renderer):\n    class DotsWithLine(VGroup):\n        def __init__(self):\n            super().__init__()\n            self.left_dot = Dot().shift((-1, 0, 0))\n            self.right_dot = Dot().shift((1, 0, 0))\n            self.line = Line(self.left_dot, self.right_dot)\n            self.add(self.left_dot, self.right_dot, self.line)\n\n        def remove_line(self):\n            self.remove(self.line)\n\n        @override_animate(remove_line)\n        def _remove_line_animation(self, anim_args=None):\n            if anim_args is None:\n                anim_args = {}\n            self.remove_line()\n            return Uncreate(self.line, **anim_args)\n\n    dots_with_line = DotsWithLine()\n    anim = dots_with_line.animate.remove_line().build()\n    assert len(dots_with_line.submobjects) == 2\n    assert type(anim) is Uncreate\n\n\ndef test_chaining_overridden_animate(using_opengl_renderer):\n    class DotsWithLine(VGroup):\n        def __init__(self):\n            super().__init__()\n            self.left_dot = Dot().shift((-1, 0, 0))\n            self.right_dot = Dot().shift((1, 0, 0))\n            self.line = Line(self.left_dot, self.right_dot)\n            self.add(self.left_dot, self.right_dot, self.line)\n\n        def remove_line(self):\n            self.remove(self.line)\n\n        @override_animate(remove_line)\n        def _remove_line_animation(self, anim_args=None):\n            if anim_args is None:\n                anim_args = {}\n            self.remove_line()\n            return Uncreate(self.line, **anim_args)\n\n    with pytest.raises(\n        NotImplementedError,\n        match=\"not supported for overridden animations\",\n    ):\n        DotsWithLine().animate.shift((1, 0, 0)).remove_line()\n\n    with pytest.raises(\n        NotImplementedError,\n        match=\"not supported for overridden animations\",\n    ):\n        DotsWithLine().animate.remove_line().shift((1, 0, 0))\n\n\ndef test_animate_with_args(using_opengl_renderer):\n    s = Square()\n    scale_factor = 2\n    run_time = 2\n\n    anim = s.animate(run_time=run_time).scale(scale_factor).build()\n    assert anim.mobject.target.width == scale_factor * s.width\n    assert anim.run_time == run_time\n\n\ndef test_chained_animate_with_args(using_opengl_renderer):\n    s = Square()\n    scale_factor = 2\n    direction = np.array((1, 1, 0))\n    run_time = 2\n\n    anim = s.animate(run_time=run_time).scale(scale_factor).shift(direction).build()\n    assert anim.mobject.target.width == scale_factor * s.width\n    assert (anim.mobject.target.get_center() == direction).all()\n    assert anim.run_time == run_time\n\n\ndef test_animate_with_args_misplaced(using_opengl_renderer):\n    s = Square()\n    scale_factor = 2\n    run_time = 2\n\n    with pytest.raises(ValueError, match=\"must be passed before\"):\n        s.animate.scale(scale_factor)(run_time=run_time)\n\n    with pytest.raises(ValueError, match=\"must be passed before\"):\n        s.animate(run_time=run_time)(run_time=run_time).scale(scale_factor)\n"
  },
  {
    "path": "tests/opengl/test_axes_shift_opengl.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim.mobject.graphing.coordinate_systems import Axes\n\n\ndef test_axes_origin_shift(using_opengl_renderer):\n    ax = Axes(x_range=(5, 10, 1), y_range=(40, 45, 0.5))\n    np.testing.assert_allclose(\n        ax.coords_to_point(5.0, 40.0), ax.x_axis.number_to_point(5)\n    )\n    np.testing.assert_allclose(\n        ax.coords_to_point(5.0, 40.0), ax.y_axis.number_to_point(40)\n    )\n"
  },
  {
    "path": "tests/opengl/test_color_opengl.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim import BLACK, BLUE, GREEN, PURE_BLUE, PURE_GREEN, PURE_RED, Scene\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject\n\n\ndef test_import_color(using_opengl_renderer):\n    import manim.utils.color as C\n\n    C.WHITE\n\n\ndef test_background_color(using_opengl_renderer):\n    S = Scene()\n    S.renderer.background_color = \"#FF0000\"\n    S.renderer.update_frame(S)\n    np.testing.assert_array_equal(\n        S.renderer.get_frame()[0, 0], np.array([255, 0, 0, 255])\n    )\n\n    S.renderer.background_color = \"#436F80\"\n    S.renderer.update_frame(S)\n    np.testing.assert_array_equal(\n        S.renderer.get_frame()[0, 0], np.array([67, 111, 128, 255])\n    )\n\n    S.renderer.background_color = \"#FFFFFF\"\n    S.renderer.update_frame(S)\n    np.testing.assert_array_equal(\n        S.renderer.get_frame()[0, 0], np.array([255, 255, 255, 255])\n    )\n\n\ndef test_set_color(using_opengl_renderer):\n    m = OpenGLMobject()\n    assert m.color.to_hex() == \"#FFFFFF\"\n    np.all(m.rgbas == np.array([[0.0, 0.0, 0.0, 1.0]]))\n\n    m.set_color(BLACK)\n    assert m.color.to_hex() == \"#000000\"\n    np.all(m.rgbas == np.array([[1.0, 1.0, 1.0, 1.0]]))\n\n    m.set_color(PURE_GREEN, opacity=0.5)\n    assert m.color.to_hex() == \"#00FF00\"\n    np.all(m.rgbas == np.array([[0.0, 1.0, 0.0, 0.5]]))\n\n    m = OpenGLVMobject()\n    assert m.color.to_hex() == \"#FFFFFF\"\n    np.all(m.fill_rgba == np.array([[0.0, 0.0, 0.0, 1.0]]))\n    np.all(m.stroke_rgba == np.array([[0.0, 0.0, 0.0, 1.0]]))\n\n    m.set_color(BLACK)\n    assert m.color.to_hex() == \"#000000\"\n    np.all(m.fill_rgba == np.array([[1.0, 1.0, 1.0, 1.0]]))\n    np.all(m.stroke_rgba == np.array([[1.0, 1.0, 1.0, 1.0]]))\n\n    m.set_color(PURE_GREEN, opacity=0.5)\n    assert m.color.to_hex() == \"#00FF00\"\n    np.all(m.fill_rgba == np.array([[0.0, 1.0, 0.0, 0.5]]))\n    np.all(m.stroke_rgba == np.array([[0.0, 1.0, 0.0, 0.5]]))\n\n\ndef test_set_fill_color(using_opengl_renderer):\n    m = OpenGLVMobject()\n    assert m.fill_color.to_hex() == \"#FFFFFF\"\n    np.all(m.fill_rgba == np.array([[0.0, 1.0, 0.0, 0.5]]))\n\n    m.set_fill(BLACK)\n    assert m.fill_color.to_hex() == \"#000000\"\n    np.all(m.fill_rgba == np.array([[1.0, 1.0, 1.0, 1.0]]))\n\n    m.set_fill(PURE_GREEN, opacity=0.5)\n    assert m.fill_color.to_hex() == \"#00FF00\"\n    np.all(m.fill_rgba == np.array([[0.0, 1.0, 0.0, 0.5]]))\n\n\ndef test_set_stroke_color(using_opengl_renderer):\n    m = OpenGLVMobject()\n    assert m.stroke_color.to_hex() == \"#FFFFFF\"\n    np.all(m.stroke_rgba == np.array([[0.0, 1.0, 0.0, 0.5]]))\n\n    m.set_stroke(BLACK)\n    assert m.stroke_color.to_hex() == \"#000000\"\n    np.all(m.stroke_rgba == np.array([[1.0, 1.0, 1.0, 1.0]]))\n\n    m.set_stroke(PURE_GREEN, opacity=0.5)\n    assert m.stroke_color.to_hex() == \"#00FF00\"\n    np.all(m.stroke_rgba == np.array([[0.0, 1.0, 0.0, 0.5]]))\n\n\ndef test_set_fill(using_opengl_renderer):\n    m = OpenGLMobject()\n    assert m.color.to_hex() == \"#FFFFFF\"\n    m.set_color(BLACK)\n    assert m.color.to_hex() == \"#000000\"\n\n    m = OpenGLVMobject()\n    assert m.color.to_hex() == \"#FFFFFF\"\n    m.set_color(BLACK)\n    assert m.color.to_hex() == \"#000000\"\n\n\ndef test_set_color_handles_lists_of_strs(using_opengl_renderer):\n    m = OpenGLVMobject()\n    assert m.color.to_hex() == \"#FFFFFF\"\n    m.set_color([BLACK, BLUE, GREEN])\n    assert m.get_colors()[0] == BLACK\n    assert m.get_colors()[1] == BLUE\n    assert m.get_colors()[2] == GREEN\n\n    assert m.get_fill_colors()[0] == BLACK\n    assert m.get_fill_colors()[1] == BLUE\n    assert m.get_fill_colors()[2] == GREEN\n\n    assert m.get_stroke_colors()[0] == BLACK\n    assert m.get_stroke_colors()[1] == BLUE\n    assert m.get_stroke_colors()[2] == GREEN\n\n\ndef test_set_color_handles_lists_of_color_objects(using_opengl_renderer):\n    m = OpenGLVMobject()\n    assert m.color.to_hex() == \"#FFFFFF\"\n    m.set_color([PURE_BLUE, PURE_GREEN, PURE_RED])\n    assert m.get_colors()[0].to_hex() == \"#0000FF\"\n    assert m.get_colors()[1].to_hex() == \"#00FF00\"\n    assert m.get_colors()[2].to_hex() == \"#FF0000\"\n\n    assert m.get_fill_colors()[0].to_hex() == \"#0000FF\"\n    assert m.get_fill_colors()[1].to_hex() == \"#00FF00\"\n    assert m.get_fill_colors()[2].to_hex() == \"#FF0000\"\n\n    assert m.get_stroke_colors()[0].to_hex() == \"#0000FF\"\n    assert m.get_stroke_colors()[1].to_hex() == \"#00FF00\"\n    assert m.get_stroke_colors()[2].to_hex() == \"#FF0000\"\n\n\ndef test_set_fill_handles_lists_of_strs(using_opengl_renderer):\n    m = OpenGLVMobject()\n    assert m.fill_color.to_hex() == \"#FFFFFF\"\n    m.set_fill([BLACK.to_hex(), BLUE.to_hex(), GREEN.to_hex()])\n    assert m.get_fill_colors()[0].to_hex() == BLACK.to_hex()\n    assert m.get_fill_colors()[1].to_hex() == BLUE.to_hex()\n    assert m.get_fill_colors()[2].to_hex() == GREEN.to_hex()\n\n\ndef test_set_fill_handles_lists_of_color_objects(using_opengl_renderer):\n    m = OpenGLVMobject()\n    assert m.fill_color.to_hex() == \"#FFFFFF\"\n    m.set_fill([PURE_BLUE, PURE_GREEN, PURE_RED])\n    assert m.get_fill_colors()[0].to_hex() == \"#0000FF\"\n    assert m.get_fill_colors()[1].to_hex() == \"#00FF00\"\n    assert m.get_fill_colors()[2].to_hex() == \"#FF0000\"\n\n\ndef test_set_stroke_handles_lists_of_strs(using_opengl_renderer):\n    m = OpenGLVMobject()\n    assert m.stroke_color.to_hex() == \"#FFFFFF\"\n    m.set_stroke([BLACK.to_hex(), BLUE.to_hex(), GREEN.to_hex()])\n    assert m.get_stroke_colors()[0].to_hex() == BLACK.to_hex()\n    assert m.get_stroke_colors()[1].to_hex() == BLUE.to_hex()\n    assert m.get_stroke_colors()[2].to_hex() == GREEN.to_hex()\n\n\ndef test_set_stroke_handles_lists_of_color_objects(using_opengl_renderer):\n    m = OpenGLVMobject()\n    assert m.stroke_color.to_hex() == \"#FFFFFF\"\n    m.set_stroke([PURE_BLUE, PURE_GREEN, PURE_RED])\n    assert m.get_stroke_colors()[0].to_hex() == \"#0000FF\"\n    assert m.get_stroke_colors()[1].to_hex() == \"#00FF00\"\n    assert m.get_stroke_colors()[2].to_hex() == \"#FF0000\"\n"
  },
  {
    "path": "tests/opengl/test_composition_opengl.py",
    "content": "from __future__ import annotations\n\nfrom unittest.mock import MagicMock\n\nfrom manim.animation.animation import Animation, Wait\nfrom manim.animation.composition import AnimationGroup, Succession\nfrom manim.animation.fading import FadeIn, FadeOut\nfrom manim.constants import DOWN, UP\nfrom manim.mobject.geometry.arc import Circle\nfrom manim.mobject.geometry.line import Line\nfrom manim.mobject.geometry.polygram import Square\n\n\ndef test_succession_timing(using_opengl_renderer):\n    \"\"\"Test timing of animations in a succession.\"\"\"\n    line = Line()\n    animation_1s = FadeIn(line, shift=UP, run_time=1.0)\n    animation_4s = FadeOut(line, shift=DOWN, run_time=4.0)\n    succession = Succession(animation_1s, animation_4s)\n    assert succession.get_run_time() == 5.0\n    succession._setup_scene(MagicMock())\n    succession.begin()\n    assert succession.active_index == 0\n    # The first animation takes 20% of the total run time.\n    succession.interpolate(0.199)\n    assert succession.active_index == 0\n    succession.interpolate(0.2)\n    assert succession.active_index == 1\n    succession.interpolate(0.8)\n    assert succession.active_index == 1\n    # At 100% and more, no animation must be active anymore.\n    succession.interpolate(1.0)\n    assert succession.active_index == 2\n    assert succession.active_animation is None\n    succession.interpolate(1.2)\n    assert succession.active_index == 2\n    assert succession.active_animation is None\n\n\ndef test_succession_in_succession_timing(using_opengl_renderer):\n    \"\"\"Test timing of nested successions.\"\"\"\n    line = Line()\n    animation_1s = FadeIn(line, shift=UP, run_time=1.0)\n    animation_4s = FadeOut(line, shift=DOWN, run_time=4.0)\n    nested_succession = Succession(animation_1s, animation_4s)\n    succession = Succession(\n        FadeIn(line, shift=UP, run_time=4.0),\n        nested_succession,\n        FadeIn(line, shift=UP, run_time=1.0),\n    )\n    assert nested_succession.get_run_time() == 5.0\n    assert succession.get_run_time() == 10.0\n    succession._setup_scene(MagicMock())\n    succession.begin()\n    succession.interpolate(0.1)\n    assert succession.active_index == 0\n    # The nested succession must not be active yet, and as a result hasn't set active_animation yet.\n    assert not hasattr(nested_succession, \"active_animation\")\n    succession.interpolate(0.39)\n    assert succession.active_index == 0\n    assert not hasattr(nested_succession, \"active_animation\")\n    # The nested succession starts at 40% of total run time\n    succession.interpolate(0.4)\n    assert succession.active_index == 1\n    assert nested_succession.active_index == 0\n    # The nested succession second animation starts at 50% of total run time.\n    succession.interpolate(0.49)\n    assert succession.active_index == 1\n    assert nested_succession.active_index == 0\n    succession.interpolate(0.5)\n    assert succession.active_index == 1\n    assert nested_succession.active_index == 1\n    # The last animation starts at 90% of total run time. The nested succession must be finished at that time.\n    succession.interpolate(0.89)\n    assert succession.active_index == 1\n    assert nested_succession.active_index == 1\n    succession.interpolate(0.9)\n    assert succession.active_index == 2\n    assert nested_succession.active_index == 2\n    assert nested_succession.active_animation is None\n    # After 100%, nothing must be playing anymore.\n    succession.interpolate(1.0)\n    assert succession.active_index == 3\n    assert succession.active_animation is None\n    assert nested_succession.active_index == 2\n    assert nested_succession.active_animation is None\n\n\ndef test_animationbuilder_in_group(using_opengl_renderer):\n    sqr = Square()\n    circ = Circle()\n    animation_group = AnimationGroup(sqr.animate.shift(DOWN).scale(2), FadeIn(circ))\n    assert all(isinstance(anim, Animation) for anim in animation_group.animations)\n    succession = Succession(sqr.animate.shift(DOWN).scale(2), FadeIn(circ))\n    assert all(isinstance(anim, Animation) for anim in succession.animations)\n\n\ndef test_animationgroup_with_wait(using_opengl_renderer):\n    sqr = Square()\n    sqr_anim = FadeIn(sqr)\n    wait = Wait()\n    animation_group = AnimationGroup(wait, sqr_anim, lag_ratio=1)\n\n    animation_group.begin()\n    timings = animation_group.anims_with_timings\n\n    assert timings.tolist() == [(wait, 0.0, 1.0), (sqr_anim, 1.0, 2.0)]\n"
  },
  {
    "path": "tests/opengl/test_config_opengl.py",
    "content": "from __future__ import annotations\n\nimport tempfile\nfrom pathlib import Path\n\nimport numpy as np\n\nfrom manim import WHITE, Scene, Square, tempconfig\n\n\ndef test_tempconfig(config, using_opengl_renderer):\n    \"\"\"Test the tempconfig context manager.\"\"\"\n    original = config.copy()\n\n    with tempconfig({\"frame_width\": 100, \"frame_height\": 42}):\n        # check that config was modified correctly\n        assert config[\"frame_width\"] == 100\n        assert config[\"frame_height\"] == 42\n\n        # check that no keys are missing and no new keys were added\n        assert set(original.keys()) == set(config.keys())\n\n    # check that the keys are still untouched\n    assert set(original.keys()) == set(config.keys())\n\n    # check that config is correctly restored\n    for k, v in original.items():\n        if isinstance(v, np.ndarray):\n            np.testing.assert_allclose(config[k], v)\n        else:\n            assert config[k] == v\n\n\nclass MyScene(Scene):\n    def construct(self):\n        self.add(Square())\n        self.wait(1)\n\n\ndef test_background_color(config, using_opengl_renderer, dry_run):\n    \"\"\"Test the 'background_color' config option.\"\"\"\n    config.background_color = WHITE\n    config.verbose = \"ERROR\"\n\n    scene = MyScene()\n    scene.render()\n    frame = scene.renderer.get_frame()\n    np.testing.assert_allclose(frame[0, 0], [255, 255, 255, 255])\n\n\ndef test_digest_file(config, using_opengl_renderer, tmp_path):\n    \"\"\"Test that a config file can be digested programmatically.\"\"\"\n    with tempfile.NamedTemporaryFile(\"w\", dir=tmp_path, delete=False) as tmp_cfg:\n        tmp_cfg.write(\n            \"\"\"\n            [CLI]\n            media_dir = this_is_my_favorite_path\n            video_dir = {media_dir}/videos\n            frame_height = 10\n            \"\"\",\n        )\n    config.digest_file(tmp_cfg.name)\n\n    assert config.get_dir(\"media_dir\") == Path(\"this_is_my_favorite_path\")\n    assert config.get_dir(\"video_dir\") == Path(\"this_is_my_favorite_path/videos\")\n\n\ndef test_frame_size(config, using_opengl_renderer, tmp_path):\n    \"\"\"Test that the frame size can be set via config file.\"\"\"\n    np.testing.assert_allclose(\n        config.aspect_ratio, config.pixel_width / config.pixel_height\n    )\n    np.testing.assert_allclose(config.frame_height, 8.0)\n\n    with tempconfig({}):\n        with tempfile.NamedTemporaryFile(\"w\", dir=tmp_path, delete=False) as tmp_cfg:\n            tmp_cfg.write(\n                \"\"\"\n                [CLI]\n                pixel_height = 10\n                pixel_width = 10\n                \"\"\",\n            )\n        config.digest_file(tmp_cfg.name)\n\n        # aspect ratio is set using pixel measurements\n        np.testing.assert_allclose(config.aspect_ratio, 1.0)\n        # if not specified in the cfg file, frame_width is set using the aspect ratio\n        np.testing.assert_allclose(config.frame_height, 8.0)\n        np.testing.assert_allclose(config.frame_width, 8.0)\n\n\ndef test_frame_size_if_frame_width(config, using_opengl_renderer, tmp_path):\n    with tempfile.NamedTemporaryFile(\"w\", dir=tmp_path, delete=False) as tmp_cfg:\n        tmp_cfg.write(\n            \"\"\"\n            [CLI]\n            pixel_height = 10\n            pixel_width = 10\n            frame_height = 10\n            frame_width = 10\n            \"\"\",\n        )\n    tmp_cfg.close()\n    config.digest_file(tmp_cfg.name)\n\n    np.testing.assert_allclose(config.aspect_ratio, 1.0)\n    # if both are specified in the cfg file, the aspect ratio is ignored\n    np.testing.assert_allclose(config.frame_height, 10.0)\n    np.testing.assert_allclose(config.frame_width, 10.0)\n\n\ndef test_temporary_dry_run(config, using_opengl_renderer):\n    \"\"\"Test that tempconfig correctly restores after setting dry_run.\"\"\"\n    assert config[\"write_to_movie\"]\n    assert not config[\"save_last_frame\"]\n\n    with tempconfig({\"dry_run\": True}):\n        assert not config[\"write_to_movie\"]\n        assert not config[\"save_last_frame\"]\n\n    assert config[\"write_to_movie\"]\n    assert not config[\"save_last_frame\"]\n\n\ndef test_dry_run_with_png_format(config, using_opengl_renderer, dry_run):\n    \"\"\"Test that there are no exceptions when running a png without output\"\"\"\n    config.disable_caching = True\n    assert config[\"dry_run\"] is True\n    scene = MyScene()\n    scene.render()\n\n\ndef test_dry_run_with_png_format_skipped_animations(\n    config, using_opengl_renderer, dry_run\n):\n    \"\"\"Test that there are no exceptions when running a png without output and skipped animations\"\"\"\n    config.write_to_movie = False\n    config.disable_caching = True\n    assert config[\"dry_run\"] is True\n    scene = MyScene(skip_animations=True)\n    scene.render()\n"
  },
  {
    "path": "tests/opengl/test_coordinate_system_opengl.py",
    "content": "from __future__ import annotations\n\nimport math\n\nimport numpy as np\nimport pytest\n\nfrom manim import (\n    LEFT,\n    ORIGIN,\n    PI,\n    UR,\n    Axes,\n    Circle,\n    ComplexPlane,\n    NumberPlane,\n    PolarPlane,\n    ThreeDAxes,\n    config,\n    tempconfig,\n)\nfrom manim import CoordinateSystem as CS\nfrom manim.utils.color import BLUE, GREEN, ORANGE, PURE_YELLOW, RED\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"coordinate_system_opengl\"\n\n\ndef test_initial_config(using_opengl_renderer):\n    \"\"\"Check that all attributes are defined properly from the config.\"\"\"\n    cs = CS()\n    assert cs.x_range[0] == round(-config[\"frame_x_radius\"])\n    assert cs.x_range[1] == round(config[\"frame_x_radius\"])\n    assert cs.x_range[2] == 1.0\n    assert cs.y_range[0] == round(-config[\"frame_y_radius\"])\n    assert cs.y_range[1] == round(config[\"frame_y_radius\"])\n    assert cs.y_range[2] == 1.0\n\n    ax = Axes()\n    np.testing.assert_allclose(ax.get_center(), ORIGIN)\n    np.testing.assert_allclose(ax.y_axis_config[\"label_direction\"], LEFT)\n\n    with tempconfig({\"frame_x_radius\": 100, \"frame_y_radius\": 200}):\n        cs = CS()\n        assert cs.x_range[0] == -100\n        assert cs.x_range[1] == 100\n        assert cs.y_range[0] == -200\n        assert cs.y_range[1] == 200\n\n\ndef test_dimension(using_opengl_renderer):\n    \"\"\"Check that objects have the correct dimension.\"\"\"\n    assert Axes().dimension == 2\n    assert NumberPlane().dimension == 2\n    assert PolarPlane().dimension == 2\n    assert ComplexPlane().dimension == 2\n    assert ThreeDAxes().dimension == 3\n\n\ndef test_abstract_base_class(using_opengl_renderer):\n    \"\"\"Check that CoordinateSystem has some abstract methods.\"\"\"\n    with pytest.raises(NotImplementedError):\n        CS().get_axes()\n\n\n@pytest.mark.skip(\n    reason=\"Causes conflicts with other tests due to axis_config changing default config\",\n)\ndef test_NumberPlane(using_opengl_renderer):\n    \"\"\"Test that NumberPlane generates the correct number of lines when its ranges do not cross 0.\"\"\"\n    pos_x_range = (0, 7)\n    neg_x_range = (-7, 0)\n\n    pos_y_range = (2, 6)\n    neg_y_range = (-6, -2)\n\n    x_vals = [0, 1.5, 2, 2.8, 4, 6.25]\n    y_vals = [2, 5, 4.25, 6, 4.5, 2.75]\n\n    testing_data = [\n        (pos_x_range, pos_y_range, x_vals, y_vals),\n        (pos_x_range, neg_y_range, x_vals, [-v for v in y_vals]),\n        (neg_x_range, pos_y_range, [-v for v in x_vals], y_vals),\n        (neg_x_range, neg_y_range, [-v for v in x_vals], [-v for v in y_vals]),\n    ]\n\n    for test_data in testing_data:\n        x_range, y_range, x_vals, y_vals = test_data\n\n        x_start, x_end = x_range\n        y_start, y_end = y_range\n\n        plane = NumberPlane(\n            x_range=x_range,\n            y_range=y_range,\n            # x_length = 7,\n            axis_config={\"include_numbers\": True},\n        )\n\n        # normally these values would be need to be added by one to pass since there's an\n        # overlapping pair of lines at the origin, but since these planes do not cross 0,\n        # this is not needed.\n        num_y_lines = math.ceil(x_end - x_start)\n        num_x_lines = math.floor(y_end - y_start)\n\n        assert len(plane.y_lines) == num_y_lines\n        assert len(plane.x_lines) == num_x_lines\n\n    plane = NumberPlane((-5, 5, 0.5), (-8, 8, 2))  # <- test for different step values\n    assert len(plane.x_lines) == 8\n    assert len(plane.y_lines) == 20\n\n\ndef test_point_to_coords(using_opengl_renderer):\n    ax = Axes(x_range=[0, 10, 2])\n    circ = Circle(radius=0.5).shift(UR * 2)\n\n    # get the coordinates of the circle with respect to the axes\n    coords = np.around(ax.point_to_coords(circ.get_right()), decimals=4)\n    np.testing.assert_array_equal(coords, (7.0833, 2.6667))\n\n\ndef test_coords_to_point(using_opengl_renderer):\n    ax = Axes()\n\n    # a point with respect to the axes\n    c2p_coord = np.around(ax.coords_to_point(2, 2), decimals=4)\n    np.testing.assert_array_equal(c2p_coord, (1.7143, 1.5, 0))\n\n\ndef test_input_to_graph_point(using_opengl_renderer):\n    ax = Axes()\n    curve = ax.plot(lambda x: np.cos(x))\n    line_graph = ax.plot_line_graph([1, 3, 5], [-1, 2, -2], add_vertex_dots=False)[\n        \"line_graph\"\n    ]\n\n    # move a square to PI on the cosine curve.\n    position = np.around(ax.input_to_graph_point(x=PI, graph=curve), decimals=4)\n    np.testing.assert_array_equal(position, (2.6928, -0.75, 0))\n\n    # test the line_graph implementation\n    position = np.around(ax.input_to_graph_point(x=PI, graph=line_graph), decimals=4)\n    np.testing.assert_array_equal(position, (2.6928, 1.2876, 0))\n\n\n@frames_comparison\ndef test_gradient_line_graph_x_axis(scene, using_opengl_renderer):\n    \"\"\"Test that using `colorscale` generates a line whose gradient matches the y-axis\"\"\"\n    axes = Axes(x_range=[-3, 3], y_range=[-3, 3])\n\n    curve = axes.plot(\n        lambda x: 0.1 * x**3,\n        x_range=(-3, 3, 0.001),\n        colorscale=[BLUE, GREEN, PURE_YELLOW, ORANGE, RED],\n        colorscale_axis=0,\n    )\n\n    scene.add(axes, curve)\n\n\n@frames_comparison\ndef test_gradient_line_graph_y_axis(scene, using_opengl_renderer):\n    \"\"\"Test that using `colorscale` generates a line whose gradient matches the y-axis\"\"\"\n    axes = Axes(x_range=[-3, 3], y_range=[-3, 3])\n\n    curve = axes.plot(\n        lambda x: 0.1 * x**3,\n        x_range=(-3, 3, 0.001),\n        colorscale=[BLUE, GREEN, PURE_YELLOW, ORANGE, RED],\n        colorscale_axis=1,\n    )\n\n    scene.add(axes, curve)\n"
  },
  {
    "path": "tests/opengl/test_copy_opengl.py",
    "content": "from __future__ import annotations\n\nfrom pathlib import Path\n\nfrom manim import BraceLabel\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\n\n\ndef test_opengl_mobject_copy(using_opengl_renderer):\n    \"\"\"Test that a copy is a deepcopy.\"\"\"\n    orig = OpenGLMobject()\n    orig.add(*(OpenGLMobject() for _ in range(10)))\n    copy = orig.copy()\n\n    assert orig is orig\n    assert orig is not copy\n    assert orig.submobjects is not copy.submobjects\n    for i in range(10):\n        assert orig.submobjects[i] is not copy.submobjects[i]\n\n\ndef test_bracelabel_copy(config, using_opengl_renderer, tmp_path):\n    \"\"\"Test that a copy is a deepcopy.\"\"\"\n    # For this test to work, we need to tweak some folders temporarily\n    original_text_dir = config[\"text_dir\"]\n    original_tex_dir = config[\"tex_dir\"]\n    mediadir = Path(tmp_path) / \"deepcopy\"\n    config[\"text_dir\"] = str(mediadir.joinpath(\"Text\"))\n    config[\"tex_dir\"] = str(mediadir.joinpath(\"Tex\"))\n    for el in [\"text_dir\", \"tex_dir\"]:\n        Path(config[el]).mkdir(parents=True, exist_ok=True)\n\n    # Before the refactoring of OpenGLMobject.copy(), the class BraceLabel was the\n    # only one to have a non-trivial definition of copy.  Here we test that it\n    # still works after the refactoring.\n    orig = BraceLabel(OpenGLMobject(), \"label\")\n    copy = orig.copy()\n\n    assert orig is orig\n    assert orig is not copy\n    assert orig.brace is not copy.brace\n    assert orig.label is not copy.label\n    assert orig.submobjects is not copy.submobjects\n    assert orig.submobjects[0] is orig.brace\n    assert copy.submobjects[0] is copy.brace\n    assert orig.submobjects[0] is not copy.brace\n    assert copy.submobjects[0] is not orig.brace\n\n    # Restore the original folders\n    config[\"text_dir\"] = original_text_dir\n    config[\"tex_dir\"] = original_tex_dir\n"
  },
  {
    "path": "tests/opengl/test_family_opengl.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim import RIGHT, Circle\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\n\n\ndef test_family(using_opengl_renderer):\n    \"\"\"Check that the family is gathered correctly.\"\"\"\n    # Check that an empty OpenGLMobject's family only contains itself\n    mob = OpenGLMobject()\n    assert mob.get_family() == [mob]\n\n    # Check that all children are in the family\n    mob = OpenGLMobject()\n    children = [OpenGLMobject() for _ in range(10)]\n    mob.add(*children)\n    family = mob.get_family()\n    assert len(family) == 1 + 10\n    assert mob in family\n    for c in children:\n        assert c in family\n\n    # Nested children should be in the family\n    mob = OpenGLMobject()\n    grandchildren = {}\n    for _ in range(10):\n        child = OpenGLMobject()\n        grandchildren[child] = [OpenGLMobject() for _ in range(10)]\n        child.add(*grandchildren[child])\n    mob.add(*list(grandchildren.keys()))\n    family = mob.get_family()\n    assert len(family) == 1 + 10 + 10 * 10\n    assert mob in family\n    for c in grandchildren:\n        assert c in family\n        for gc in grandchildren[c]:\n            assert gc in family\n\n\ndef test_overlapping_family(using_opengl_renderer):\n    \"\"\"Check that each member of the family is only gathered once.\"\"\"\n    (\n        mob,\n        child1,\n        child2,\n    ) = (\n        OpenGLMobject(),\n        OpenGLMobject(),\n        OpenGLMobject(),\n    )\n    gchild1, gchild2, gchild_common = OpenGLMobject(), OpenGLMobject(), OpenGLMobject()\n    child1.add(gchild1, gchild_common)\n    child2.add(gchild2, gchild_common)\n    mob.add(child1, child2)\n    family = mob.get_family()\n    assert mob in family\n    assert len(family) == 6\n    assert family.count(gchild_common) == 1\n\n\ndef test_shift_family(using_opengl_renderer):\n    \"\"\"Check that each member of the family is shifted along with the parent.\n\n    Importantly, here we add a common grandchild to each of the children.  So\n    this test will fail if the grandchild moves twice as much as it should.\n\n    \"\"\"\n    # Note shift() needs the OpenGLMobject to have a non-empty `points` attribute, so\n    # we cannot use a plain OpenGLMobject or OpenGLVMobject.  We use Circle instead.\n    (\n        mob,\n        child1,\n        child2,\n    ) = (\n        Circle(),\n        Circle(),\n        Circle(),\n    )\n    gchild1, gchild2, gchild_common = Circle(), Circle(), Circle()\n\n    child1.add(gchild1, gchild_common)\n    child2.add(gchild2, gchild_common)\n    mob.add(child1, child2)\n    family = mob.get_family()\n\n    positions_before = {m: m.get_center().copy() for m in family}\n    mob.shift(RIGHT)\n    positions_after = {m: m.get_center().copy() for m in family}\n\n    for m in family:\n        np.testing.assert_allclose(positions_before[m] + RIGHT, positions_after[m])\n"
  },
  {
    "path": "tests/opengl/test_graph_opengl.py",
    "content": "from __future__ import annotations\n\nfrom manim import Dot, Graph, Line, Text\n\n\ndef test_graph_creation(using_opengl_renderer):\n    vertices = [1, 2, 3, 4]\n    edges = [(1, 2), (2, 3), (3, 4), (4, 1)]\n    layout = {1: [0, 0, 0], 2: [1, 1, 0], 3: [1, -1, 0], 4: [-1, 0, 0]}\n    G_manual = Graph(vertices=vertices, edges=edges, layout=layout)\n    assert len(G_manual.vertices) == 4\n    assert len(G_manual.edges) == 4\n    G_spring = Graph(vertices=vertices, edges=edges)\n    assert len(G_spring.vertices) == 4\n    assert len(G_spring.edges) == 4\n\n\ndef test_graph_add_vertices(using_opengl_renderer):\n    G = Graph([1, 2, 3], [(1, 2), (2, 3)])\n    G.add_vertices(4)\n    assert len(G.vertices) == 4\n    assert len(G.edges) == 2\n    G.add_vertices(5, labels={5: Text(\"5\")})\n    assert len(G.vertices) == 5\n    assert len(G.edges) == 2\n    assert 5 in G._labels\n    assert 5 in G._vertex_config\n    G.add_vertices(6, 7, 8)\n    assert len(G.vertices) == 8\n    assert len(G._graph.nodes()) == 8\n\n\ndef test_graph_remove_vertices(using_opengl_renderer):\n    G = Graph([1, 2, 3, 4, 5], [(1, 2), (2, 3), (3, 4), (4, 5)])\n    removed_mobjects = G.remove_vertices(3)\n    assert len(removed_mobjects) == 3\n    assert len(G.vertices) == 4\n    assert len(G.edges) == 2\n    assert list(G.vertices.keys()) == [1, 2, 4, 5]\n    assert list(G.edges.keys()) == [(1, 2), (4, 5)]\n    removed_mobjects = G.remove_vertices(4, 5)\n    assert len(removed_mobjects) == 3\n    assert len(G.vertices) == 2\n    assert len(G.edges) == 1\n    assert list(G.vertices.keys()) == [1, 2]\n    assert list(G.edges.keys()) == [(1, 2)]\n\n\ndef test_graph_add_edges(using_opengl_renderer):\n    G = Graph([1, 2, 3, 4, 5], [(1, 2), (2, 3)])\n    added_mobjects = G.add_edges((1, 3))\n    assert isinstance(added_mobjects.submobjects[0], Line)\n    assert len(G.vertices) == 5\n    assert len(G.edges) == 3\n    assert set(G.vertices.keys()) == {1, 2, 3, 4, 5}\n    assert set(G.edges.keys()) == {(1, 2), (2, 3), (1, 3)}\n\n    added_mobjects = G.add_edges((1, 42))\n    removed_mobjects = added_mobjects.submobjects\n    assert isinstance(removed_mobjects[0], Dot)\n    assert isinstance(removed_mobjects[1], Line)\n\n    assert len(G.vertices) == 6\n    assert len(G.edges) == 4\n    assert set(G.vertices.keys()) == {1, 2, 3, 4, 5, 42}\n    assert set(G.edges.keys()) == {(1, 2), (2, 3), (1, 3), (1, 42)}\n\n    added_mobjects = G.add_edges((4, 5), (5, 6), (6, 7))\n    assert len(added_mobjects) == 5\n    assert len(G.vertices) == 8\n    assert len(G.edges) == 7\n    assert set(G.vertices.keys()) == {1, 2, 3, 4, 5, 42, 6, 7}\n    assert set(G._graph.nodes()) == set(G.vertices.keys())\n    assert set(G.edges.keys()) == {\n        (1, 2),\n        (2, 3),\n        (1, 3),\n        (1, 42),\n        (4, 5),\n        (5, 6),\n        (6, 7),\n    }\n    assert set(G._graph.edges()) == set(G.edges.keys())\n\n\ndef test_graph_remove_edges(using_opengl_renderer):\n    G = Graph([1, 2, 3, 4, 5], [(1, 2), (2, 3), (3, 4), (4, 5), (1, 5)])\n    removed_mobjects = G.remove_edges((1, 2))\n    assert isinstance(removed_mobjects.submobjects[0], Line)\n    assert len(G.vertices) == 5\n    assert len(G.edges) == 4\n    assert set(G.edges.keys()) == {(2, 3), (3, 4), (4, 5), (1, 5)}\n    assert set(G._graph.edges()) == set(G.edges.keys())\n\n    removed_mobjects = G.remove_edges((2, 3), (3, 4), (4, 5), (1, 5))\n    assert len(removed_mobjects) == 4\n    assert len(G.vertices) == 5\n    assert len(G.edges) == 0\n    assert set(G._graph.edges()) == set()\n    assert set(G.edges.keys()) == set()\n"
  },
  {
    "path": "tests/opengl/test_ipython_magic_opengl.py",
    "content": "from __future__ import annotations\n\nimport re\n\nfrom manim.utils.ipython_magic import _generate_file_name\n\n\ndef test_jupyter_file_naming(config, using_opengl_renderer):\n    \"\"\"Check the format of file names for jupyter\"\"\"\n    scene_name = \"SimpleScene\"\n    expected_pattern = r\"[0-9a-zA-Z_]+[@_-]\\d\\d\\d\\d-\\d\\d-\\d\\d[@_-]\\d\\d-\\d\\d-\\d\\d\"\n    config.scene_names = [scene_name]\n    file_name = _generate_file_name()\n    match = re.match(expected_pattern, file_name)\n    assert scene_name in file_name, (\n        \"Expected file to contain \" + scene_name + \" but got \" + file_name\n    )\n    assert match, \"file name does not match expected pattern \" + expected_pattern\n\n\ndef test_jupyter_file_output(tmp_path, config, using_opengl_renderer):\n    \"\"\"Check the jupyter file naming is valid and can be created\"\"\"\n    scene_name = \"SimpleScene\"\n    config.scene_names = [scene_name]\n    file_name = _generate_file_name()\n    actual_path = tmp_path.with_name(file_name)\n    with actual_path.open(\"w\") as outfile:\n        outfile.write(\"\")\n        assert actual_path.exists()\n        assert actual_path.is_file()\n"
  },
  {
    "path": "tests/opengl/test_markup_opengl.py",
    "content": "from __future__ import annotations\n\nfrom manim import MarkupText\n\n\ndef test_good_markup(using_opengl_renderer):\n    \"\"\"Test creation of valid :class:`MarkupText` object\"\"\"\n    try:\n        MarkupText(\"<b>foo</b>\")\n        MarkupText(\"foo\")\n        success = True\n    except ValueError:\n        success = False\n    assert success, \"'<b>foo</b>' and 'foo' should not fail validation\"\n\n\ndef test_special_tags_markup(using_opengl_renderer):\n    \"\"\"Test creation of valid :class:`MarkupText` object with unofficial tags\"\"\"\n    try:\n        MarkupText('<color col=\"RED\">foo</color>')\n        MarkupText('<gradient from=\"RED\" to=\"YELLOW\">foo</gradient>')\n        success = True\n    except ValueError:\n        success = False\n    assert success, (\n        '\\'<color col=\"RED\">foo</color>\\' and \\'<gradient from=\"RED\" to=\"YELLOW\">foo</gradient>\\' should not fail validation'\n    )\n\n\ndef test_unbalanced_tag_markup(using_opengl_renderer):\n    \"\"\"Test creation of invalid :class:`MarkupText` object (unbalanced tag)\"\"\"\n    try:\n        MarkupText(\"<b>foo\")\n        success = False\n    except ValueError:\n        success = True\n    assert success, \"'<b>foo' should fail validation\"\n\n\ndef test_invalid_tag_markup(using_opengl_renderer):\n    \"\"\"Test creation of invalid :class:`MarkupText` object (invalid tag)\"\"\"\n    try:\n        MarkupText(\"<invalidtag>foo</invalidtag>\")\n        success = False\n    except ValueError:\n        success = True\n\n    assert success, \"'<invalidtag>foo</invalidtag>' should fail validation\"\n"
  },
  {
    "path": "tests/opengl/test_number_line_opengl.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim import NumberLine\nfrom manim.mobject.text.numbers import Integer\n\n\ndef test_unit_vector():\n    \"\"\"Check if the magnitude of unit vector along\n    the NumberLine is equal to its unit_size.\n    \"\"\"\n    axis1 = NumberLine(unit_size=0.4)\n    axis2 = NumberLine(x_range=[-2, 5], length=12)\n    for axis in (axis1, axis2):\n        assert np.linalg.norm(axis.get_unit_vector()) == axis.unit_size\n\n\ndef test_decimal_determined_by_step():\n    \"\"\"Checks that step size is considered when determining the number of decimal\n    places.\n    \"\"\"\n    axis = NumberLine(x_range=[-2, 2, 0.5])\n    expected_decimal_places = 1\n    actual_decimal_places = axis.decimal_number_config[\"num_decimal_places\"]\n    assert actual_decimal_places == expected_decimal_places, (\n        \"Expected 1 decimal place but got \" + actual_decimal_places\n    )\n\n    axis2 = NumberLine(x_range=[-1, 1, 0.25])\n    expected_decimal_places = 2\n    actual_decimal_places = axis2.decimal_number_config[\"num_decimal_places\"]\n    assert actual_decimal_places == expected_decimal_places, (\n        \"Expected 1 decimal place but got \" + actual_decimal_places\n    )\n\n\ndef test_decimal_config_overrides_defaults():\n    \"\"\"Checks that ``num_decimal_places`` is determined by step size and gets overridden by ``decimal_number_config``.\"\"\"\n    axis = NumberLine(\n        x_range=[-2, 2, 0.5],\n        decimal_number_config={\"num_decimal_places\": 0},\n    )\n    expected_decimal_places = 0\n    actual_decimal_places = axis.decimal_number_config[\"num_decimal_places\"]\n    assert actual_decimal_places == expected_decimal_places, (\n        \"Expected 1 decimal place but got \" + actual_decimal_places\n    )\n\n\ndef test_whole_numbers_step_size_default_to_0_decimal_places():\n    \"\"\"Checks that ``num_decimal_places`` defaults to 0 when a whole number step size is passed.\"\"\"\n    axis = NumberLine(x_range=[-2, 2, 1])\n    expected_decimal_places = 0\n    actual_decimal_places = axis.decimal_number_config[\"num_decimal_places\"]\n    assert actual_decimal_places == expected_decimal_places, (\n        \"Expected 1 decimal place but got \" + actual_decimal_places\n    )\n\n\ndef test_add_labels():\n    expected_label_length = 6\n    num_line = NumberLine(x_range=[-4, 4])\n    num_line.add_labels(\n        dict(zip(list(range(-3, 3)), [Integer(m) for m in range(-1, 5)], strict=True)),\n    )\n    actual_label_length = len(num_line.labels)\n    assert actual_label_length == expected_label_length, (\n        f\"Expected a VGroup with {expected_label_length} integers but got {actual_label_length}.\"\n    )\n"
  },
  {
    "path": "tests/opengl/test_numbers_opengl.py",
    "content": "from __future__ import annotations\n\nfrom manim.mobject.text.numbers import DecimalNumber\n\n\ndef test_font_size():\n    \"\"\"Test that DecimalNumber returns the correct font_size value\n    after being scaled.\n    \"\"\"\n    num = DecimalNumber(0).scale(0.3)\n\n    assert round(num.font_size, 5) == 14.4\n\n\ndef test_font_size_vs_scale():\n    \"\"\"Test that scale produces the same results as .scale()\"\"\"\n    num = DecimalNumber(0, font_size=12)\n    num_scale = DecimalNumber(0).scale(1 / 4)\n\n    assert num.height == num_scale.height\n\n\ndef test_changing_font_size():\n    \"\"\"Test that the font_size property properly scales DecimalNumber.\"\"\"\n    num = DecimalNumber(0, font_size=12)\n    num.font_size = 48\n\n    assert num.height == DecimalNumber(0, font_size=48).height\n\n\ndef test_set_value_size():\n    \"\"\"Test that the size of DecimalNumber after set_value is correct.\"\"\"\n    num = DecimalNumber(0).scale(0.3)\n    test_num = num.copy()\n    num.set_value(0)\n\n    # round because the height is off by 1e-17\n    assert round(num.height, 12) == round(test_num.height, 12)\n"
  },
  {
    "path": "tests/opengl/test_opengl_mobject.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport pytest\n\nfrom manim import PI\nfrom manim.mobject.opengl.opengl_geometry import OpenGLTriangle\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\n\n\ndef test_opengl_mobject_add(using_opengl_renderer):\n    \"\"\"Test OpenGLMobject.add().\"\"\"\n    \"\"\"Call this function with a Container instance to test its add() method.\"\"\"\n    # check that obj.submobjects is updated correctly\n    obj = OpenGLMobject()\n    assert len(obj.submobjects) == 0\n    obj.add(OpenGLMobject())\n    assert len(obj.submobjects) == 1\n    obj.add(*(OpenGLMobject() for _ in range(10)))\n    assert len(obj.submobjects) == 11\n\n    # check that adding a OpenGLMobject twice does not actually add it twice\n    repeated = OpenGLMobject()\n    obj.add(repeated)\n    assert len(obj.submobjects) == 12\n    obj.add(repeated)\n    assert len(obj.submobjects) == 12\n\n    # check that OpenGLMobject.add() returns the OpenGLMobject (for chained calls)\n    assert obj.add(OpenGLMobject()) is obj\n    assert len(obj.submobjects) == 13\n\n    obj = OpenGLMobject()\n\n    # an OpenGLMobject cannot contain itself\n    with pytest.raises(ValueError) as add_self_info:\n        obj.add(OpenGLMobject(), obj, OpenGLMobject())\n    assert str(add_self_info.value) == (\n        \"Cannot add OpenGLMobject as a submobject of itself (at index 1).\"\n    )\n    assert len(obj.submobjects) == 0\n\n    # can only add Mobjects\n    with pytest.raises(TypeError) as add_str_info:\n        obj.add(OpenGLMobject(), OpenGLMobject(), \"foo\")\n    assert str(add_str_info.value) == (\n        \"Only values of type OpenGLMobject can be added as submobjects of \"\n        \"OpenGLMobject, but the value foo (at index 2) is of type str.\"\n    )\n    assert len(obj.submobjects) == 0\n\n\ndef test_opengl_mobject_remove(using_opengl_renderer):\n    \"\"\"Test OpenGLMobject.remove().\"\"\"\n    obj = OpenGLMobject()\n    to_remove = OpenGLMobject()\n    obj.add(to_remove)\n    obj.add(*(OpenGLMobject() for _ in range(10)))\n    assert len(obj.submobjects) == 11\n    obj.remove(to_remove)\n    assert len(obj.submobjects) == 10\n    obj.remove(to_remove)\n    assert len(obj.submobjects) == 10\n\n    assert obj.remove(OpenGLMobject()) is obj\n\n\ndef test_opengl_rotate_about_vertex_view(using_opengl_renderer):\n    \"\"\"Test that rotating about a vertex obtained from get_vertices() works correctly.\n\n    This is a regression test for an issue in the non-OpenGL (Cairo) renderer where\n    get_vertices() returns a view of the points array, and using it as about_point\n    in rotate() would cause the view to be mutated. The OpenGL renderer was not affected\n    by this bug due to its different implementation (using `arr - about_point` which\n    creates a temporary array rather than `arr -= about_point` which mutates in-place).\n\n    This test verifies that the OpenGL renderer continues to handle vertex views correctly.\n    \"\"\"\n    triangle = OpenGLTriangle()\n    original_vertices = triangle.get_vertices().copy()\n    first_vertex = original_vertices[0].copy()\n\n    # This should rotate about the first vertex without corrupting it\n    triangle.rotate(PI / 2, about_point=triangle.get_vertices()[0])\n\n    # The first vertex should remain in the same position (within numerical precision)\n    rotated_vertices = triangle.get_vertices()\n    np.testing.assert_allclose(rotated_vertices[0], first_vertex, atol=1e-6)\n"
  },
  {
    "path": "tests/opengl/test_opengl_surface.py",
    "content": "import numpy as np\n\nfrom manim.mobject.opengl.opengl_surface import OpenGLSurface\nfrom manim.mobject.opengl.opengl_three_dimensions import OpenGLSurfaceMesh\n\n\ndef test_surface_initialization(using_opengl_renderer):\n    surface = OpenGLSurface(\n        lambda u, v: (u, v, u * np.sin(v) + v * np.cos(u)),\n        u_range=(-3, 3),\n        v_range=(-3, 3),\n    )\n\n    mesh = OpenGLSurfaceMesh(surface)\n"
  },
  {
    "path": "tests/opengl/test_opengl_vectorized_mobject.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\nimport pytest\n\nfrom manim import Circle, Line, Square, VDict, VGroup, VMobject\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject\n\n\ndef test_opengl_vmobject_add(using_opengl_renderer):\n    \"\"\"Test the OpenGLVMobject add method.\"\"\"\n    obj = OpenGLVMobject()\n    assert len(obj.submobjects) == 0\n\n    obj.add(OpenGLVMobject())\n    assert len(obj.submobjects) == 1\n\n    # Can't add non-OpenGLVMobject values to a VMobject.\n    with pytest.raises(TypeError) as add_int_info:\n        obj.add(3)\n    assert str(add_int_info.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of \"\n        \"OpenGLVMobject, but the value 3 (at index 0) is of type int.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    # Plain OpenGLMobjects can't be added to a OpenGLVMobject if they're not\n    # OpenGLVMobjects. Suggest adding them into an OpenGLGroup instead.\n    with pytest.raises(TypeError) as add_mob_info:\n        obj.add(OpenGLMobject())\n    assert str(add_mob_info.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of \"\n        \"OpenGLVMobject, but the value OpenGLMobject (at index 0) is of type \"\n        \"OpenGLMobject. You can try adding this value into a Group instead.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    with pytest.raises(TypeError) as add_vmob_and_mob_info:\n        # If only one of the added objects is not an instance of VMobject, none of them should be added\n        obj.add(OpenGLVMobject(), OpenGLMobject())\n    assert str(add_vmob_and_mob_info.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of \"\n        \"OpenGLVMobject, but the value OpenGLMobject (at index 1) is of type \"\n        \"OpenGLMobject. You can try adding this value into a Group instead.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    # A VMobject or VGroup cannot contain itself.\n    with pytest.raises(ValueError) as add_self_info:\n        obj.add(obj)\n    assert str(add_self_info.value) == (\n        \"Cannot add OpenGLVMobject as a submobject of itself (at index 0).\"\n    )\n    assert len(obj.submobjects) == 1\n\n\ndef test_opengl_vmobject_point_from_proportion(using_opengl_renderer):\n    obj = OpenGLVMobject()\n\n    # One long line, one short line\n    obj.set_points_as_corners(\n        [\n            np.array([0, 0, 0]),\n            np.array([4, 0, 0]),\n            np.array([4, 2, 0]),\n        ],\n    )\n\n    # Total length of 6, so halfway along the object\n    # would be at length 3, which lands in the first, long line.\n    np.testing.assert_array_equal(obj.point_from_proportion(0.5), np.array([3, 0, 0]))\n\n    with pytest.raises(ValueError, match=\"between 0 and 1\"):\n        obj.point_from_proportion(2)\n\n    obj.clear_points()\n    with pytest.raises(Exception, match=\"with no points\"):\n        obj.point_from_proportion(0)\n\n\ndef test_vgroup_init(using_opengl_renderer):\n    \"\"\"Test the VGroup instantiation.\"\"\"\n    VGroup()\n    VGroup(OpenGLVMobject())\n    VGroup(OpenGLVMobject(), OpenGLVMobject())\n\n    # A VGroup cannot contain non-VMobject values.\n    with pytest.raises(TypeError) as init_with_float_info:\n        VGroup(3.0)\n    assert str(init_with_float_info.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of \"\n        \"VGroup, but the value 3.0 (at index 0 of parameter 0) is of type float.\"\n    )\n\n    with pytest.raises(TypeError) as init_with_mob_info:\n        VGroup(OpenGLMobject())\n    assert str(init_with_mob_info.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of \"\n        \"VGroup, but the value OpenGLMobject (at index 0 of parameter 0) is of type \"\n        \"OpenGLMobject. You can try adding this value into a Group instead.\"\n    )\n\n    with pytest.raises(TypeError) as init_with_vmob_and_mob_info:\n        VGroup(OpenGLVMobject(), OpenGLMobject())\n    assert str(init_with_vmob_and_mob_info.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of \"\n        \"VGroup, but the value OpenGLMobject (at index 0 of parameter 1) is of type \"\n        \"OpenGLMobject. You can try adding this value into a Group instead.\"\n    )\n\n\ndef test_vgroup_init_with_iterable(using_opengl_renderer):\n    \"\"\"Test VGroup instantiation with an iterable type.\"\"\"\n\n    def type_generator(type_to_generate, n):\n        return (type_to_generate() for _ in range(n))\n\n    def mixed_type_generator(major_type, minor_type, minor_type_positions, n):\n        return (\n            minor_type() if i in minor_type_positions else major_type()\n            for i in range(n)\n        )\n\n    obj = VGroup(OpenGLVMobject())\n    assert len(obj.submobjects) == 1\n\n    obj = VGroup(type_generator(OpenGLVMobject, 38))\n    assert len(obj.submobjects) == 38\n\n    obj = VGroup(\n        OpenGLVMobject(),\n        [OpenGLVMobject(), OpenGLVMobject()],\n        type_generator(OpenGLVMobject, 38),\n    )\n    assert len(obj.submobjects) == 41\n\n    # A VGroup cannot be initialised with an iterable containing a OpenGLMobject\n    with pytest.raises(TypeError) as init_with_mob_iterable:\n        VGroup(type_generator(OpenGLMobject, 5))\n    assert str(init_with_mob_iterable.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of VGroup, \"\n        \"but the value OpenGLMobject (at index 0 of parameter 0) is of type OpenGLMobject.\"\n    )\n\n    # A VGroup cannot be initialised with an iterable containing a OpenGLMobject in any position\n    with pytest.raises(TypeError) as init_with_mobs_and_vmobs_iterable:\n        VGroup(mixed_type_generator(OpenGLVMobject, OpenGLMobject, [3, 5], 7))\n    assert str(init_with_mobs_and_vmobs_iterable.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of VGroup, \"\n        \"but the value OpenGLMobject (at index 3 of parameter 0) is of type OpenGLMobject.\"\n    )\n\n    # A VGroup cannot be initialised with an iterable containing non OpenGLVMobject's in any position\n    with pytest.raises(TypeError) as init_with_float_and_vmobs_iterable:\n        VGroup(mixed_type_generator(OpenGLVMobject, float, [6, 7], 9))\n    assert str(init_with_float_and_vmobs_iterable.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of VGroup, \"\n        \"but the value 0.0 (at index 6 of parameter 0) is of type float.\"\n    )\n\n    # A VGroup cannot be initialised with an iterable containing both OpenGLVMobject's and VMobject's\n    with pytest.raises(TypeError) as init_with_mobs_and_vmobs_iterable:\n        VGroup(mixed_type_generator(OpenGLVMobject, VMobject, [3, 5], 7))\n    assert str(init_with_mobs_and_vmobs_iterable.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of VGroup, \"\n        \"but the value VMobject (at index 3 of parameter 0) is of type VMobject.\"\n    )\n\n\ndef test_vgroup_add(using_opengl_renderer):\n    \"\"\"Test the VGroup add method.\"\"\"\n    obj = VGroup()\n    assert len(obj.submobjects) == 0\n\n    obj.add(OpenGLVMobject())\n    assert len(obj.submobjects) == 1\n\n    # Can't add non-OpenGLVMobject values to a VMobject.\n    with pytest.raises(TypeError) as add_int_info:\n        obj.add(3)\n    assert str(add_int_info.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of \"\n        \"VGroup, but the value 3 (at index 0 of parameter 0) is of type int.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    # Plain OpenGLMobjects can't be added to a OpenGLVMobject if they're not\n    # OpenGLVMobjects. Suggest adding them into an OpenGLGroup instead.\n    with pytest.raises(TypeError) as add_mob_info:\n        obj.add(OpenGLMobject())\n    assert str(add_mob_info.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of \"\n        \"VGroup, but the value OpenGLMobject (at index 0 of parameter 0) is of type \"\n        \"OpenGLMobject. You can try adding this value into a Group instead.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    with pytest.raises(TypeError) as add_vmob_and_mob_info:\n        # If only one of the added objects is not an instance of VMobject, none of them should be added\n        obj.add(OpenGLVMobject(), OpenGLMobject())\n    assert str(add_vmob_and_mob_info.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of \"\n        \"VGroup, but the value OpenGLMobject (at index 0 of parameter 1) is of type \"\n        \"OpenGLMobject. You can try adding this value into a Group instead.\"\n    )\n    assert len(obj.submobjects) == 1\n\n    # A VMobject or VGroup cannot contain itself.\n    with pytest.raises(ValueError) as add_self_info:\n        obj.add(obj)\n    assert str(add_self_info.value) == (\n        \"Cannot add VGroup as a submobject of itself (at index 0).\"\n    )\n    assert len(obj.submobjects) == 1\n\n\ndef test_vgroup_add_dunder(using_opengl_renderer):\n    \"\"\"Test the VGroup __add__ magic method.\"\"\"\n    obj = VGroup()\n    assert len(obj.submobjects) == 0\n    obj + OpenGLVMobject()\n    assert len(obj.submobjects) == 0\n    obj += OpenGLVMobject()\n    assert len(obj.submobjects) == 1\n    with pytest.raises(TypeError):\n        obj += OpenGLMobject()\n    assert len(obj.submobjects) == 1\n    with pytest.raises(TypeError):\n        # If only one of the added object is not an instance of OpenGLVMobject, none of them should be added\n        obj += (OpenGLVMobject(), OpenGLMobject())\n    assert len(obj.submobjects) == 1\n    with pytest.raises(ValueError):\n        # a OpenGLMobject cannot contain itself\n        obj += obj\n\n\ndef test_vgroup_remove(using_opengl_renderer):\n    \"\"\"Test the VGroup remove method.\"\"\"\n    a = OpenGLVMobject()\n    c = OpenGLVMobject()\n    b = VGroup(c)\n    obj = VGroup(a, b)\n    assert len(obj.submobjects) == 2\n    assert len(b.submobjects) == 1\n    obj.remove(a)\n    b.remove(c)\n    assert len(obj.submobjects) == 1\n    assert len(b.submobjects) == 0\n    obj.remove(b)\n    assert len(obj.submobjects) == 0\n\n\ndef test_vgroup_remove_dunder(using_opengl_renderer):\n    \"\"\"Test the VGroup __sub__ magic method.\"\"\"\n    a = OpenGLVMobject()\n    c = OpenGLVMobject()\n    b = VGroup(c)\n    obj = VGroup(a, b)\n    assert len(obj.submobjects) == 2\n    assert len(b.submobjects) == 1\n    assert len(obj - a) == 1\n    assert len(obj.submobjects) == 2\n    obj -= a\n    b -= c\n    assert len(obj.submobjects) == 1\n    assert len(b.submobjects) == 0\n    obj -= b\n    assert len(obj.submobjects) == 0\n\n\ndef test_vmob_add_to_back(using_opengl_renderer):\n    \"\"\"Test the OpenGLMobject add_to_back method.\"\"\"\n    a = OpenGLVMobject()\n    b = Line()\n    c = \"text\"\n    with pytest.raises(ValueError):\n        # OpenGLMobject cannot contain self\n        a.add_to_back(a)\n    with pytest.raises(TypeError):\n        # All submobjects must be of type OpenGLMobject\n        a.add_to_back(c)\n\n    # No submobject gets added twice\n    a.add_to_back(b)\n    a.add_to_back(b, b)\n    assert len(a.submobjects) == 1\n    a.submobjects.clear()\n    a.add_to_back(b, b, b)\n    a.add_to_back(b, b)\n    assert len(a.submobjects) == 1\n    a.submobjects.clear()\n\n    # Make sure the ordering has not changed\n    o1, o2, o3 = Square(), Line(), Circle()\n    a.add_to_back(o1, o2, o3)\n    assert a.submobjects.pop() == o3\n    assert a.submobjects.pop() == o2\n    assert a.submobjects.pop() == o1\n\n\ndef test_vdict_init(using_opengl_renderer):\n    \"\"\"Test the VDict instantiation.\"\"\"\n    # Test empty VDict\n    VDict()\n    # Test VDict made from list of pairs\n    VDict([(\"a\", OpenGLVMobject()), (\"b\", OpenGLVMobject()), (\"c\", OpenGLVMobject())])\n    # Test VDict made from a python dict\n    VDict({\"a\": OpenGLVMobject(), \"b\": OpenGLVMobject(), \"c\": OpenGLVMobject()})\n    # Test VDict made using zip\n    VDict(\n        zip(\n            [\"a\", \"b\", \"c\"],\n            [OpenGLVMobject(), OpenGLVMobject(), OpenGLVMobject()],\n            strict=True,\n        )\n    )\n    # If the value is of type OpenGLMobject, must raise a TypeError\n    with pytest.raises(TypeError):\n        VDict({\"a\": OpenGLMobject()})\n\n\ndef test_vdict_add(using_opengl_renderer):\n    \"\"\"Test the VDict add method.\"\"\"\n    obj = VDict()\n    assert len(obj.submob_dict) == 0\n    obj.add([(\"a\", OpenGLVMobject())])\n    assert len(obj.submob_dict) == 1\n    with pytest.raises(TypeError):\n        obj.add([(\"b\", OpenGLMobject())])\n\n\ndef test_vdict_remove(using_opengl_renderer):\n    \"\"\"Test the VDict remove method.\"\"\"\n    obj = VDict([(\"a\", OpenGLVMobject())])\n    assert len(obj.submob_dict) == 1\n    obj.remove(\"a\")\n    assert len(obj.submob_dict) == 0\n    with pytest.raises(KeyError):\n        obj.remove(\"a\")\n\n\ndef test_vgroup_supports_item_assigment(using_opengl_renderer):\n    \"\"\"Test VGroup supports array-like assignment for OpenGLVMObjects\"\"\"\n    a = OpenGLVMobject()\n    b = OpenGLVMobject()\n    vgroup = VGroup(a)\n    assert vgroup[0] == a\n    vgroup[0] = b\n    assert vgroup[0] == b\n    assert len(vgroup) == 1\n\n\ndef test_vgroup_item_assignment_at_correct_position(using_opengl_renderer):\n    \"\"\"Test VGroup item-assignment adds to correct position for OpenGLVMobjects\"\"\"\n    n_items = 10\n    vgroup = VGroup()\n    for _i in range(n_items):\n        vgroup.add(OpenGLVMobject())\n    new_obj = OpenGLVMobject()\n    vgroup[6] = new_obj\n    assert vgroup[6] == new_obj\n    assert len(vgroup) == n_items\n\n\ndef test_vgroup_item_assignment_only_allows_vmobjects(using_opengl_renderer):\n    \"\"\"Test VGroup item-assignment raises TypeError when invalid type is passed\"\"\"\n    vgroup = VGroup(OpenGLVMobject())\n    with pytest.raises(TypeError) as assign_str_info:\n        vgroup[0] = \"invalid object\"\n    assert str(assign_str_info.value) == (\n        \"Only values of type OpenGLVMobject can be added as submobjects of \"\n        \"VGroup, but the value invalid object (at index 0) is of type str.\"\n    )\n"
  },
  {
    "path": "tests/opengl/test_override_animation_opengl.py",
    "content": "from __future__ import annotations\n\nimport pytest\n\nfrom manim import Animation, override_animation\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\nfrom manim.utils.exceptions import MultiAnimationOverrideException\n\n\nclass AnimationA1(Animation):\n    pass\n\n\nclass AnimationA2(Animation):\n    pass\n\n\nclass AnimationA3(Animation):\n    pass\n\n\nclass AnimationB1(AnimationA1):\n    pass\n\n\nclass AnimationC1(AnimationB1):\n    pass\n\n\nclass AnimationX(Animation):\n    pass\n\n\nclass OpenGLMobjectA(OpenGLMobject):\n    @override_animation(AnimationA1)\n    def anim_a1(self):\n        return AnimationA2(self)\n\n    @override_animation(AnimationX)\n    def anim_x(self, *args, **kwargs):\n        return args, kwargs\n\n\nclass OpenGLMobjectB(OpenGLMobjectA):\n    pass\n\n\nclass OpenGLMobjectC(OpenGLMobjectB):\n    @override_animation(AnimationA1)\n    def anim_a1(self):\n        return AnimationA3(self)\n\n\nclass OpenGLMobjectX(OpenGLMobject):\n    @override_animation(AnimationB1)\n    def animation(self):\n        return \"Overridden\"\n\n\n@pytest.mark.xfail(reason=\"Needs investigating\")\ndef test_opengl_mobject_inheritance():\n    mob = OpenGLMobject()\n    a = OpenGLMobjectA()\n    b = OpenGLMobjectB()\n    c = OpenGLMobjectC()\n\n    assert type(AnimationA1(mob)) is AnimationA1\n    assert type(AnimationA1(a)) is AnimationA2\n    assert type(AnimationA1(b)) is AnimationA2\n    assert type(AnimationA1(c)) is AnimationA3\n\n\n@pytest.mark.xfail(reason=\"Needs investigating\")\ndef test_arguments():\n    a = OpenGLMobjectA()\n    args = (1, \"two\", {\"three\": 3}, [\"f\", \"o\", \"u\", \"r\"])\n    kwargs = {\"test\": \"manim\", \"keyword\": 42, \"arguments\": []}\n    animA = AnimationX(a, *args, **kwargs)\n\n    assert animA[0] == args\n    assert animA[1] == kwargs\n\n\n@pytest.mark.xfail(reason=\"Needs investigating\")\ndef test_multi_animation_override_exception():\n    with pytest.raises(MultiAnimationOverrideException):\n\n        class OpenGLMobjectB2(OpenGLMobjectA):\n            @override_animation(AnimationA1)\n            def anim_a1_different_name(self):\n                pass\n\n\n@pytest.mark.xfail(reason=\"Needs investigating\")\ndef test_animation_inheritance():\n    x = OpenGLMobjectX()\n\n    assert type(AnimationA1(x)) is AnimationA1\n    assert AnimationB1(x) == \"Overridden\"\n    assert type(AnimationC1(x)) is AnimationC1\n"
  },
  {
    "path": "tests/opengl/test_scene_opengl.py",
    "content": "from __future__ import annotations\n\nfrom manim import Scene, tempconfig\nfrom manim.mobject.opengl.opengl_mobject import OpenGLMobject\n\n\ndef test_scene_add_remove(using_opengl_renderer):\n    with tempconfig({\"dry_run\": True}):\n        scene = Scene()\n        assert len(scene.mobjects) == 0\n        scene.add(OpenGLMobject())\n        assert len(scene.mobjects) == 1\n        scene.add(*(OpenGLMobject() for _ in range(10)))\n        assert len(scene.mobjects) == 11\n\n        # Check that adding a mobject twice does not actually add it twice\n        repeated = OpenGLMobject()\n        scene.add(repeated)\n        assert len(scene.mobjects) == 12\n        scene.add(repeated)\n        assert len(scene.mobjects) == 12\n\n        # Check that Scene.add() returns the Scene (for chained calls)\n        assert scene.add(OpenGLMobject()) is scene\n        to_remove = OpenGLMobject()\n        scene = Scene()\n        scene.add(to_remove)\n        scene.add(*(OpenGLMobject() for _ in range(10)))\n        assert len(scene.mobjects) == 11\n        scene.remove(to_remove)\n        assert len(scene.mobjects) == 10\n        scene.remove(to_remove)\n        assert len(scene.mobjects) == 10\n\n        # Check that Scene.remove() returns the instance (for chained calls)\n        assert scene.add(OpenGLMobject()) is scene\n"
  },
  {
    "path": "tests/opengl/test_sound_opengl.py",
    "content": "from __future__ import annotations\n\nimport struct\nimport wave\nfrom pathlib import Path\n\nimport pytest\n\nfrom manim import Scene\n\n\n@pytest.mark.xfail(reason=\"Not currently implemented for opengl\")\ndef test_add_sound(using_opengl_renderer, tmpdir):\n    # create sound file\n    sound_loc = Path(tmpdir, \"noise.wav\")\n    with wave.open(str(sound_loc), \"w\") as f:\n        f.setparams((2, 2, 44100, 0, \"NONE\", \"not compressed\"))\n        for _ in range(22050):  # half a second of sound\n            packed_value = struct.pack(\"h\", 14242)\n            f.writeframes(packed_value)\n            f.writeframes(packed_value)\n\n    scene = Scene()\n    scene.add_sound(sound_loc)\n"
  },
  {
    "path": "tests/opengl/test_stroke_opengl.py",
    "content": "from __future__ import annotations\n\nimport manim.utils.color as C\nfrom manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject\n\n\ndef test_stroke_props_in_ctor(using_opengl_renderer):\n    m = OpenGLVMobject(stroke_color=C.ORANGE, stroke_width=10)\n    assert m.stroke_color.to_hex() == C.ORANGE.to_hex()\n    assert m.stroke_width == 10\n\n\ndef test_set_stroke(using_opengl_renderer):\n    m = OpenGLVMobject()\n    m.set_stroke(color=C.ORANGE, width=2, opacity=0.8)\n    assert m.stroke_width == 2\n    assert m.stroke_opacity == 0.8\n    assert m.stroke_color.to_hex() == C.ORANGE.to_hex()\n"
  },
  {
    "path": "tests/opengl/test_svg_mobject_opengl.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom tests.helpers.path_utils import get_svg_resource\n\n\ndef test_set_fill_color(using_opengl_renderer):\n    expected_color = \"#FF862F\"\n    svg = SVGMobject(get_svg_resource(\"heart.svg\"), fill_color=expected_color)\n    assert svg.fill_color.to_hex() == expected_color\n\n\ndef test_set_stroke_color(using_opengl_renderer):\n    expected_color = \"#FFFDDD\"\n    svg = SVGMobject(get_svg_resource(\"heart.svg\"), stroke_color=expected_color)\n    assert svg.stroke_color.to_hex() == expected_color\n\n\ndef test_set_color_sets_fill_and_stroke(using_opengl_renderer):\n    expected_color = \"#EEE777\"\n    svg = SVGMobject(get_svg_resource(\"heart.svg\"), color=expected_color)\n    assert svg.color.to_hex() == expected_color\n    assert svg.fill_color.to_hex() == expected_color\n    assert svg.stroke_color.to_hex() == expected_color\n\n\ndef test_set_fill_opacity(using_opengl_renderer):\n    expected_opacity = 0.5\n    svg = SVGMobject(get_svg_resource(\"heart.svg\"), fill_opacity=expected_opacity)\n    assert svg.fill_opacity == expected_opacity\n\n\ndef test_stroke_opacity(using_opengl_renderer):\n    expected_opacity = 0.4\n    svg = SVGMobject(get_svg_resource(\"heart.svg\"), stroke_opacity=expected_opacity)\n    assert svg.stroke_opacity == expected_opacity\n\n\ndef test_fill_overrides_color(using_opengl_renderer):\n    expected_color = \"#343434\"\n    svg = SVGMobject(\n        get_svg_resource(\"heart.svg\"),\n        color=\"#123123\",\n        fill_color=expected_color,\n    )\n    assert svg.fill_color.to_hex() == expected_color\n\n\ndef test_stroke_overrides_color(using_opengl_renderer):\n    expected_color = \"#767676\"\n    svg = SVGMobject(\n        get_svg_resource(\"heart.svg\"),\n        color=\"#334433\",\n        stroke_color=expected_color,\n    )\n    assert svg.stroke_color.to_hex() == expected_color\n"
  },
  {
    "path": "tests/opengl/test_texmobject_opengl.py",
    "content": "from __future__ import annotations\n\nfrom pathlib import Path\n\nimport pytest\n\nfrom manim import MathTex, SingleStringMathTex, Tex\n\n\ndef test_MathTex(config, using_opengl_renderer):\n    MathTex(\"a^2 + b^2 = c^2\")\n    assert Path(config.media_dir, \"Tex\", \"05bb0a41ed575f00.svg\").exists()\n\n\ndef test_SingleStringMathTex(config, using_opengl_renderer):\n    SingleStringMathTex(\"test\")\n    assert Path(config.media_dir, \"Tex\", \"8ce17c7f5013209f.svg\").exists()\n\n\n@pytest.mark.parametrize(  # : PT006\n    (\"text_input\", \"length_sub\"),\n    [(\"{{ a }} + {{ b }} = {{ c }}\", 5), (r\"\\frac{1}{a+b\\sqrt{2}}\", 1)],\n)\ndef test_double_braces_testing(using_opengl_renderer, text_input, length_sub):\n    t1 = MathTex(text_input)\n    assert len(t1.submobjects) == length_sub\n\n\ndef test_tex(config, using_opengl_renderer):\n    Tex(\"The horse does not eat cucumber salad.\")\n    assert Path(config.media_dir, \"Tex\", \"5384b41741a246bd.svg\").exists()\n\n\ndef test_tex_whitespace_arg(using_opengl_renderer):\n    \"\"\"Check that correct number of submobjects are created per string with whitespace separator\"\"\"\n    separator = \"\\t\"\n    str_part_1 = \"Hello\"\n    str_part_2 = \"world\"\n    str_part_3 = \"It is\"\n    str_part_4 = \"me!\"\n    tex = Tex(str_part_1, str_part_2, str_part_3, str_part_4, arg_separator=separator)\n    assert len(tex) == 4\n    assert len(tex[0]) == len(\"\".join((str_part_1 + separator).split()))\n    assert len(tex[1]) == len(\"\".join((str_part_2 + separator).split()))\n    assert len(tex[2]) == len(\"\".join((str_part_3 + separator).split()))\n    assert len(tex[3]) == len(\"\".join(str_part_4.split()))\n\n\ndef test_tex_non_whitespace_arg(using_opengl_renderer):\n    \"\"\"Check that correct number of submobjects are created per string with non_whitespace characters\"\"\"\n    separator = \",\"\n    str_part_1 = \"Hello\"\n    str_part_2 = \"world\"\n    str_part_3 = \"It is\"\n    str_part_4 = \"me!\"\n    tex = Tex(str_part_1, str_part_2, str_part_3, str_part_4, arg_separator=separator)\n    assert len(tex) == 4\n    assert len(tex[0]) == len(\"\".join((str_part_1 + separator).split()))\n    assert len(tex[1]) == len(\"\".join((str_part_2 + separator).split()))\n    assert len(tex[2]) == len(\"\".join((str_part_3 + separator).split()))\n    assert len(tex[3]) == len(\"\".join(str_part_4.split()))\n\n\ndef test_tex_white_space_and_non_whitespace_args(using_opengl_renderer):\n    \"\"\"Check that correct number of submobjects are created per string when mixing characters with whitespace\"\"\"\n    separator = \", \\n . \\t\\t\"\n    str_part_1 = \"Hello\"\n    str_part_2 = \"world\"\n    str_part_3 = \"It is\"\n    str_part_4 = \"me!\"\n    tex = Tex(str_part_1, str_part_2, str_part_3, str_part_4, arg_separator=separator)\n    assert len(tex) == 4\n    assert len(tex[0]) == len(\"\".join((str_part_1 + separator).split()))\n    assert len(tex[1]) == len(\"\".join((str_part_2 + separator).split()))\n    assert len(tex[2]) == len(\"\".join((str_part_3 + separator).split()))\n    assert len(tex[3]) == len(\"\".join(str_part_4.split()))\n\n\ndef test_tex_size(using_opengl_renderer):\n    \"\"\"Check that the size of a :class:`Tex` string is not changed.\"\"\"\n    text = Tex(\"what\").center()\n    vertical = text.get_top() - text.get_bottom()\n    horizontal = text.get_right() - text.get_left()\n    assert round(vertical[1], 4) == 0.3512\n    assert round(horizontal[0], 4) == 1.0420\n\n\ndef test_font_size(using_opengl_renderer):\n    \"\"\"Test that tex_mobject classes return\n    the correct font_size value after being scaled.\n    \"\"\"\n    string = MathTex(0).scale(0.3)\n\n    assert round(string.font_size, 5) == 14.4\n\n\ndef test_font_size_vs_scale(using_opengl_renderer):\n    \"\"\"Test that scale produces the same results as .scale()\"\"\"\n    num = MathTex(0, font_size=12)\n    num_scale = MathTex(0).scale(1 / 4)\n\n    assert num.height == num_scale.height\n\n\ndef test_changing_font_size(using_opengl_renderer):\n    \"\"\"Test that the font_size property properly scales tex_mobject.py classes.\"\"\"\n    num = Tex(\"0\", font_size=12)\n    num.font_size = 48\n\n    assert num.height == Tex(\"0\", font_size=48).height\n"
  },
  {
    "path": "tests/opengl/test_text_mobject_opengl.py",
    "content": "from __future__ import annotations\n\nfrom manim.mobject.text.text_mobject import MarkupText, Text\n\n\ndef test_font_size(using_opengl_renderer):\n    \"\"\"Test that Text and MarkupText return the\n    correct font_size value after being scaled.\n    \"\"\"\n    text_string = Text(\"0\").scale(0.3)\n    markuptext_string = MarkupText(\"0\").scale(0.3)\n\n    assert round(text_string.font_size, 5) == 14.4\n    assert round(markuptext_string.font_size, 5) == 14.4\n"
  },
  {
    "path": "tests/opengl/test_ticks_opengl.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim import PI, Axes, NumberLine\n\n\ndef test_duplicate_ticks_removed_for_axes(using_opengl_renderer):\n    axis = NumberLine(\n        x_range=[-10, 10],\n    )\n    ticks = axis.get_tick_range()\n    assert np.unique(ticks).size == ticks.size\n\n\ndef test_ticks_not_generated_on_origin_for_axes(using_opengl_renderer):\n    axes = Axes(\n        x_range=[-10, 10],\n        y_range=[-10, 10],\n        axis_config={\"include_ticks\": True},\n    )\n\n    x_axis_range = axes.x_axis.get_tick_range()\n    y_axis_range = axes.y_axis.get_tick_range()\n\n    assert 0 not in x_axis_range\n    assert 0 not in y_axis_range\n\n\ndef test_expected_ticks_generated(using_opengl_renderer):\n    axes = Axes(x_range=[-2, 2], y_range=[-2, 2], axis_config={\"include_ticks\": True})\n    x_axis_range = axes.x_axis.get_tick_range()\n    y_axis_range = axes.y_axis.get_tick_range()\n\n    assert 1 in x_axis_range\n    assert 1 in y_axis_range\n    assert -1 in x_axis_range\n    assert -1 in y_axis_range\n\n\ndef test_ticks_generated_from_origin_for_axes(using_opengl_renderer):\n    axes = Axes(\n        x_range=[-PI, PI],\n        y_range=[-PI, PI],\n        axis_config={\"include_ticks\": True},\n    )\n    x_axis_range = axes.x_axis.get_tick_range()\n    y_axis_range = axes.y_axis.get_tick_range()\n\n    assert -2 in x_axis_range\n    assert -1 in x_axis_range\n    assert 0 not in x_axis_range\n    assert 1 in x_axis_range\n    assert 2 in x_axis_range\n\n    assert -2 in y_axis_range\n    assert -1 in y_axis_range\n    assert 0 not in y_axis_range\n    assert 1 in y_axis_range\n    assert 2 in y_axis_range\n"
  },
  {
    "path": "tests/opengl/test_unit_geometry_opengl.py",
    "content": "from __future__ import annotations\n\nimport numpy as np\n\nfrom manim import Sector\n\n\ndef test_get_arc_center(using_opengl_renderer):\n    np.testing.assert_array_equal(\n        Sector(arc_center=[1, 2, 0]).get_arc_center(), [1, 2, 0]\n    )\n"
  },
  {
    "path": "tests/opengl/test_value_tracker_opengl.py",
    "content": "from __future__ import annotations\n\nfrom manim.mobject.value_tracker import ComplexValueTracker, ValueTracker\n\n\ndef test_value_tracker_set_value(using_opengl_renderer):\n    \"\"\"Test ValueTracker.set_value()\"\"\"\n    tracker = ValueTracker()\n    tracker.set_value(10.0)\n    assert tracker.get_value() == 10.0\n\n\ndef test_value_tracker_get_value(using_opengl_renderer):\n    \"\"\"Test ValueTracker.get_value()\"\"\"\n    tracker = ValueTracker(10.0)\n    assert tracker.get_value() == 10.0\n\n\ndef test_value_tracker_interpolate(using_opengl_renderer):\n    \"\"\"Test ValueTracker.interpolate()\"\"\"\n    tracker1 = ValueTracker(1.0)\n    tracker2 = ValueTracker(2.5)\n    tracker3 = ValueTracker().interpolate(tracker1, tracker2, 0.7)\n    assert tracker3.get_value() == 2.05\n\n\ndef test_value_tracker_increment_value(using_opengl_renderer):\n    \"\"\"Test ValueTracker.increment_value()\"\"\"\n    tracker = ValueTracker(0.0)\n    tracker.increment_value(10.0)\n    assert tracker.get_value() == 10.0\n\n\ndef test_value_tracker_bool(using_opengl_renderer):\n    \"\"\"Test ValueTracker.__bool__()\"\"\"\n    tracker = ValueTracker(0.0)\n    assert not tracker\n    tracker.increment_value(1.0)\n    assert tracker\n\n\ndef test_value_tracker_iadd(using_opengl_renderer):\n    \"\"\"Test ValueTracker.__iadd__()\"\"\"\n    tracker = ValueTracker(0.0)\n    tracker += 10.0\n    assert tracker.get_value() == 10.0\n\n\ndef test_value_tracker_ifloordiv(using_opengl_renderer):\n    \"\"\"Test ValueTracker.__ifloordiv__()\"\"\"\n    tracker = ValueTracker(5.0)\n    tracker //= 2.0\n    assert tracker.get_value() == 2.0\n\n\ndef test_value_tracker_imod(using_opengl_renderer):\n    \"\"\"Test ValueTracker.__imod__()\"\"\"\n    tracker = ValueTracker(20.0)\n    tracker %= 3.0\n    assert tracker.get_value() == 2.0\n\n\ndef test_value_tracker_imul(using_opengl_renderer):\n    \"\"\"Test ValueTracker.__imul__()\"\"\"\n    tracker = ValueTracker(3.0)\n    tracker *= 4.0\n    assert tracker.get_value() == 12.0\n\n\ndef test_value_tracker_ipow(using_opengl_renderer):\n    \"\"\"Test ValueTracker.__ipow__()\"\"\"\n    tracker = ValueTracker(3.0)\n    tracker **= 3.0\n    assert tracker.get_value() == 27.0\n\n\ndef test_value_tracker_isub(using_opengl_renderer):\n    \"\"\"Test ValueTracker.__isub__()\"\"\"\n    tracker = ValueTracker(20.0)\n    tracker -= 10.0\n    assert tracker.get_value() == 10.0\n\n\ndef test_value_tracker_itruediv(using_opengl_renderer):\n    \"\"\"Test ValueTracker.__itruediv__()\"\"\"\n    tracker = ValueTracker(5.0)\n    tracker /= 2.0\n    assert tracker.get_value() == 2.5\n\n\ndef test_complex_value_tracker_set_value(using_opengl_renderer):\n    \"\"\"Test ComplexValueTracker.set_value()\"\"\"\n    tracker = ComplexValueTracker()\n    tracker.set_value(1 + 2j)\n    assert tracker.get_value() == 1 + 2j\n\n\ndef test_complex_value_tracker_get_value(using_opengl_renderer):\n    \"\"\"Test ComplexValueTracker.get_value()\"\"\"\n    tracker = ComplexValueTracker(2.0 - 3.0j)\n    assert tracker.get_value() == 2.0 - 3.0j\n"
  },
  {
    "path": "tests/standard_config.cfg",
    "content": "[CLI]\nframe_rate = 15\npixel_height = 480\npixel_width = 300\nverbosity = DEBUG\n"
  },
  {
    "path": "tests/template_generate_graphical_units_data.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom tests.helpers.graphical_units import set_test_scene\n\n# Note: DO NOT COMMIT THIS FILE. The purpose of this template is to produce control data for graphical_units_data. As\n# soon as the test data is produced, please revert all changes you made to this file, so this template file will be\n# still available for others :)\n# More about graphical unit tests: https://github.com/ManimCommunity/manim/wiki/Testing#graphical-unit-test\n\n\nclass YourClassTest(Scene):  # e.g. RoundedRectangleTest\n    def construct(self):\n        circle = Circle()\n        self.play(Animation(circle))\n\n\nset_test_scene(\n    YourClassTest,\n    \"INSERT_MODULE_NAME\",\n)  # INSERT_MODULE_NAME can be e.g.  \"geometry\" or \"movements\"\n"
  },
  {
    "path": "tests/test_camera.py",
    "content": "from __future__ import annotations\n\nfrom manim import MovingCamera, Square\n\n\ndef test_movingcamera_auto_zoom():\n    camera = MovingCamera()\n    square = Square()\n    margin = 0.5\n    camera.auto_zoom([square], margin=margin, animate=False)\n    assert camera.frame.height == square.height + margin\n"
  },
  {
    "path": "tests/test_code_mobject.py",
    "content": "import numpy as np\nimport pytest\n\nfrom manim.mobject.text.code_mobject import Code\nfrom manim.utils.color.core import ManimColor\n\n\ndef test_code_initialization_from_string():\n    code_string = \"\"\"from manim import Scene, Square\n\nclass FadeInSquare(Scene):\n    def construct(self):\n        s = Square()\n        self.play(FadeIn(s))\n        self.play(s.animate.scale(2))\n        self.wait()\"\"\"\n    rendered_code = Code(\n        code_string=code_string,\n        language=\"python\",\n    )\n    num_lines = len(code_string.split(\"\\n\"))\n    assert len(rendered_code.code_lines) == num_lines\n    assert len(rendered_code.line_numbers) == num_lines\n\n\ndef test_code_initialization_from_file():\n    rendered_code = Code(\n        code_file=\"tests/test_code_mobject.py\",\n        language=\"python\",\n        background=\"window\",\n        background_config={\"fill_color\": \"#101010\"},\n    )\n    assert len(rendered_code.code_lines) == len(rendered_code.line_numbers)\n    assert rendered_code.background.fill_color == ManimColor(\"#101010\")\n\n\ndef test_line_heights_initial_whitespace():\n    rendered_code = Code(\n        code_string=\"\"\"print('Hello, World!')\nfor _ in range(42):\n    print('Hello, World!')\n\"\"\",\n        language=\"python\",\n    )\n    np.testing.assert_almost_equal(\n        rendered_code.code_lines[0].height,\n        rendered_code.code_lines[2].height,\n    )\n\n\ndef test_code_initialization_style_correct_color():\n    for style in Code.get_styles_list():\n        try:\n            Code(\n                code_string=\"\"\"# This is a comment.\nvar = 3\nprint(var)\n\"\"\",\n                formatter_style=style,\n            )\n        except ValueError as e:\n            pytest.fail(f\"Code initialization failed for style {style} with error: {e}\")\n"
  },
  {
    "path": "tests/test_config.py",
    "content": "from __future__ import annotations\n\nimport tempfile\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\n\nfrom manim import WHITE, Scene, Square, Tex, Text, tempconfig\nfrom manim._config.utils import ManimConfig\nfrom tests.assert_utils import assert_dir_exists, assert_dir_filled, assert_file_exists\n\n\ndef test_tempconfig(config):\n    \"\"\"Test the tempconfig context manager.\"\"\"\n    original = config.copy()\n\n    with tempconfig({\"frame_width\": 100, \"frame_height\": 42}):\n        # check that config was modified correctly\n        assert config[\"frame_width\"] == 100\n        assert config[\"frame_height\"] == 42\n\n        # check that no keys are missing and no new keys were added\n        assert set(original.keys()) == set(config.keys())\n\n    # check that the keys are still untouched\n    assert set(original.keys()) == set(config.keys())\n\n    # check that config is correctly restored\n    for k, v in original.items():\n        if isinstance(v, np.ndarray):\n            np.testing.assert_allclose(config[k], v)\n        else:\n            assert config[k] == v\n\n\n@pytest.mark.parametrize(\n    (\"format\", \"expected_file_extension\"),\n    [\n        (\"mp4\", \".mp4\"),\n        (\"webm\", \".webm\"),\n        (\"mov\", \".mov\"),\n        (\"gif\", \".mp4\"),\n    ],\n)\ndef test_resolve_file_extensions(config, format, expected_file_extension):\n    config.format = format\n    assert config.movie_file_extension == expected_file_extension\n\n\nclass MyScene(Scene):\n    def construct(self):\n        self.add(Square())\n        self.add(Text(\"Prepare for unforeseen consequencesλ\"))\n        self.add(Tex(r\"$\\lambda$\"))\n        self.wait(1)\n\n\ndef test_transparent(config):\n    \"\"\"Test the 'transparent' config option.\"\"\"\n    config.verbosity = \"ERROR\"\n    config.dry_run = True\n\n    scene = MyScene()\n    scene.render()\n    frame = scene.renderer.get_frame()\n    np.testing.assert_allclose(frame[0, 0], [0, 0, 0, 255])\n\n    config.transparent = True\n\n    scene = MyScene()\n    scene.render()\n    frame = scene.renderer.get_frame()\n    np.testing.assert_allclose(frame[0, 0], [0, 0, 0, 0])\n\n\ndef test_transparent_by_background_opacity(config, dry_run):\n    config.background_opacity = 0.5\n    assert config.transparent is True\n\n    scene = MyScene()\n    scene.render()\n    frame = scene.renderer.get_frame()\n    np.testing.assert_allclose(frame[0, 0], [0, 0, 0, 127])\n    assert config.movie_file_extension == \".mov\"\n    assert config.transparent is True\n\n\ndef test_background_color(config):\n    \"\"\"Test the 'background_color' config option.\"\"\"\n    config.background_color = WHITE\n    config.verbosity = \"ERROR\"\n    config.dry_run = True\n\n    scene = MyScene()\n    scene.render()\n    frame = scene.renderer.get_frame()\n    np.testing.assert_allclose(frame[0, 0], [255, 255, 255, 255])\n\n\ndef test_digest_file(tmp_path, config):\n    \"\"\"Test that a config file can be digested programmatically.\"\"\"\n    with tempfile.NamedTemporaryFile(\"w\", dir=tmp_path, delete=False) as tmp_cfg:\n        tmp_cfg.write(\n            \"\"\"\n            [CLI]\n            media_dir = this_is_my_favorite_path\n            video_dir = {media_dir}/videos\n            sections_dir = {media_dir}/{scene_name}/prepare_for_unforeseen_consequences\n            frame_height = 10\n            \"\"\",\n        )\n    config.digest_file(tmp_cfg.name)\n\n    assert config.get_dir(\"media_dir\") == Path(\"this_is_my_favorite_path\")\n    assert config.get_dir(\"video_dir\") == Path(\"this_is_my_favorite_path/videos\")\n    assert config.get_dir(\"sections_dir\", scene_name=\"test\") == Path(\n        \"this_is_my_favorite_path/test/prepare_for_unforeseen_consequences\"\n    )\n\n\ndef test_custom_dirs(tmp_path, config):\n    config.media_dir = tmp_path\n    config.save_sections = True\n    config.log_to_file = True\n    config.frame_rate = 15\n    config.pixel_height = 854\n    config.pixel_width = 480\n    config.sections_dir = \"{media_dir}/test_sections\"\n    config.video_dir = \"{media_dir}/test_video\"\n    config.partial_movie_dir = \"{media_dir}/test_partial_movie_dir\"\n    config.images_dir = \"{media_dir}/test_images\"\n    config.text_dir = \"{media_dir}/test_text\"\n    config.tex_dir = \"{media_dir}/test_tex\"\n    config.log_dir = \"{media_dir}/test_log\"\n\n    scene = MyScene()\n    scene.render()\n    tmp_path = Path(tmp_path)\n    assert_dir_filled(tmp_path / \"test_sections\")\n    assert_file_exists(tmp_path / \"test_sections/MyScene.json\")\n\n    assert_dir_filled(tmp_path / \"test_video\")\n    assert_file_exists(tmp_path / \"test_video/MyScene.mp4\")\n\n    assert_dir_filled(tmp_path / \"test_partial_movie_dir\")\n    assert_file_exists(tmp_path / \"test_partial_movie_dir/partial_movie_file_list.txt\")\n\n    # TODO: another example with image output would be nice\n    assert_dir_exists(tmp_path / \"test_images\")\n\n    assert_dir_filled(tmp_path / \"test_text\")\n    assert_dir_filled(tmp_path / \"test_tex\")\n    assert_dir_filled(tmp_path / \"test_log\")\n\n\ndef test_pixel_dimensions(tmp_path, config):\n    with tempfile.NamedTemporaryFile(\"w\", dir=tmp_path, delete=False) as tmp_cfg:\n        tmp_cfg.write(\n            \"\"\"\n            [CLI]\n            pixel_height = 10\n            pixel_width = 10\n            \"\"\",\n        )\n    config.digest_file(tmp_cfg.name)\n\n    # aspect ratio is set using pixel measurements\n    np.testing.assert_allclose(config.aspect_ratio, 1.0)\n    # if not specified in the cfg file, frame_width is set using the aspect ratio\n    np.testing.assert_allclose(config.frame_height, 8.0)\n    np.testing.assert_allclose(config.frame_width, 8.0)\n\n\ndef test_frame_size(tmp_path, config):\n    \"\"\"Test that the frame size can be set via config file.\"\"\"\n    np.testing.assert_allclose(\n        config.aspect_ratio, config.pixel_width / config.pixel_height\n    )\n    np.testing.assert_allclose(config.frame_height, 8.0)\n\n    with tempfile.NamedTemporaryFile(\"w\", dir=tmp_path, delete=False) as tmp_cfg:\n        tmp_cfg.write(\n            \"\"\"\n            [CLI]\n            pixel_height = 10\n            pixel_width = 10\n            frame_height = 10\n            frame_width = 10\n            \"\"\",\n        )\n    config.digest_file(tmp_cfg.name)\n\n    np.testing.assert_allclose(config.aspect_ratio, 1.0)\n    # if both are specified in the cfg file, the aspect ratio is ignored\n    np.testing.assert_allclose(config.frame_height, 10.0)\n    np.testing.assert_allclose(config.frame_width, 10.0)\n\n\ndef test_temporary_dry_run(config):\n    \"\"\"Test that tempconfig correctly restores after setting dry_run.\"\"\"\n    assert config[\"write_to_movie\"]\n    assert not config[\"save_last_frame\"]\n\n    with tempconfig({\"dry_run\": True}):\n        assert not config[\"write_to_movie\"]\n        assert not config[\"save_last_frame\"]\n\n    assert config[\"write_to_movie\"]\n    assert not config[\"save_last_frame\"]\n\n\ndef test_dry_run_with_png_format(config, dry_run):\n    \"\"\"Test that there are no exceptions when running a png without output\"\"\"\n    config.write_to_movie = False\n    config.disable_caching = True\n    assert config.dry_run is True\n    scene = MyScene()\n    scene.render()\n\n\ndef test_dry_run_with_png_format_skipped_animations(config, dry_run):\n    \"\"\"Test that there are no exceptions when running a png without output and skipped animations\"\"\"\n    config.write_to_movie = False\n    config.disable_caching = True\n    assert config[\"dry_run\"] is True\n    scene = MyScene(skip_animations=True)\n    scene.render()\n\n\ndef test_tex_template_file(tmp_path):\n    \"\"\"Test that a custom tex template file can be set from a config file.\"\"\"\n    tex_file = Path(tmp_path / \"my_template.tex\")\n    tex_file.write_text(\"Hello World!\")\n    with tempfile.NamedTemporaryFile(\"w\", dir=tmp_path, delete=False) as tmp_cfg:\n        tmp_cfg.write(\n            f\"\"\"\n            [CLI]\n            tex_template_file = {tex_file}\n            \"\"\",\n        )\n\n    custom_config = ManimConfig().digest_file(tmp_cfg.name)\n\n    assert Path(custom_config.tex_template_file) == tex_file\n    assert custom_config.tex_template.body == \"Hello World!\"\n\n\ndef test_from_to_animations_only_first_animation(config):\n    config: ManimConfig\n    config.from_animation_number = 0\n    config.upto_animation_number = 0\n\n    class SceneWithTwoAnimations(Scene):\n        def construct(self):\n            self.after_first_animation = False\n            s = Square()\n            self.add(s)\n            self.play(s.animate.scale(2))\n            self.renderer.update_skipping_status()\n            self.after_first_animation = True\n            self.play(s.animate.scale(2))\n\n    scene = SceneWithTwoAnimations()\n    scene.render()\n\n    assert scene.after_first_animation is False\n"
  },
  {
    "path": "tests/test_graphical_units/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_graphical_units/conftest.py",
    "content": "from __future__ import annotations\n\nimport pytest\n\n\n@pytest.fixture\ndef show_diff(request):\n    return request.config.getoption(\"show_diff\")\n\n\n@pytest.fixture(params=[True, False])\ndef use_vectorized(request):\n    return request.param\n"
  },
  {
    "path": "tests/test_graphical_units/test_animation.py",
    "content": "from manim import *\nfrom manim.animation.animation import DEFAULT_ANIMATION_RUN_TIME\n\n__module_test__ = \"animation\"\n\n\ndef test_animation_set_default():\n    s = Square()\n    Rotate.set_default(run_time=100)\n    anim = Rotate(s)\n    assert anim.run_time == 100\n    anim = Rotate(s, run_time=5)\n    assert anim.run_time == 5\n    Rotate.set_default()\n    anim = Rotate(s)\n    assert anim.run_time == DEFAULT_ANIMATION_RUN_TIME\n"
  },
  {
    "path": "tests/test_graphical_units/test_axes.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"plot\"\n\n\n@frames_comparison\ndef test_axes(scene):\n    graph = Axes(\n        x_range=[-10, 10, 1],\n        y_range=[-10, 10, 1],\n        x_length=6,\n        y_length=6,\n        color=WHITE,\n        y_axis_config={\"tip_shape\": StealthTip},\n    )\n    labels = graph.get_axis_labels()\n    scene.add(graph, labels)\n\n\n@frames_comparison\ndef test_plot_functions(scene, use_vectorized):\n    ax = Axes(x_range=(-10, 10.3), y_range=(-1.5, 1.5))\n    graph = ax.plot(lambda x: x**2, use_vectorized=use_vectorized)\n    scene.add(ax, graph)\n\n\n@frames_comparison\ndef test_custom_coordinates(scene):\n    ax = Axes(x_range=[0, 10])\n\n    ax.add_coordinates(\n        dict(zip(list(range(1, 10)), [Tex(\"str\") for _ in range(1, 10)], strict=True)),\n    )\n    scene.add(ax)\n\n\n@frames_comparison\ndef test_get_axis_labels(scene):\n    ax = Axes()\n    labels = ax.get_axis_labels(Tex(\"$x$-axis\").scale(0.7), Tex(\"$y$-axis\").scale(0.45))\n    scene.add(ax, labels)\n\n\n@frames_comparison\ndef test_get_x_axis_label(scene):\n    ax = Axes(x_range=(0, 8), y_range=(0, 5), x_length=8, y_length=5)\n    x_label = ax.get_x_axis_label(\n        Tex(\"$x$-values\").scale(0.65),\n        edge=DOWN,\n        direction=DOWN,\n        buff=0.5,\n    )\n    scene.add(ax, x_label)\n\n\n@frames_comparison\ndef test_get_y_axis_label(scene):\n    ax = Axes(x_range=(0, 8), y_range=(0, 5), x_length=8, y_length=5)\n    y_label = ax.get_y_axis_label(\n        Tex(\"$y$-values\").scale(0.65).rotate(90 * DEGREES),\n        edge=LEFT,\n        direction=LEFT,\n        buff=0.3,\n    )\n    scene.add(ax, y_label)\n\n\n@frames_comparison\ndef test_axis_tip_default_width_height(scene):\n    ax = Axes(\n        x_range=(0, 4),\n        y_range=(0, 4),\n        axis_config={\"include_numbers\": True, \"include_tip\": True},\n    )\n\n    scene.add(ax)\n\n\n@frames_comparison\ndef test_axis_tip_custom_width_height(scene):\n    ax = Axes(\n        x_range=(0, 4),\n        y_range=(0, 4),\n        axis_config={\"include_numbers\": True, \"include_tip\": True},\n        x_axis_config={\"tip_width\": 1, \"tip_height\": 0.1},\n        y_axis_config={\"tip_width\": 0.1, \"tip_height\": 1},\n    )\n\n    scene.add(ax)\n\n\n@frames_comparison\ndef test_plot_derivative_graph(scene, use_vectorized):\n    ax = NumberPlane(y_range=[-1, 7], background_line_style={\"stroke_opacity\": 0.4})\n\n    curve_1 = ax.plot(lambda x: x**2, color=PURPLE_B, use_vectorized=use_vectorized)\n    curve_2 = ax.plot_derivative_graph(curve_1, use_vectorized=use_vectorized)\n    curve_3 = ax.plot_antiderivative_graph(curve_1, use_vectorized=use_vectorized)\n    curves = VGroup(curve_1, curve_2, curve_3)\n    scene.add(ax, curves)\n\n\n@frames_comparison\ndef test_plot(scene, use_vectorized):\n    # construct the axes\n    ax_1 = Axes(\n        x_range=[0.001, 6],\n        y_range=[-8, 2],\n        x_length=5,\n        y_length=3,\n        tips=False,\n    )\n    ax_2 = ax_1.copy()\n    ax_3 = ax_1.copy()\n\n    # position the axes\n    ax_1.to_corner(UL)\n    ax_2.to_corner(UR)\n    ax_3.to_edge(DOWN)\n    axes = VGroup(ax_1, ax_2, ax_3)\n\n    # create the logarithmic curves\n    def log_func(x):\n        return np.log(x)\n\n    # a curve without adjustments; poor interpolation.\n    curve_1 = ax_1.plot(log_func, color=PURE_RED, use_vectorized=use_vectorized)\n\n    # disabling interpolation makes the graph look choppy as not enough\n    # inputs are available\n    curve_2 = ax_2.plot(\n        log_func, use_smoothing=False, color=ORANGE, use_vectorized=use_vectorized\n    )\n\n    # taking more inputs of the curve by specifying a step for the\n    # x_range yields expected results, but increases rendering time.\n    curve_3 = ax_3.plot(\n        log_func,\n        x_range=(0.001, 6, 0.001),\n        color=PURE_GREEN,\n        use_vectorized=use_vectorized,\n    )\n\n    curves = VGroup(curve_1, curve_2, curve_3)\n\n    scene.add(axes, curves)\n\n\n@frames_comparison\ndef test_get_graph_label(scene):\n    ax = Axes()\n    sin = ax.plot(lambda x: np.sin(x), color=PURPLE_B)\n    label = ax.get_graph_label(\n        graph=sin,\n        label=MathTex(r\"\\frac{\\pi}{2}\"),\n        x_val=PI / 2,\n        dot=True,\n        dot_config={\"radius\": 0.04},\n        direction=UR,\n    )\n\n    scene.add(ax, sin, label)\n\n\n@frames_comparison\ndef test_get_lines_to_point(scene):\n    ax = Axes()\n    circ = Circle(radius=0.5).move_to([-4, -1.5, 0])\n\n    lines_1 = ax.get_lines_to_point(circ.get_right(), color=GREEN_B)\n    lines_2 = ax.get_lines_to_point(circ.get_corner(DL), color=BLUE_B)\n    scene.add(ax, lines_1, lines_2, circ)\n\n\n@frames_comparison\ndef test_plot_line_graph(scene):\n    plane = NumberPlane(\n        x_range=(0, 7),\n        y_range=(0, 5),\n        x_length=7,\n        axis_config={\"include_numbers\": True},\n    )\n\n    line_graph = plane.plot_line_graph(\n        x_values=[0, 1.5, 2, 2.8, 4, 6.25],\n        y_values=[1, 3, 2.25, 4, 2.5, 1.75],\n        line_color=GOLD_E,\n        vertex_dot_style={\"stroke_width\": 3, \"fill_color\": PURPLE},\n        vertex_dot_radius=0.04,\n        stroke_width=4,\n    )\n    # test that the line and dots can be accessed afterwards\n    line_graph[\"line_graph\"].set_stroke(width=2)\n    line_graph[\"vertex_dots\"].scale(2)\n    scene.add(plane, line_graph)\n\n\n@frames_comparison\ndef test_t_label(scene):\n    # defines the axes and linear function\n    axes = Axes(x_range=[-1, 10], y_range=[-1, 10], x_length=9, y_length=6)\n    func = axes.plot(lambda x: x, color=BLUE)\n    # creates the T_label\n    t_label = axes.get_T_label(x_val=4, graph=func, label=Tex(\"$x$-value\"))\n    scene.add(axes, func, t_label)\n\n\n@frames_comparison\ndef test_get_area(scene):\n    ax = Axes().add_coordinates()\n    curve1 = ax.plot(\n        lambda x: 2 * np.sin(x),\n        x_range=[-5, ax.x_range[1]],\n        color=DARK_BLUE,\n    )\n    curve2 = ax.plot(lambda x: (x + 4) ** 2 - 2, x_range=[-5, -2], color=RED)\n    area1 = ax.get_area(\n        curve1,\n        x_range=(PI / 2, 3 * PI / 2),\n        color=(GREEN_B, GREEN_D),\n        opacity=1,\n    )\n    area2 = ax.get_area(\n        curve1,\n        x_range=(-4.5, -2),\n        color=(RED, PURE_YELLOW),\n        opacity=0.2,\n        bounded_graph=curve2,\n    )\n\n    scene.add(ax, curve1, curve2, area1, area2)\n\n\n@frames_comparison\ndef test_get_area_with_boundary_and_few_plot_points(scene):\n    ax = Axes(x_range=[-2, 2], y_range=[-2, 2], color=WHITE)\n    f1 = ax.plot(lambda t: t, [-1, 1, 0.5])\n    f2 = ax.plot(lambda t: 1, [-1, 1, 0.5])\n    a1 = ax.get_area(f1, [-1, 0.75], color=RED)\n    a2 = ax.get_area(f1, [-0.75, 1], bounded_graph=f2, color=GREEN)\n\n    scene.add(ax, f1, f2, a1, a2)\n\n\n@frames_comparison\ndef test_get_riemann_rectangles(scene, use_vectorized):\n    ax = Axes(y_range=[-2, 10])\n    quadratic = ax.plot(lambda x: 0.5 * x**2 - 0.5, use_vectorized=use_vectorized)\n\n    # the rectangles are constructed from their top right corner.\n    # passing an iterable to `color` produces a gradient\n    rects_right = ax.get_riemann_rectangles(\n        quadratic,\n        x_range=[-4, -3],\n        dx=0.25,\n        color=(TEAL, BLUE_B, DARK_BLUE),\n        input_sample_type=\"right\",\n    )\n\n    # the colour of rectangles below the x-axis is inverted\n    # due to show_signed_area\n    rects_left = ax.get_riemann_rectangles(\n        quadratic,\n        x_range=[-1.5, 1.5],\n        dx=0.15,\n        color=PURE_YELLOW,\n    )\n\n    bounding_line = ax.plot(lambda x: 1.5 * x, color=BLUE_B, x_range=[3.3, 6])\n    bounded_rects = ax.get_riemann_rectangles(\n        bounding_line,\n        bounded_graph=quadratic,\n        dx=0.15,\n        x_range=[4, 5],\n        show_signed_area=False,\n        color=(MAROON_A, RED_B, PURPLE_D),\n    )\n\n    scene.add(ax, bounding_line, quadratic, rects_right, rects_left, bounded_rects)\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_get_z_axis_label(scene):\n    ax = ThreeDAxes()\n    lab = ax.get_z_axis_label(Tex(\"$z$-label\"))\n    scene.set_camera_orientation(phi=2 * PI / 5, theta=PI / 5)\n    scene.add(ax, lab)\n\n\n@frames_comparison\ndef test_polar_graph(scene):\n    polar = PolarPlane()\n\n    def r(theta):\n        return 4 * np.sin(theta * 4)\n\n    polar_graph = polar.plot_polar_graph(r)\n    scene.add(polar, polar_graph)\n\n\n@frames_comparison\ndef test_log_scaling_graph(scene):\n    ax = Axes(\n        x_range=[0, 8],\n        y_range=[-2, 4],\n        x_length=10,\n        y_axis_config={\"scaling\": LogBase()},\n    )\n    ax.add_coordinates()\n\n    gr = ax.plot(lambda x: x, use_smoothing=False, x_range=[0.01, 8])\n\n    scene.add(ax, gr)\n"
  },
  {
    "path": "tests/test_graphical_units/test_banner.py",
    "content": "from __future__ import annotations\n\nfrom manim import ManimBanner\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"logo\"\n\n\n@frames_comparison(last_frame=False)\ndef test_banner(scene):\n    banner = ManimBanner()\n    scene.play(banner.create(), run_time=0.5)\n    scene.play(banner.expand(), run_time=0.5)\n"
  },
  {
    "path": "tests/test_graphical_units/test_boolops.py",
    "content": "from __future__ import annotations\n\nfrom manim import (\n    BLUE,\n    Circle,\n    Difference,\n    Exclusion,\n    Intersection,\n    Rectangle,\n    Square,\n    Triangle,\n    Union,\n)\n\n# not exported by default, so directly import\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"boolean_ops\"\n\n\n@frames_comparison()\ndef test_union(scene):\n    a = Square()\n    b = Circle().move_to([0.2, 0.2, 0.0])\n    c = Rectangle()\n    un = Union(a, b, c).next_to(b)\n    scene.add(a, b, c, un)\n\n\n@frames_comparison()\ndef test_intersection(scene):\n    a = Square()\n    b = Circle().move_to([0.3, 0.3, 0.0])\n    i = Intersection(a, b).next_to(b)\n    scene.add(a, b, i)\n\n\n@frames_comparison()\ndef test_difference(scene):\n    a = Square()\n    b = Circle().move_to([0.2, 0.3, 0.0])\n    di = Difference(a, b).next_to(b)\n    scene.add(a, b, di)\n\n\n@frames_comparison()\ndef test_exclusion(scene):\n    a = Square()\n    b = Circle().move_to([0.3, 0.2, 0.0])\n    ex = Exclusion(a, b).next_to(a)\n    scene.add(a, b, ex)\n\n\n@frames_comparison()\ndef test_intersection_3_mobjects(scene):\n    a = Square()\n    b = Circle().move_to([0.2, 0.2, 0])\n    c = Triangle()\n    i = Intersection(a, b, c, fill_opacity=0.5, color=BLUE)\n    scene.add(a, b, c, i)\n"
  },
  {
    "path": "tests/test_graphical_units/test_brace.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"brace\"\n\n\n@frames_comparison\ndef test_brace_sharpness(scene):\n    line = Line(LEFT * 3, RIGHT * 3).shift(UP * 4)\n    for sharpness in [0, 0.25, 0.5, 0.75, 1, 2, 3, 5]:\n        scene.add(Brace(line, sharpness=sharpness))\n        line.shift(DOWN)\n        scene.wait()\n\n\n@frames_comparison\ndef test_braceTip(scene):\n    line = Line().shift(LEFT * 3).rotate(PI / 2)\n    steps = 8\n    for _i in range(steps):\n        brace = Brace(line, direction=line.copy().rotate(PI / 2).get_unit_vector())\n        dot = Dot()\n        brace.put_at_tip(dot)\n        line.rotate_about_origin(TAU / steps)\n        scene.add(brace, dot)\n        scene.wait()\n\n\n@frames_comparison\ndef test_arcBrace(scene):\n    scene.play(Animation(ArcBrace()))\n"
  },
  {
    "path": "tests/test_graphical_units/test_composition.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"composition\"\n\n\n@frames_comparison\ndef test_animationgroup_is_passing_remover_to_animations(scene):\n    animation_group = AnimationGroup(Create(Square()), Write(Circle()), remover=True)\n\n    scene.play(animation_group)\n    scene.wait(0.1)\n\n\n@frames_comparison\ndef test_animationgroup_is_passing_remover_to_nested_animationgroups(scene):\n    animation_group = AnimationGroup(\n        AnimationGroup(Create(Square()), Create(RegularPolygon(5))),\n        Write(Circle(), remover=True),\n        remover=True,\n    )\n\n    scene.play(animation_group)\n    scene.wait(0.1)\n"
  },
  {
    "path": "tests/test_graphical_units/test_coordinate_systems.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"coordinate_system\"\n\n\n@frames_comparison\ndef test_number_plane(scene):\n    plane = NumberPlane(\n        x_range=[-4, 6, 1],\n        axis_config={\"include_numbers\": True},\n        x_axis_config={\"unit_size\": 1.2},\n        y_range=[-2, 5],\n        y_length=6,\n        y_axis_config={\"label_direction\": UL},\n    )\n\n    scene.add(plane)\n\n\n@frames_comparison\ndef test_line_graph(scene):\n    plane = NumberPlane()\n    first_line = plane.plot_line_graph(\n        x_values=[-3, 1],\n        y_values=[-2, 2],\n        line_color=PURE_YELLOW,\n    )\n    second_line = plane.plot_line_graph(\n        x_values=[0, 2, 2, 4],\n        y_values=[0, 0, 2, 4],\n        line_color=RED,\n    )\n\n    scene.add(plane, first_line, second_line)\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_plot_surface(scene):\n    axes = ThreeDAxes(x_range=(-5, 5, 1), y_range=(-5, 5, 1), z_range=(-5, 5, 1))\n\n    def param_trig(u, v):\n        x = u\n        y = v\n        z = 2 * np.sin(x) + 2 * np.cos(y)\n        return z\n\n    trig_plane = axes.plot_surface(\n        param_trig,\n        u_range=(-5, 5),\n        v_range=(-5, 5),\n        color=BLUE,\n    )\n\n    scene.add(axes, trig_plane)\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_plot_surface_colorscale(scene):\n    axes = ThreeDAxes(x_range=(-3, 3, 1), y_range=(-3, 3, 1), z_range=(-5, 5, 1))\n\n    def param_trig(u, v):\n        x = u\n        y = v\n        z = 2 * np.sin(x) + 2 * np.cos(y)\n        return z\n\n    trig_plane = axes.plot_surface(\n        param_trig,\n        u_range=(-3, 3),\n        v_range=(-3, 3),\n        colorscale=[BLUE, GREEN, PURE_YELLOW, ORANGE, RED],\n    )\n\n    scene.add(axes, trig_plane)\n\n\n@frames_comparison\ndef test_implicit_graph(scene):\n    ax = Axes()\n    graph = ax.plot_implicit_curve(lambda x, y: x**2 + y**2 - 4)\n    scene.add(ax, graph)\n\n\n@frames_comparison\ndef test_plot_log_x_axis(scene):\n    ax = Axes(\n        x_range=[-1, 4],\n        y_range=[0, 3],\n        x_axis_config={\"scaling\": LogBase()},\n    )\n\n    graph = ax.plot(lambda x: 2 if x < 10 else 1, x_range=[-1, 4])\n    scene.add(ax, graph)\n\n\n@frames_comparison\ndef test_plot_log_x_axis_vectorized(scene):\n    ax = Axes(\n        x_range=[-1, 4],\n        y_range=[0, 3],\n        x_axis_config={\"scaling\": LogBase()},\n    )\n\n    graph = ax.plot(\n        lambda x: np.where(x < 10, 2, 1), x_range=[-1, 4], use_vectorized=True\n    )\n    scene.add(ax, graph)\n\n\n@frames_comparison\ndef test_number_plane_log(scene):\n    \"\"\"Test that NumberPlane generates its lines properly with a LogBase\"\"\"\n    # y_axis log\n    plane1 = (\n        NumberPlane(\n            x_range=[0, 8, 1],\n            y_range=[-2, 5],\n            y_length=6,\n            x_length=10,\n            y_axis_config={\"scaling\": LogBase()},\n        )\n        .add_coordinates()\n        .scale(1 / 2)\n    )\n\n    # x_axis log\n    plane2 = (\n        NumberPlane(\n            x_range=[0, 8, 1],\n            y_range=[-2, 5],\n            y_length=6,\n            x_length=10,\n            x_axis_config={\"scaling\": LogBase()},\n            faded_line_ratio=4,\n        )\n        .add_coordinates()\n        .scale(1 / 2)\n    )\n\n    scene.add(VGroup(plane1, plane2).arrange())\n\n\n@frames_comparison\ndef test_gradient_line_graph_x_axis(scene):\n    \"\"\"Test that using `colorscale` generates a line whose gradient matches the y-axis\"\"\"\n    axes = Axes(x_range=[-3, 3], y_range=[-3, 3])\n\n    curve = axes.plot(\n        lambda x: 0.1 * x**3,\n        x_range=(-3, 3, 0.001),\n        colorscale=[BLUE, GREEN, PURE_YELLOW, ORANGE, RED],\n        colorscale_axis=0,\n    )\n\n    scene.add(axes, curve)\n\n\n@frames_comparison\ndef test_gradient_line_graph_y_axis(scene):\n    \"\"\"Test that using `colorscale` generates a line whose gradient matches the y-axis\"\"\"\n    axes = Axes(x_range=[-3, 3], y_range=[-3, 3])\n\n    curve = axes.plot(\n        lambda x: 0.1 * x**3,\n        x_range=(-3, 3, 0.001),\n        colorscale=[BLUE, GREEN, PURE_YELLOW, ORANGE, RED],\n        colorscale_axis=1,\n    )\n\n    scene.add(axes, curve)\n"
  },
  {
    "path": "tests/test_graphical_units/test_creation.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"creation\"\n\n\n@frames_comparison(last_frame=False)\ndef test_create(scene):\n    square = Square()\n    scene.play(Create(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_uncreate(scene):\n    square = Square()\n    scene.add(square)\n    scene.play(Uncreate(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_uncreate_rate_func(scene):\n    square = Square()\n    scene.add(square)\n    scene.play(Uncreate(square), rate_func=linear)\n\n\n@frames_comparison(last_frame=False)\ndef test_DrawBorderThenFill(scene):\n    square = Square(fill_opacity=1)\n    scene.play(DrawBorderThenFill(square))\n\n\n# NOTE : Here should be the Write Test. But for some reasons it appears that this function is untestable (see issue #157)\n@frames_comparison(last_frame=False)\ndef test_FadeOut(scene):\n    square = Square()\n    scene.add(square)\n    scene.play(FadeOut(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_FadeIn(scene):\n    square = Square()\n    scene.play(FadeIn(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_GrowFromPoint(scene):\n    square = Square()\n    scene.play(GrowFromPoint(square, np.array((1, 1, 0))))\n\n\n@frames_comparison(last_frame=False)\ndef test_GrowFromCenter(scene):\n    square = Square()\n    scene.play(GrowFromCenter(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_GrowFromEdge(scene):\n    square = Square()\n    scene.play(GrowFromEdge(square, DOWN))\n\n\n@frames_comparison(last_frame=False)\ndef test_SpinInFromNothing(scene):\n    square = Square()\n    scene.play(SpinInFromNothing(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_ShrinkToCenter(scene):\n    square = Square()\n    scene.play(ShrinkToCenter(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_bring_to_back_introducer(scene):\n    a = Square(color=RED, fill_opacity=1)\n    b = Square(color=BLUE, fill_opacity=1).shift(RIGHT)\n    scene.add(a)\n    scene.bring_to_back(b)\n    scene.play(FadeIn(b))\n    scene.wait()\n\n\n@frames_comparison(last_frame=False)\ndef test_z_index_introducer(scene):\n    a = Circle().set_fill(color=RED, opacity=1.0)\n    scene.add(a)\n    b = Circle(arc_center=(0.5, 0.5, 0.0), color=GREEN, fill_opacity=1)\n    b.set_z_index(-1)\n    scene.play(Create(b))\n    scene.wait()\n\n\n@frames_comparison(last_frame=False)\ndef test_SpiralIn(scene):\n    circle = Circle().shift(LEFT)\n    square = Square().shift(UP)\n    shapes = VGroup(circle, square)\n    scene.play(SpiralIn(shapes))\n"
  },
  {
    "path": "tests/test_graphical_units/test_functions.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"functions\"\n\n\n@frames_comparison\ndef test_FunctionGraph(scene):\n    graph = FunctionGraph(lambda x: 2 * np.cos(0.5 * x), x_range=[-PI, PI], color=BLUE)\n    scene.add(graph)\n\n\n@frames_comparison\ndef test_ImplicitFunction(scene):\n    graph = ImplicitFunction(lambda x, y: x**2 + y**2 - 9)\n    scene.add(graph)\n"
  },
  {
    "path": "tests/test_graphical_units/test_geometry.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"geometry\"\n\n\n@frames_comparison(last_frame=True)\ndef test_Coordinates(scene):\n    dots = [Dot(np.array([x, y, 0])) for x in range(-7, 8) for y in range(-4, 5)]\n    scene.add(VGroup(*dots))\n\n\n@frames_comparison\ndef test_Arc(scene):\n    a = Arc(radius=1, start_angle=PI)\n    scene.add(a)\n\n\n@frames_comparison\ndef test_ArcBetweenPoints(scene):\n    a = ArcBetweenPoints(np.array([1, 1, 0]), np.array([2, 2, 0]))\n    scene.add(a)\n\n\n@frames_comparison\ndef test_CurvedArrow(scene):\n    a = CurvedArrow(np.array([1, 1, 0]), np.array([2, 2, 0]))\n    scene.add(a)\n\n\n@frames_comparison\ndef test_CustomDoubleArrow(scene):\n    a = DoubleArrow(\n        np.array([-1, -1, 0]),\n        np.array([1, 1, 0]),\n        tip_shape_start=ArrowCircleTip,\n        tip_shape_end=ArrowSquareFilledTip,\n    )\n    scene.add(a)\n\n\n@frames_comparison\ndef test_Circle(scene):\n    circle = Circle()\n    scene.add(circle)\n\n\n@frames_comparison\ndef test_CirclePoints(scene):\n    circle = Circle.from_three_points(LEFT, LEFT + UP, UP * 2)\n    scene.add(circle)\n\n\n@frames_comparison\ndef test_Dot(scene):\n    dot = Dot()\n    scene.add(dot)\n\n\n@frames_comparison\ndef test_DashedVMobject(scene):\n    circle = DashedVMobject(Circle(), 12, 0.9, dash_offset=0.1)\n    line = DashedLine(dash_length=0.5)\n    scene.add(circle, line)\n\n\n@frames_comparison\ndef test_AnnotationDot(scene):\n    adot = AnnotationDot()\n    scene.add(adot)\n\n\n@frames_comparison\ndef test_Ellipse(scene):\n    e = Ellipse()\n    scene.add(e)\n\n\n@frames_comparison\ndef test_Sector(scene):\n    e = Sector()\n    scene.add(e)\n\n\n@frames_comparison\ndef test_Annulus(scene):\n    a = Annulus()\n    scene.add(a)\n\n\n@frames_comparison\ndef test_AnnularSector(scene):\n    a = AnnularSector()\n    scene.add(a)\n\n\n@frames_comparison\ndef test_Line(scene):\n    a = Line(np.array([1, 1, 0]), np.array([2, 2, 0]))\n    scene.add(a)\n\n\n@frames_comparison\ndef test_Elbow(scene):\n    a = Elbow()\n    scene.add(a)\n\n\n@frames_comparison\ndef test_DoubleArrow(scene):\n    a = DoubleArrow()\n    scene.add(a)\n\n\n@frames_comparison\ndef test_Vector(scene):\n    a = Vector(UP)\n    scene.add(a)\n\n\n@frames_comparison\ndef test_Polygon(scene):\n    a = Polygon(*[np.array([1, 1, 0]), np.array([2, 2, 0]), np.array([2, 3, 0])])\n    scene.add(a)\n\n\n@frames_comparison\ndef test_Rectangle(scene):\n    a = Rectangle()\n    scene.add(a)\n\n\n@frames_comparison\ndef test_RoundedRectangle(scene):\n    a = RoundedRectangle()\n    scene.add(a)\n\n\n@frames_comparison\ndef test_ConvexHull(scene):\n    a = ConvexHull(\n        *[\n            [-2.7, -0.6, 0],\n            [0.2, -1.7, 0],\n            [1.9, 1.2, 0],\n            [-2.7, 0.9, 0],\n            [1.6, 2.2, 0],\n        ]\n    )\n    scene.add(a)\n\n\n@frames_comparison\ndef test_Arrange(scene):\n    s1 = Square()\n    s2 = Square()\n    x = VGroup(s1, s2).set_x(0).arrange(buff=1.4)\n    scene.add(x)\n\n\n@frames_comparison(last_frame=False)\ndef test_ZIndex(scene):\n    circle = Circle().set_fill(RED, opacity=1)\n    square = Square(side_length=1.7).set_fill(BLUE, opacity=1)\n    triangle = Triangle().set_fill(GREEN, opacity=1)\n    square.z_index = 0\n    triangle.z_index = 1\n    circle.z_index = 2\n\n    scene.play(FadeIn(VGroup(circle, square, triangle)))\n    scene.play(ApplyMethod(circle.shift, UP))\n    scene.play(ApplyMethod(triangle.shift, 2 * UP))\n\n\n@frames_comparison(last_frame=False)\ndef test_negative_z_index_AnimationGroup(scene):\n    # https://github.com/ManimCommunity/manim/issues/3334\n    s = Square().set_z_index(-1)\n    scene.play(AnimationGroup(GrowFromCenter(s)))\n\n\n@frames_comparison(last_frame=False)\ndef test_negative_z_index_LaggedStart(scene):\n    # https://github.com/ManimCommunity/manim/issues/3914\n    line_1 = Line(LEFT, RIGHT, color=BLUE)\n    line_2 = Line(UP + LEFT, UP + RIGHT, color=RED).set_z_index(-1)\n    scene.play(LaggedStart(FadeIn(line_1), FadeIn(line_2), lag_ratio=0.5))\n\n\n@frames_comparison(last_frame=False)\ndef test_nested_animation_groups_with_negative_z_index(scene):\n    line = Line(LEFT, RIGHT, color=BLUE).set_z_index(-1)\n    scene.play(AnimationGroup(AnimationGroup(AnimationGroup(FadeIn(line)))))\n\n\n@frames_comparison\ndef test_Angle(scene):\n    l1 = Line(ORIGIN, RIGHT)\n    l2 = Line(ORIGIN, UP)\n    a = Angle(l1, l2)\n    scene.add(a)\n\n\n@frames_comparison\ndef test_three_points_Angle(scene):\n    # acute angle\n    acute = Angle.from_three_points(\n        np.array([10, 0, 0]), np.array([0, 0, 0]), np.array([10, 10, 0])\n    )\n    # obtuse angle\n    obtuse = Angle.from_three_points(\n        np.array([-10, 1, 0]), np.array([0, 0, 0]), np.array([10, 1, 0])\n    )\n    # quadrant 1 angle\n    q1 = Angle.from_three_points(\n        np.array([10, 10, 0]), np.array([0, 0, 0]), np.array([10, 1, 0])\n    )\n    # quadrant 2 angle\n    q2 = Angle.from_three_points(\n        np.array([-10, 1, 0]), np.array([0, 0, 0]), np.array([-1, 10, 0])\n    )\n    # quadrant 3 angle\n    q3 = Angle.from_three_points(\n        np.array([-10, -1, 0]), np.array([0, 0, 0]), np.array([-1, -10, 0])\n    )\n    # quadrant 4 angle\n    q4 = Angle.from_three_points(\n        np.array([10, -1, 0]), np.array([0, 0, 0]), np.array([1, -10, 0])\n    )\n    scene.add(VGroup(acute, obtuse, q1, q2, q3, q4).arrange(RIGHT))\n\n\n@frames_comparison\ndef test_RightAngle(scene):\n    l1 = Line(ORIGIN, RIGHT)\n    l2 = Line(ORIGIN, UP)\n    a = RightAngle(l1, l2)\n    scene.add(a)\n\n\n@frames_comparison\ndef test_Polygram(scene):\n    hexagram = Polygram(\n        [[0, 2, 0], [-np.sqrt(3), -1, 0], [np.sqrt(3), -1, 0]],\n        [[-np.sqrt(3), 1, 0], [0, -2, 0], [np.sqrt(3), 1, 0]],\n    )\n    scene.add(hexagram)\n\n\n@frames_comparison\ndef test_RegularPolygram(scene):\n    pentagram = RegularPolygram(5, radius=2)\n    octagram = RegularPolygram(8, radius=2)\n    scene.add(VGroup(pentagram, octagram).arrange(RIGHT))\n\n\n@frames_comparison\ndef test_Star(scene):\n    star = Star(outer_radius=2)\n    scene.add(star)\n\n\n@frames_comparison\ndef test_AngledArrowTip(scene):\n    arrow = Arrow(start=ORIGIN, end=UP + RIGHT + OUT)\n    scene.add(arrow)\n\n\n@frames_comparison\ndef test_CurvedArrowCustomTip(scene):\n    arrow = CurvedArrow(\n        LEFT,\n        RIGHT,\n        tip_shape=ArrowCircleTip,\n    )\n    double_arrow = CurvedDoubleArrow(\n        LEFT,\n        RIGHT,\n        tip_shape_start=ArrowCircleTip,\n        tip_shape_end=ArrowSquareFilledTip,\n    )\n    scene.add(arrow, double_arrow)\n\n\n@frames_comparison\ndef test_LabeledLine(scene):\n    line = LabeledLine(\n        label=\"0.5\",\n        label_position=0.8,\n        label_config={\"font_size\": 20},\n        start=LEFT + DOWN,\n        end=RIGHT + UP,\n    )\n    scene.add(line)\n\n\n@frames_comparison\ndef test_LabeledArrow(scene):\n    l_arrow = LabeledArrow(\n        label=\"0.5\",\n        label_position=0.5,\n        label_config={\"font_size\": 15},\n        start=LEFT * 3,\n        end=RIGHT * 3 + UP * 2,\n    )\n    scene.add(l_arrow)\n\n\n@frames_comparison\ndef test_LabeledPolygram(scene):\n    polygram = LabeledPolygram(\n        [\n            [-2.5, -2.5, 0],\n            [2.5, -2.5, 0],\n            [2.5, 2.5, 0],\n            [-2.5, 2.5, 0],\n            [-2.5, -2.5, 0],\n        ],\n        [[-1, -1, 0], [0.5, -1, 0], [0.5, 0.5, 0], [-1, 0.5, 0], [-1, -1, 0]],\n        [[1, 1, 0], [2, 1, 0], [2, 2, 0], [1, 2, 0], [1, 1, 0]],\n        label=\"C\",\n    )\n    scene.add(polygram)\n"
  },
  {
    "path": "tests/test_graphical_units/test_img_and_svg.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\nfrom ..helpers.path_utils import get_svg_resource\n\n__module_test__ = \"img_and_svg\"\n\n# Tests break down into two kinds: one where the SVG is simple enough to step through\n# and ones where the SVG is realistically complex, and the output should be visually inspected.\n\n# First are the simple tests.\n\n\n@frames_comparison\ndef test_Line(scene):\n    line_demo = SVGMobject(get_svg_resource(\"line.svg\"))\n    scene.add(line_demo)\n    scene.wait()\n\n\n@frames_comparison\ndef test_CubicPath(scene):\n    cubic_demo = SVGMobject(get_svg_resource(\"cubic_demo.svg\"))\n    scene.add(cubic_demo)\n    scene.wait()\n\n\n@frames_comparison\ndef test_CubicAndLineto(scene):\n    cubic_lineto = SVGMobject(get_svg_resource(\"cubic_and_lineto.svg\"))\n    scene.add(cubic_lineto)\n    scene.wait()\n\n\n@frames_comparison\ndef test_Rhomboid(scene):\n    rhomboid = SVGMobject(get_svg_resource(\"rhomboid.svg\")).scale(0.5)\n    rhomboid_fill = rhomboid.copy().set_fill(opacity=1).shift(UP * 2)\n    rhomboid_no_fill = rhomboid.copy().set_fill(opacity=0).shift(DOWN * 2)\n    scene.add(rhomboid, rhomboid_fill, rhomboid_no_fill)\n    scene.wait()\n\n\n@frames_comparison\ndef test_Inheritance(scene):\n    three_arrows = SVGMobject(get_svg_resource(\"inheritance_test.svg\")).scale(0.5)\n    scene.add(three_arrows)\n    scene.wait()\n\n\n@frames_comparison\ndef test_MultiPartPath(scene):\n    mpp = SVGMobject(get_svg_resource(\"multi_part_path.svg\"))\n    scene.add(mpp)\n    scene.wait()\n\n\n@frames_comparison\ndef test_QuadraticPath(scene):\n    quad = SVGMobject(get_svg_resource(\"qcurve_demo.svg\"))\n    scene.add(quad)\n    scene.wait()\n\n\n@frames_comparison\ndef test_SmoothCurves(scene):\n    smooths = SVGMobject(get_svg_resource(\"smooth_curves.svg\"))\n    scene.add(smooths)\n    scene.wait()\n\n\n@frames_comparison\ndef test_WatchTheDecimals(scene):\n    def construct(scene):\n        decimal = SVGMobject(get_svg_resource(\"watch_the_decimals.svg\"))\n        scene.add(decimal)\n        scene.wait()\n\n\n@frames_comparison\ndef test_UseTagInheritance(scene):\n    aabbb = SVGMobject(get_svg_resource(\"aabbb.svg\"))\n    scene.add(aabbb)\n    scene.wait()\n\n\n@frames_comparison\ndef test_HalfEllipse(scene):\n    half_ellipse = SVGMobject(get_svg_resource(\"half_ellipse.svg\"))\n    scene.add(half_ellipse)\n    scene.wait()\n\n\n@frames_comparison\ndef test_Heart(scene):\n    heart = SVGMobject(get_svg_resource(\"heart.svg\"))\n    scene.add(heart)\n    scene.wait()\n\n\n@frames_comparison\ndef test_Arcs01(scene):\n    # See: https://www.w3.org/TR/SVG11/images/paths/arcs01.svg\n    arcs = SVGMobject(get_svg_resource(\"arcs01.svg\"))\n    scene.add(arcs)\n    scene.wait()\n\n\n@frames_comparison(last_frame=False)\ndef test_Arcs02(scene):\n    # See: https://www.w3.org/TR/SVG11/images/paths/arcs02.svg\n    arcs = SVGMobject(get_svg_resource(\"arcs02.svg\"))\n    scene.add(arcs)\n    scene.wait()\n\n\n# Second are the visual tests - these are probably too complex to verify step-by-step, so\n# these are really more of a spot-check\n\n\n@frames_comparison(last_frame=False)\ndef test_WeightSVG(scene):\n    path = get_svg_resource(\"weight.svg\")\n    svg_obj = SVGMobject(path)\n    scene.add(svg_obj)\n    scene.wait()\n\n\n@frames_comparison\ndef test_BrachistochroneCurve(scene):\n    brach_curve = SVGMobject(get_svg_resource(\"curve.svg\"))\n    scene.add(brach_curve)\n    scene.wait()\n\n\n@frames_comparison\ndef test_DesmosGraph1(scene):\n    dgraph = SVGMobject(get_svg_resource(\"desmos-graph_1.svg\")).scale(3)\n    scene.add(dgraph)\n    scene.wait()\n\n\n@frames_comparison\ndef test_Penrose(scene):\n    penrose = SVGMobject(get_svg_resource(\"penrose.svg\"))\n    scene.add(penrose)\n    scene.wait()\n\n\n@frames_comparison\ndef test_ManimLogo(scene):\n    background_rect = Rectangle(color=WHITE, fill_opacity=1).scale(2)\n    manim_logo = SVGMobject(get_svg_resource(\"manim-logo-sidebar.svg\"))\n    scene.add(background_rect, manim_logo)\n    scene.wait()\n\n\n@frames_comparison\ndef test_UKFlag(scene):\n    uk_flag = SVGMobject(get_svg_resource(\"united-kingdom.svg\"))\n    scene.add(uk_flag)\n    scene.wait()\n\n\n@frames_comparison\ndef test_SingleUSState(scene):\n    single_state = SVGMobject(get_svg_resource(\"single_state.svg\"))\n    scene.add(single_state)\n    scene.wait()\n\n\n@frames_comparison\ndef test_ContiguousUSMap(scene):\n    states = SVGMobject(get_svg_resource(\"states_map.svg\")).scale(3)\n    scene.add(states)\n    scene.wait()\n\n\n@frames_comparison\ndef test_PixelizedText(scene):\n    background_rect = Rectangle(color=WHITE, fill_opacity=1).scale(2)\n    rgb_svg = SVGMobject(get_svg_resource(\"pixelated_text.svg\"))\n    scene.add(background_rect, rgb_svg)\n    scene.wait()\n\n\n@frames_comparison\ndef test_VideoIcon(scene):\n    video_icon = SVGMobject(get_svg_resource(\"video_icon.svg\"))\n    scene.add(video_icon)\n    scene.wait()\n\n\n@frames_comparison\ndef test_MultipleTransform(scene):\n    svg_obj = SVGMobject(get_svg_resource(\"multiple_transforms.svg\"))\n    scene.add(svg_obj)\n    scene.wait()\n\n\n@frames_comparison\ndef test_MatrixTransform(scene):\n    svg_obj = SVGMobject(get_svg_resource(\"matrix.svg\"))\n    scene.add(svg_obj)\n    scene.wait()\n\n\n@frames_comparison\ndef test_ScaleTransform(scene):\n    svg_obj = SVGMobject(get_svg_resource(\"scale.svg\"))\n    scene.add(svg_obj)\n    scene.wait()\n\n\n@frames_comparison\ndef test_TranslateTransform(scene):\n    svg_obj = SVGMobject(get_svg_resource(\"translate.svg\"))\n    scene.add(svg_obj)\n    scene.wait()\n\n\n@frames_comparison\ndef test_SkewXTransform(scene):\n    svg_obj = SVGMobject(get_svg_resource(\"skewX.svg\"))\n    scene.add(svg_obj)\n    scene.wait()\n\n\n@frames_comparison\ndef test_SkewYTransform(scene):\n    svg_obj = SVGMobject(get_svg_resource(\"skewY.svg\"))\n    scene.add(svg_obj)\n    scene.wait()\n\n\n@frames_comparison\ndef test_RotateTransform(scene):\n    svg_obj = SVGMobject(get_svg_resource(\"rotate.svg\"))\n    scene.add(svg_obj)\n    scene.wait()\n\n\n@frames_comparison\ndef test_path_multiple_moves(scene):\n    svg_obj = SVGMobject(\n        get_svg_resource(\"path_multiple_moves.svg\"),\n        fill_color=WHITE,\n        stroke_color=WHITE,\n        stroke_width=3,\n    )\n    scene.add(svg_obj)\n\n\n@frames_comparison\ndef test_ImageMobject(scene):\n    file_path = get_svg_resource(\"tree_img_640x351.png\")\n    im1 = ImageMobject(file_path).shift(4 * LEFT + UP)\n    im2 = ImageMobject(file_path, scale_to_resolution=1080).shift(4 * LEFT + 2 * DOWN)\n    im3 = ImageMobject(file_path, scale_to_resolution=540).shift(4 * RIGHT)\n    scene.add(im1, im2, im3)\n    scene.wait(1)\n\n\n@frames_comparison\ndef test_ImageInterpolation(scene):\n    img = ImageMobject(\n        np.uint8([[63, 0, 0, 0], [0, 127, 0, 0], [0, 0, 191, 0], [0, 0, 0, 255]]),\n    )\n    img.height = 3\n\n    algorithm_texts = [\"nearest\", \"linear\", \"cubic\"]\n    for i, algorithm_text in enumerate(algorithm_texts):\n        algorithm = RESAMPLING_ALGORITHMS[algorithm_text]\n        img_copy = img.copy().set_resampling_algorithm(algorithm)\n        position = img.height * (i - (len(algorithm_texts) - 1) / 2) * RIGHT\n        img_copy.move_to(position)\n        scene.add(img_copy)\n\n    scene.wait()\n\n\ndef test_ImageMobject_points_length():\n    file_path = get_svg_resource(\"tree_img_640x351.png\")\n    im1 = ImageMobject(file_path)\n    assert len(im1.points) == 4\n\n\ndef test_ImageMobject_rotation():\n    # see https://github.com/ManimCommunity/manim/issues/3067\n    # rotating an image to and from the same angle should not change the image\n    file_path = get_svg_resource(\"tree_img_640x351.png\")\n    im1 = ImageMobject(file_path)\n    im2 = im1.copy()\n    im1.rotate(PI / 2)\n    im1.rotate(-PI / 2)\n    np.testing.assert_array_equal(im1.points, im2.points)\n"
  },
  {
    "path": "tests/test_graphical_units/test_indication.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"indication\"\n\n\n@frames_comparison(last_frame=False)\ndef test_FocusOn(scene):\n    square = Square()\n    scene.add(square)\n    scene.play(FocusOn(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_Indicate(scene):\n    square = Square()\n    scene.add(square)\n    scene.play(Indicate(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_Flash(scene):\n    square = Square()\n    scene.add(square)\n    scene.play(Flash(ORIGIN))\n\n\n@frames_comparison(last_frame=False)\ndef test_Circumscribe(scene):\n    square = Square()\n    scene.add(square)\n    scene.play(Circumscribe(square))\n    scene.wait()\n\n\n@frames_comparison(last_frame=False)\ndef test_ShowPassingFlash(scene):\n    square = Square()\n    scene.add(square)\n    scene.play(ShowPassingFlash(square.copy()))\n\n\n@frames_comparison(last_frame=False)\ndef test_ApplyWave(scene):\n    square = Square()\n    scene.add(square)\n    scene.play(ApplyWave(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_Wiggle(scene):\n    square = Square()\n    scene.add(square)\n    scene.play(Wiggle(square))\n\n\ndef test_Wiggle_custom_about_points():\n    square = Square()\n    wiggle = Wiggle(\n        square,\n        scale_about_point=[1.0, 2.0, 3.0],\n        rotate_about_point=[4.0, 5.0, 6.0],\n    )\n    assert np.all(wiggle.get_scale_about_point() == [1.0, 2.0, 3.0])\n    assert np.all(wiggle.get_rotate_about_point() == [4.0, 5.0, 6.0])\n"
  },
  {
    "path": "tests/test_graphical_units/test_mobjects.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"mobjects\"\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_PointCloudDot(scene):\n    p = PointCloudDot()\n    scene.add(p)\n\n\n@frames_comparison\ndef test_become(scene):\n    s = Rectangle(width=2, height=1, color=RED).shift(UP)\n    d = Dot()\n\n    s1 = s.copy().become(d, match_width=True).set_opacity(0.25).set_color(BLUE)\n    s2 = (\n        s.copy()\n        .become(d, match_height=True, match_center=True)\n        .set_opacity(0.25)\n        .set_color(GREEN)\n    )\n    s3 = s.copy().become(d, stretch=True).set_opacity(0.25).set_color(PURE_YELLOW)\n\n    scene.add(s, d, s1, s2, s3)\n\n\n@frames_comparison\ndef test_become_no_color_linking(scene):\n    a = Circle()\n    b = Square()\n    scene.add(a)\n    scene.add(b)\n    b.become(a)\n    b.shift(1 * RIGHT)\n    b.set_stroke(PURE_YELLOW, opacity=1)\n\n\n@frames_comparison\ndef test_match_style(scene):\n    square = Square(fill_color=[RED, GREEN], fill_opacity=1)\n    circle = Circle()\n    VGroup(square, circle).arrange()\n    circle.match_style(square)\n    scene.add(square, circle)\n\n\n@frames_comparison\ndef test_vmobject_joint_types(scene):\n    angled_line = VMobject(stroke_width=20, color=GREEN).set_points_as_corners(\n        [\n            np.array([-2, 0, 0]),\n            np.array([0, 0, 0]),\n            np.array([-2, 1, 0]),\n        ]\n    )\n    lines = VGroup(*[angled_line.copy() for _ in range(len(LineJointType))])\n    for line, joint_type in zip(lines, LineJointType, strict=True):\n        line.joint_type = joint_type\n\n    lines.arrange(RIGHT, buff=1)\n    scene.add(lines)\n\n\n@frames_comparison\ndef test_vmobject_cap_styles(scene):\n    arcs = VGroup(\n        *[\n            Arc(\n                radius=1,\n                start_angle=0,\n                angle=TAU / 4,\n                stroke_width=20,\n                color=GREEN,\n                cap_style=cap_style,\n            )\n            for cap_style in CapStyleType\n        ]\n    )\n    arcs.arrange(RIGHT, buff=1)\n    scene.add(arcs)\n"
  },
  {
    "path": "tests/test_graphical_units/test_modifier_methods.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"modifier_methods\"\n\n\n@frames_comparison\ndef test_Gradient(scene):\n    c = Circle(fill_opacity=1).set_color(color=[PURE_YELLOW, GREEN])\n    scene.add(c)\n\n\n@frames_comparison\ndef test_GradientRotation(scene):\n    c = Circle(fill_opacity=1).set_color(color=[PURE_YELLOW, GREEN]).rotate(PI)\n    scene.add(c)\n"
  },
  {
    "path": "tests/test_graphical_units/test_movements.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"movements\"\n\n\n@frames_comparison(last_frame=False)\ndef test_Homotopy(scene):\n    def func(x, y, z, t):\n        norm = np.linalg.norm([x, y])\n        tau = interpolate(5, -5, t) + norm / config[\"frame_x_radius\"]\n        alpha = sigmoid(tau)\n        return [x, y + 0.5 * np.sin(2 * np.pi * alpha) - t * SMALL_BUFF / 2, z]\n\n    square = Square()\n    scene.play(Homotopy(func, square))\n\n\n@frames_comparison(last_frame=False)\ndef test_PhaseFlow(scene):\n    square = Square()\n\n    def func(t):\n        return t * 0.5 * UP\n\n    scene.play(PhaseFlow(func, square))\n\n\n@frames_comparison(last_frame=False)\ndef test_MoveAlongPath(scene):\n    square = Square()\n    dot = Dot()\n    scene.play(MoveAlongPath(dot, square))\n\n\n@frames_comparison(last_frame=False)\ndef test_Rotate(scene):\n    square = Square()\n    scene.play(Rotate(square, PI))\n\n\n@frames_comparison(last_frame=False)\ndef test_MoveTo(scene):\n    square = Square()\n    scene.play(square.animate.move_to(np.array([1.0, 1.0, 0.0])))\n\n\n@frames_comparison(last_frame=False)\ndef test_Shift(scene):\n    square = Square()\n    scene.play(square.animate.shift(UP))\n"
  },
  {
    "path": "tests/test_graphical_units/test_numbers.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"numbers\"\n\n\n@frames_comparison(last_frame=False)\ndef test_set_value_with_updaters(scene):\n    \"\"\"Test that the position of the decimal updates properly\"\"\"\n    decimal = DecimalNumber(\n        0,\n        show_ellipsis=True,\n        num_decimal_places=3,\n        include_sign=True,\n    )\n    square = Square().to_edge(UP)\n\n    decimal.add_updater(lambda d: d.next_to(square, RIGHT))\n    decimal.add_updater(lambda d: d.set_value(square.get_center()[1]))\n    scene.add(square, decimal)\n    scene.play(\n        square.animate.to_edge(DOWN),\n        rate_func=there_and_back,\n    )\n"
  },
  {
    "path": "tests/test_graphical_units/test_opengl.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.renderer.opengl_renderer import OpenGLRenderer\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"opengl\"\n\n\n@frames_comparison(renderer_class=OpenGLRenderer, renderer=\"opengl\")\ndef test_Circle(scene):\n    circle = Circle().set_color(RED)\n    scene.add(circle)\n    scene.wait()\n\n\n@frames_comparison(\n    renderer_class=OpenGLRenderer,\n    renderer=\"opengl\",\n)\ndef test_FixedMobjects3D(scene: Scene):\n    scene.renderer.camera.set_euler_angles(phi=75 * DEGREES, theta=-45 * DEGREES)\n    circ = Circle(fill_opacity=1).to_edge(LEFT)\n    square = Square(fill_opacity=1).to_edge(RIGHT)\n    triangle = Triangle(fill_opacity=1).to_corner(UR)\n    [i.fix_orientation() for i in (circ, square)]\n    triangle.fix_in_frame()\n"
  },
  {
    "path": "tests/test_graphical_units/test_polyhedra.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"polyhedra\"\n\n\n@frames_comparison\ndef test_Tetrahedron(scene):\n    scene.add(Tetrahedron())\n\n\n@frames_comparison\ndef test_Octahedron(scene):\n    scene.add(Octahedron())\n\n\n@frames_comparison\ndef test_Icosahedron(scene):\n    scene.add(Icosahedron())\n\n\n@frames_comparison\ndef test_Dodecahedron(scene):\n    scene.add(Dodecahedron())\n\n\n@frames_comparison\ndef test_ConvexHull3D(scene):\n    a = ConvexHull3D(\n        *[\n            [-2.7, -0.6, 3.5],\n            [0.2, -1.7, -2.8],\n            [1.9, 1.2, 0.7],\n            [-2.7, 0.9, 1.9],\n            [1.6, 2.2, -4.2],\n        ]\n    )\n    scene.add(a)\n"
  },
  {
    "path": "tests/test_graphical_units/test_probability.py",
    "content": "from manim.constants import LEFT\nfrom manim.mobject.graphing.probability import BarChart\nfrom manim.mobject.text.tex_mobject import MathTex\nfrom manim.utils.color import BLUE, GREEN, PURE_YELLOW, RED, WHITE\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"probability\"\n\n\n@frames_comparison\ndef test_default_chart(scene):\n    pull_req = [54, 23, 47, 48, 40, 64, 112, 87]\n    versions = [\n        \"v0.1.0\",\n        \"v0.1.1\",\n        \"v0.2.0\",\n        \"v0.3.0\",\n        \"v0.4.0\",\n        \"v0.5.0\",\n        \"v0.6.0\",\n        \"v0.7.0\",\n    ]\n\n    chart = BarChart(pull_req, versions)\n    scene.add(chart)\n\n\n@frames_comparison\ndef test_get_bar_labels(scene):\n    chart = BarChart(values=[10, 9, 8, 7, 6, 5, 4, 3, 2, 1], y_range=[0, 10, 1])\n\n    c_bar_lbls = chart.get_bar_labels(\n        color=WHITE, label_constructor=MathTex, font_size=36\n    )\n\n    scene.add(chart, c_bar_lbls)\n\n\n@frames_comparison\ndef test_label_constructor(scene):\n    chart = BarChart(\n        values=[25, 46, 50, 10],\n        bar_names=[r\"\\alpha \\beta \\gamma\", r\"a+c\", r\"\\sqrt{a \\over b}\", r\"a^2+b^2\"],\n        y_length=5,\n        x_length=5,\n        bar_width=0.8,\n        x_axis_config={\"font_size\": 36, \"label_constructor\": MathTex},\n    )\n\n    scene.add(chart)\n\n\n@frames_comparison\ndef test_negative_values(scene):\n    chart = BarChart(\n        values=[-5, 40, -10, 20, -3],\n        bar_names=[\"one\", \"two\", \"three\", \"four\", \"five\"],\n        y_range=[-20, 50, 10],\n    )\n\n    c_bar_lbls = chart.get_bar_labels()\n\n    scene.add(chart, c_bar_lbls)\n\n\n@frames_comparison\ndef test_advanced_customization(scene):\n    \"\"\"Tests to make sure advanced customization can be done through :class:`~.BarChart`\"\"\"\n    chart = BarChart(values=[10, 40, 10, 20], bar_names=[\"one\", \"two\", \"three\", \"four\"])\n\n    c_x_lbls = chart.x_axis.labels\n    c_x_lbls.set_color_by_gradient(GREEN, RED, PURE_YELLOW)\n\n    c_y_nums = chart.y_axis.numbers\n    c_y_nums.set_color_by_gradient(BLUE, WHITE).shift(LEFT)\n\n    c_y_axis = chart.y_axis\n    c_y_axis.ticks.set_color(PURE_YELLOW)\n\n    c_bar_lbls = chart.get_bar_labels()\n\n    scene.add(chart, c_bar_lbls)\n\n\n@frames_comparison\ndef test_change_bar_values_some_vals(scene):\n    chart = BarChart(\n        values=[-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10],\n        y_range=[-10, 10, 2],\n        y_axis_config={\"font_size\": 24},\n    )\n    scene.add(chart)\n\n    chart.change_bar_values([-6, -4, -2])\n\n    scene.add(chart.get_bar_labels(font_size=24))\n\n\n@frames_comparison\ndef test_change_bar_values_negative(scene):\n    chart = BarChart(\n        values=[-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10],\n        y_range=[-10, 10, 2],\n        y_axis_config={\"font_size\": 24},\n    )\n    scene.add(chart)\n\n    chart.change_bar_values(list(reversed([-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10])))\n\n    scene.add(chart.get_bar_labels(font_size=24))\n"
  },
  {
    "path": "tests/test_graphical_units/test_specialized.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"specialized\"\n\n\n@frames_comparison(last_frame=False)\ndef test_Broadcast(scene):\n    circle = Circle()\n    scene.play(Broadcast(circle))\n"
  },
  {
    "path": "tests/test_graphical_units/test_speed.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"speed\"\n\n\n@frames_comparison(last_frame=False)\ndef test_SpeedModifier(scene):\n    a = Dot().shift(LEFT * 2 + 0.5 * UP)\n    b = Dot().shift(LEFT * 2 + 0.5 * DOWN)\n    c = Dot().shift(2 * RIGHT)\n    ChangeSpeed.add_updater(c, lambda x, dt: x.rotate_about_origin(PI / 3.7 * dt))\n    scene.add(a, b, c)\n    scene.play(ChangeSpeed(Wait(0.5), speedinfo={0.3: 1, 0.4: 0.1, 0.6: 0.1, 1: 1}))\n    scene.play(\n        ChangeSpeed(\n            AnimationGroup(\n                a.animate(run_time=0.5, rate_func=linear).shift(RIGHT * 4),\n                b.animate(run_time=0.5, rate_func=rush_from).shift(RIGHT * 4),\n            ),\n            speedinfo={0.3: 1, 0.4: 0.1, 0.6: 0.1, 1: 1},\n            affects_speed_updaters=False,\n        ),\n    )\n    scene.play(\n        ChangeSpeed(\n            AnimationGroup(\n                a.animate(run_time=0.5, rate_func=linear).shift(LEFT * 4),\n                b.animate(run_time=0.5, rate_func=rush_into).shift(LEFT * 4),\n            ),\n            speedinfo={0.3: 1, 0.4: 0.1, 0.6: 0.1, 1: 1},\n            rate_func=there_and_back,\n        ),\n    )\n"
  },
  {
    "path": "tests/test_graphical_units/test_tables.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"tables\"\n\n\n@frames_comparison\ndef test_Table(scene):\n    t = Table(\n        [[\"1\", \"2\"], [\"3\", \"4\"]],\n        row_labels=[Tex(\"R1\"), Tex(\"R2\")],\n        col_labels=[Tex(\"C1\"), Tex(\"C2\")],\n        top_left_entry=MathTex(\"TOP\"),\n        element_to_mobject=Tex,\n        include_outer_lines=True,\n    )\n    scene.add(t)\n\n\n@frames_comparison\ndef test_MathTable(scene):\n    t = MathTable([[1, 2], [3, 4]])\n    scene.add(t)\n\n\n@frames_comparison\ndef test_MobjectTable(scene):\n    a = Circle().scale(0.5)\n    t = MobjectTable([[a.copy(), a.copy()], [a.copy(), a.copy()]])\n    scene.add(t)\n\n\n@frames_comparison\ndef test_IntegerTable(scene):\n    t = IntegerTable(\n        np.arange(1, 21).reshape(5, 4),\n    )\n    scene.add(t)\n\n\n@frames_comparison\ndef test_DecimalTable(scene):\n    t = DecimalTable(\n        np.linspace(0, 0.9, 20).reshape(5, 4),\n    )\n    scene.add(t)\n"
  },
  {
    "path": "tests/test_graphical_units/test_tex_mobject.py",
    "content": "from manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"tex_mobject\"\n\n\n@frames_comparison\ndef test_color_inheritance(scene):\n    \"\"\"Test that Text and MarkupText correctly inherit colour from\n    their parent class.\n    \"\"\"\n    VMobject.set_default(color=RED)\n    tex = Tex(\"test color inheritance\")\n    mathtex = MathTex(\"test color inheritance\")\n    vgr = VGroup(tex, mathtex).arrange()\n    VMobject.set_default()\n\n    scene.add(vgr)\n\n\n@frames_comparison\ndef test_set_opacity_by_tex(scene):\n    \"\"\"Test that set_opacity_by_tex works correctly.\"\"\"\n    tex = MathTex(\"f(x) = y\", substrings_to_isolate=[\"f(x)\"])\n    tex.set_opacity_by_tex(\"f(x)\", 0.2, 0.5)\n    scene.add(tex)\n\n\ndef test_preserve_tex_color():\n    \"\"\"Test that Tex preserves original tex colors.\"\"\"\n    template = TexTemplate(preamble=r\"\\usepackage{xcolor}\")\n    Tex.set_default(tex_template=template)\n\n    txt = Tex(r\"\\textcolor{red}{Hello} World\")\n    assert len(txt[0].submobjects) == 10\n    assert all(char.fill_color.to_hex() == \"#FF0000\" for char in txt[0][:5])  # \"Hello\"\n    assert all(\n        char.fill_color.to_hex() == WHITE.to_hex() for char in txt[0][-5:]\n    )  # \"World\"\n\n    txt = Tex(r\"\\textcolor{red}{Hello} World\", color=BLUE)\n    assert len(txt[0].submobjects) == 10\n    assert all(char.fill_color.to_hex() == \"#FF0000\" for char in txt[0][:5])  # \"Hello\"\n    assert all(\n        char.fill_color.to_hex() == BLUE.to_hex() for char in txt[0][-5:]\n    )  # \"World\"\n\n    Tex.set_default(color=GREEN)\n    txt = Tex(r\"\\textcolor{red}{Hello} World\")\n    assert len(txt[0].submobjects) == 10\n    assert all(char.fill_color.to_hex() == \"#FF0000\" for char in txt[0][:5])  # \"Hello\"\n    assert all(\n        char.fill_color.to_hex() == GREEN.to_hex() for char in txt[0][-5:]\n    )  # \"World\"\n\n    Tex.set_default()\n"
  },
  {
    "path": "tests/test_graphical_units/test_text.py",
    "content": "from manim import RED, MarkupText, Text, VMobject\n\n__module_test__ = \"text\"\n\n\ndef test_Text2Color():\n    txt = Text(\n        \"this is  a text  with spaces!\",\n        t2c={\"spaces\": RED},\n        stroke_width=1,\n        disable_ligatures=True,\n    )\n    assert len(txt.submobjects) == 29\n    assert all(char.fill_color.to_hex() == \"#FFFFFF\" for char in txt[:4])  # \"this\"\n    assert all(\n        char.fill_color.to_hex() == RED.to_hex() for char in txt[-7:-1]\n    )  # \"spaces\"\n    assert txt[-1].fill_color.to_hex() == \"#FFFFFF\"  # \"!\"\n\n\ndef test_text_color_inheritance():\n    \"\"\"Test that Text and MarkupText correctly inherit colour from\n    their parent class.\n    \"\"\"\n    VMobject.set_default(color=RED)\n    # set both to a singular font so that the tests agree.\n    text = Text(\"test_color_inheritance\", font=\"Sans\")\n    markup_text = MarkupText(\"test_color_inheritance\", font=\"Sans\")\n\n    assert all(char.fill_color.to_hex() == RED.to_hex() for char in text)\n    assert all(char.fill_color.to_hex() == RED.to_hex() for char in markup_text)\n\n    # reset the default color so that future tests aren't affected by this change.\n    VMobject.set_default()\n"
  },
  {
    "path": "tests/test_graphical_units/test_threed.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"threed\"\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_AddFixedInFrameMobjects(scene):\n    scene.set_camera_orientation(phi=75 * DEGREES, theta=-45 * DEGREES)\n    text = Tex(\"This is a 3D tex\")\n    scene.add_fixed_in_frame_mobjects(text)\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_Cube(scene):\n    scene.add(Cube())\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_Sphere(scene):\n    scene.add(Sphere())\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_Dot3D(scene):\n    scene.add(Dot3D())\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_Cone(scene):\n    scene.add(Cone(resolution=16))\n\n\ndef test_Cone_get_start_and_get_end():\n    cone = Cone().shift(RIGHT).rotate(PI / 4, about_point=ORIGIN, about_edge=OUT)\n    start = [0.70710678, 0.70710678, -1.0]\n    end = [0.70710678, 0.70710678, 0.0]\n    assert np.allclose(cone.get_start(), start, atol=0.01), (\n        \"start points of Cone do not match\"\n    )\n    assert np.allclose(cone.get_end(), end, atol=0.01), (\n        \"end points of Cone do not match\"\n    )\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_Cylinder(scene):\n    scene.add(Cylinder())\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_Line3D(scene):\n    line1 = Line3D(resolution=16).shift(LEFT * 2)\n    line2 = Line3D(resolution=16).shift(RIGHT * 2)\n    perp_line = Line3D.perpendicular_to(line1, UP + OUT, resolution=16)\n    parallel_line = Line3D.parallel_to(line2, DOWN + IN, resolution=16)\n    scene.add(line1, line2, perp_line, parallel_line)\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_Arrow3D(scene):\n    scene.add(Arrow3D(resolution=16))\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_Torus(scene):\n    scene.add(Torus())\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_Axes(scene):\n    scene.add(ThreeDAxes())\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_CameraMoveAxes(scene):\n    \"\"\"Tests camera movement to explore varied views of a static scene.\"\"\"\n    axes = ThreeDAxes()\n    scene.add(axes)\n    scene.add(Dot([1, 2, 3]))\n    scene.move_camera(phi=PI / 8, theta=-PI / 8, frame_center=[1, 2, 3], zoom=2)\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_CameraMove(scene):\n    cube = Cube()\n    scene.add(cube)\n    scene.move_camera(phi=PI / 4, theta=PI / 4, frame_center=[0, 0, -1], zoom=0.5)\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_AmbientCameraMove(scene):\n    cube = Cube()\n    scene.begin_ambient_camera_rotation(rate=0.5)\n    scene.add(cube)\n    scene.wait()\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_MovingVertices(scene):\n    scene.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n    vertices = [1, 2, 3, 4]\n    edges = [(1, 2), (2, 3), (3, 4), (1, 3), (1, 4)]\n    g = Graph(vertices, edges)\n    scene.add(g)\n    scene.play(\n        g[1].animate.move_to([1, 1, 1]),\n        g[2].animate.move_to([-1, 1, 2]),\n        g[3].animate.move_to([1, -1, -1]),\n        g[4].animate.move_to([-1, -1, 0]),\n    )\n    scene.wait()\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_SurfaceColorscale(scene):\n    resolution_fa = 16\n    scene.set_camera_orientation(phi=75 * DEGREES, theta=-30 * DEGREES)\n    axes = ThreeDAxes(x_range=(-3, 3, 1), y_range=(-3, 3, 1), z_range=(-4, 4, 1))\n\n    def param_trig(u, v):\n        x = u\n        y = v\n        z = y**2 / 2 - x**2 / 2\n        return z\n\n    trig_plane = Surface(\n        lambda x, y: axes.c2p(x, y, param_trig(x, y)),\n        resolution=(resolution_fa, resolution_fa),\n        v_range=[-3, 3],\n        u_range=[-3, 3],\n    )\n    trig_plane.set_fill_by_value(\n        axes=axes, colorscale=[BLUE, GREEN, PURE_YELLOW, ORANGE, RED]\n    )\n    scene.add(axes, trig_plane)\n\n\n@frames_comparison(base_scene=ThreeDScene)\ndef test_Y_Direction(scene):\n    resolution_fa = 16\n    scene.set_camera_orientation(phi=75 * DEGREES, theta=-120 * DEGREES)\n    axes = ThreeDAxes(x_range=(0, 5, 1), y_range=(0, 5, 1), z_range=(-1, 1, 0.5))\n\n    def param_surface(u, v):\n        x = u\n        y = v\n        z = np.sin(x) * np.cos(y)\n        return z\n\n    surface_plane = Surface(\n        lambda u, v: axes.c2p(u, v, param_surface(u, v)),\n        resolution=(resolution_fa, resolution_fa),\n        v_range=[0, 5],\n        u_range=[0, 5],\n    )\n    surface_plane.set_style(fill_opacity=1)\n    surface_plane.set_fill_by_value(\n        axes=axes, colorscale=[(RED, -0.4), (PURE_YELLOW, 0), (GREEN, 0.4)], axis=1\n    )\n    scene.add(axes, surface_plane)\n\n\ndef test_get_start_and_end_Arrow3d():\n    start, end = ORIGIN, np.array([2, 1, 0], dtype=np.float64)\n    arrow = Arrow3D(start, end)\n    assert np.allclose(arrow.get_start(), start, atol=0.01), (\n        \"start points of Arrow3D do not match\"\n    )\n    assert np.allclose(arrow.get_end(), end, atol=0.01), (\n        \"end points of Arrow3D do not match\"\n    )\n\n\ndef test_type_conversion_in_Line3D():\n    start, end = [0, 0, 0], [1, 1, 1]\n    line = Line3D(start, end)\n    type_table = [type(item) for item in [*line.get_start(), *line.get_end()]]\n    bool_table = [t == np.float64 for t in type_table]\n    assert all(bool_table), \"Types of start and end points are not np.float64\"\n\n\ndef test_type_conversion_in_Arrow3D():\n    start, end = [0, 0, 0], [1, 1, 1]\n    arrow = Arrow3D(start, end)\n    type_table = [type(item) for item in [*arrow.get_start(), *arrow.get_end()]]\n    bool_table = [t == np.float64 for t in type_table]\n    assert all(bool_table), \"Types of start and end points are not np.float64\"\n\n    assert np.allclose(arrow.get_start(), start, atol=0.01), (\n        \"start points of Arrow3D do not match\"\n    )\n    assert np.allclose(arrow.get_end(), end, atol=0.01), (\n        \"end points of Arrow3D do not match\"\n    )\n"
  },
  {
    "path": "tests/test_graphical_units/test_transform.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"transform\"\n\n\n@frames_comparison(last_frame=False)\ndef test_Transform(scene):\n    square = Square()\n    circle = Circle()\n    scene.play(Transform(square, circle))\n\n\n@frames_comparison(last_frame=False)\ndef test_TransformFromCopy(scene):\n    square = Square()\n    circle = Circle()\n    scene.play(TransformFromCopy(square, circle))\n\n\n@frames_comparison(last_frame=False)\ndef test_FullRotation(scene):\n    s = VGroup(*(Square() for _ in range(4))).arrange()\n    scene.play(\n        Rotate(s[0], -2 * TAU),\n        Rotate(s[1], -1 * TAU),\n        Rotate(s[2], 1 * TAU),\n        Rotate(s[3], 2 * TAU),\n    )\n\n\n@frames_comparison(last_frame=False)\ndef test_ClockwiseTransform(scene):\n    square = Square()\n    circle = Circle()\n    scene.play(ClockwiseTransform(square, circle))\n\n\n@frames_comparison(last_frame=False)\ndef test_CounterclockwiseTransform(scene):\n    square = Square()\n    circle = Circle()\n    scene.play(CounterclockwiseTransform(square, circle))\n\n\n@frames_comparison(last_frame=False)\ndef test_MoveToTarget(scene):\n    square = Square()\n    square.generate_target()\n    square.target.shift(3 * UP)\n    scene.play(MoveToTarget(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_ApplyPointwiseFunction(scene):\n    square = Square()\n\n    def func(p):\n        return np.array([1.0, 1.0, 0.0])\n\n    scene.play(ApplyPointwiseFunction(func, square))\n\n\n@frames_comparison(last_frame=False)\ndef test_FadeToColort(scene):\n    square = Square()\n    scene.play(FadeToColor(square, RED))\n\n\n@frames_comparison(last_frame=False)\ndef test_ScaleInPlace(scene):\n    square = Square()\n    scene.play(ScaleInPlace(square, scale_factor=0.1))\n\n\n@frames_comparison(last_frame=False)\ndef test_ShrinkToCenter(scene):\n    square = Square()\n    scene.play(ShrinkToCenter(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_Restore(scene):\n    square = Square()\n    circle = Circle()\n    scene.play(Transform(square, circle))\n    square.save_state()\n    scene.play(square.animate.shift(UP))\n    scene.play(Restore(square))\n\n\n@frames_comparison\ndef test_ApplyFunction(scene):\n    square = Square()\n    scene.add(square)\n\n    def apply_function(mob):\n        mob.scale(2)\n        mob.to_corner(UR)\n        mob.rotate(PI / 4)\n        mob.set_color(RED)\n        return mob\n\n    scene.play(ApplyFunction(apply_function, square))\n\n\n@frames_comparison(last_frame=False)\ndef test_ApplyComplexFunction(scene):\n    square = Square()\n    scene.play(\n        ApplyComplexFunction(\n            lambda complex_num: complex_num + 2 * complex(0, 1),\n            square,\n        ),\n    )\n\n\n@frames_comparison(last_frame=False)\ndef test_ApplyMatrix(scene):\n    square = Square()\n    matrice = [[1.0, 0.5], [1.0, 0.0]]\n    about_point = np.asarray((-10.0, 5.0, 0.0))\n    scene.play(ApplyMatrix(matrice, square, about_point))\n\n\n@frames_comparison(last_frame=False)\ndef test_CyclicReplace(scene):\n    square = Square()\n    circle = Circle()\n    circle.shift(3 * UP)\n    scene.play(CyclicReplace(square, circle))\n\n\n@frames_comparison(last_frame=False)\ndef test_FadeInAndOut(scene):\n    square = Square(color=BLUE).shift(2 * UP)\n    annotation = Square(color=BLUE)\n    scene.add(annotation)\n    scene.play(FadeIn(square))\n\n    annotation.become(Square(color=RED).rotate(PI / 4))\n    scene.add(annotation)\n    scene.play(FadeOut(square))\n\n\n@frames_comparison\ndef test_MatchPointsScene(scene):\n    circ = Circle(fill_color=RED, fill_opacity=0.8)\n    square = Square(fill_color=BLUE, fill_opacity=0.2)\n    scene.play(circ.animate.match_points(square))\n\n\n@frames_comparison(last_frame=False)\ndef test_AnimationBuilder(scene):\n    scene.play(Square().animate.shift(RIGHT).rotate(PI / 4))\n\n\n@frames_comparison(last_frame=False)\ndef test_ReplacementTransform(scene):\n    yellow = Square(fill_opacity=1.0, fill_color=PURE_YELLOW)\n    yellow.move_to([0, 0.75, 0])\n\n    green = Square(fill_opacity=1.0, fill_color=GREEN)\n    green.move_to([-0.75, 0, 0])\n\n    blue = Square(fill_opacity=1.0, fill_color=BLUE)\n    blue.move_to([0.75, 0, 0])\n\n    orange = Square(fill_opacity=1.0, fill_color=ORANGE)\n    orange.move_to([0, -0.75, 0])\n\n    scene.add(yellow)\n    scene.add(VGroup(green, blue))\n    scene.add(orange)\n\n    purple = Circle(fill_opacity=1.0, fill_color=PURPLE)\n    purple.move_to(green)\n\n    scene.play(ReplacementTransform(green, purple))\n    # This pause is important to verify the purple circle remains behind\n    # the blue and orange squares, and the blue square remains behind the\n    # orange square after the transform fully completes.\n    scene.pause()\n\n\n@frames_comparison(last_frame=False)\ndef test_TransformWithPathFunc(scene):\n    dots_start = VGroup(*[Dot(LEFT, color=BLUE), Dot(3 * RIGHT, color=RED)])\n    dots_end = VGroup(*[Dot(LEFT + 2 * DOWN, color=BLUE), Dot(2 * UP, color=RED)])\n    scene.play(Transform(dots_start, dots_end, path_func=clockwise_path()))\n\n\n@frames_comparison(last_frame=False)\ndef test_TransformWithPathArcCenters(scene):\n    dots_start = VGroup(*[Dot(LEFT, color=BLUE), Dot(3 * RIGHT, color=RED)])\n    dots_end = VGroup(*[Dot(LEFT + 2 * DOWN, color=BLUE), Dot(2 * UP, color=RED)])\n    scene.play(\n        Transform(\n            dots_start,\n            dots_end,\n            path_arc=2 * PI,\n            path_arc_centers=ORIGIN,\n        )\n    )\n\n\n@frames_comparison(last_frame=False)\ndef test_TransformWithConflictingPaths(scene):\n    dots_start = VGroup(*[Dot(LEFT, color=BLUE), Dot(3 * RIGHT, color=RED)])\n    dots_end = VGroup(*[Dot(LEFT + 2 * DOWN, color=BLUE), Dot(2 * UP, color=RED)])\n    scene.play(\n        Transform(\n            dots_start,\n            dots_end,\n            path_func=clockwise_path(),\n            path_arc=2 * PI,\n            path_arc_centers=ORIGIN,\n        )\n    )\n\n\n@frames_comparison(last_frame=False)\ndef test_FadeTransformPieces(scene):\n    src = VGroup(Square(), Circle().shift(LEFT + UP))\n    src.shift(3 * LEFT)\n\n    target = VGroup(Circle(), Triangle().shift(RIGHT + DOWN))\n    target.shift(3 * RIGHT)\n\n    scene.add(src)\n    scene.play(FadeTransformPieces(src, target))\n\n\n@frames_comparison(last_frame=False)\ndef test_FadeTransform(scene):\n    src = Square(fill_opacity=1.0)\n    src.shift(3 * LEFT)\n\n    target = Circle(fill_opacity=1.0, color=ORANGE)\n    target.shift(3 * RIGHT)\n\n    scene.add(src)\n    scene.play(FadeTransform(src, target))\n\n\n@frames_comparison(last_frame=False)\ndef test_FadeTransform_TargetIsEmpty_FadesOutInPlace(scene):\n    # https://github.com/ManimCommunity/manim/issues/2845\n    src = Square(fill_opacity=1.0)\n    src.shift(3 * LEFT)\n\n    target = VGroup()\n    target.shift(3 * RIGHT)\n\n    scene.add(src)\n    scene.play(FadeTransform(src, target))\n"
  },
  {
    "path": "tests/test_graphical_units/test_transform_matching_parts.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"transform_matching_parts\"\n\n\n@frames_comparison(last_frame=True)\ndef test_TransformMatchingLeavesOneObject(scene):\n    square = Square()\n    circle = Circle().shift(RIGHT)\n    scene.add(square)\n    scene.play(TransformMatchingShapes(square, circle))\n    assert len(scene.mobjects) == 1\n    assert isinstance(scene.mobjects[0], Circle)\n\n\n@frames_comparison(last_frame=False)\ndef test_TransformMatchingDisplaysCorrect(scene):\n    square = Square()\n    circle = Circle().shift(RIGHT)\n    scene.add(square)\n    scene.play(TransformMatchingShapes(square, circle))\n    # Wait to make sure object isn't missing in-between animations\n    scene.wait(0.5)\n    # Shift to make sure object isn't duplicated if moved\n    scene.play(circle.animate.shift(DOWN))\n\n\n@frames_comparison(last_frame=False)\ndef test_TransformMatchingTex(scene):\n    start = MathTex(\"A\", \"+\", \"B\", \"=\", \"C\")\n    end = MathTex(\"C\", \"=\", \"B\", \"-\", \"A\")\n\n    scene.add(start)\n    scene.play(TransformMatchingTex(start, end))\n\n\n@frames_comparison(last_frame=False)\ndef test_TransformMatchingTex_FadeTransformMismatches(scene):\n    start = MathTex(\"A\", \"+\", \"B\", \"=\", \"C\")\n    end = MathTex(\"C\", \"=\", \"B\", \"-\", \"A\")\n\n    scene.add(start)\n    scene.play(TransformMatchingTex(start, end, fade_transform_mismatches=True))\n\n\n@frames_comparison(last_frame=False)\ndef test_TransformMatchingTex_TransformMismatches(scene):\n    start = MathTex(\"A\", \"+\", \"B\", \"=\", \"C\")\n    end = MathTex(\"C\", \"=\", \"B\", \"-\", \"A\")\n\n    scene.add(start)\n    scene.play(TransformMatchingTex(start, end, transform_mismatches=True))\n\n\n@frames_comparison(last_frame=False)\ndef test_TransformMatchingTex_FadeTransformMismatches_NothingToFade(scene):\n    # https://github.com/ManimCommunity/manim/issues/2845\n    start = MathTex(\"A\", r\"\\to\", \"B\")\n    end = MathTex(\"B\", r\"\\to\", \"A\")\n\n    scene.add(start)\n    scene.play(TransformMatchingTex(start, end, fade_transform_mismatches=True))\n"
  },
  {
    "path": "tests/test_graphical_units/test_updaters.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"updaters\"\n\n\n@frames_comparison(last_frame=False)\ndef test_Updater(scene):\n    dot = Dot()\n    square = Square()\n    scene.add(dot, square)\n    square.add_updater(lambda m: m.next_to(dot, RIGHT, buff=SMALL_BUFF))\n    scene.add(square)\n    scene.play(dot.animate.shift(UP * 2))\n    square.clear_updaters()\n\n\n@frames_comparison\ndef test_ValueTracker(scene):\n    theta = ValueTracker(PI / 2)\n    line = Line(ORIGIN, RIGHT)\n    line.rotate(theta.get_value(), about_point=ORIGIN)\n    scene.add(line)\n\n\n@frames_comparison(last_frame=False)\ndef test_UpdateSceneDuringAnimation(scene):\n    def f(mob):\n        scene.add(Square())\n\n    s = Circle().add_updater(f)\n    scene.play(Create(s))\n\n\n@frames_comparison(last_frame=False)\ndef test_LastFrameWhenCleared(scene):\n    dot = Dot()\n    square = Square()\n    square.add_updater(lambda m: m.move_to(dot, UL))\n    scene.add(square)\n    scene.play(dot.animate.shift(UP * 2), rate_func=linear)\n    square.clear_updaters()\n    scene.wait()\n"
  },
  {
    "path": "tests/test_graphical_units/test_utils.py",
    "content": "from __future__ import annotations\n\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"utils\"\n\n\n@frames_comparison\ndef test_pixel_error_threshold(scene):\n    \"\"\"Scene produces black frame, control data has 11 modified pixel values.\"\"\"\n    pass\n"
  },
  {
    "path": "tests/test_graphical_units/test_vector_scene.py",
    "content": "from __future__ import annotations\n\nfrom manim.scene.vector_space_scene import LinearTransformationScene, VectorScene\nfrom manim.utils.testing.frames_comparison import frames_comparison\n\n__module_test__ = \"vector_scene\"\n\n\n@frames_comparison(base_scene=VectorScene, last_frame=False)\ndef test_vector_to_coords(scene):\n    scene.add_plane().add_coordinates()\n    vector = scene.add_vector([-3, -2])\n    basis = scene.get_basis_vectors()\n    scene.add(basis)\n    scene.vector_to_coords(vector=vector)\n    scene.wait()\n\n\ndef test_apply_matrix():\n    scene = LinearTransformationScene(include_background_plane=False)\n    scene.setup()\n    matrix = [[-1, 1], [1, 1]]\n    # use short runtimes to speed up animation rendering\n    scene.apply_matrix(matrix, run_time=0.01)\n    scene.wait()\n    scene.apply_inverse(matrix, run_time=0.01)\n"
  },
  {
    "path": "tests/test_ipython_magic.py",
    "content": "from __future__ import annotations\n\nimport re\n\nfrom manim.utils.ipython_magic import _generate_file_name\n\n\ndef test_jupyter_file_naming(config):\n    \"\"\"Check the format of file names for jupyter\"\"\"\n    scene_name = \"SimpleScene\"\n    expected_pattern = r\"[0-9a-zA-Z_]+[@_-]\\d\\d\\d\\d-\\d\\d-\\d\\d[@_-]\\d\\d-\\d\\d-\\d\\d\"\n    config.scene_names = [scene_name]\n    file_name = _generate_file_name()\n    match = re.match(expected_pattern, file_name)\n    assert scene_name in file_name, (\n        \"Expected file to contain \" + scene_name + \" but got \" + file_name\n    )\n    assert match, \"file name does not match expected pattern \" + expected_pattern\n\n\ndef test_jupyter_file_output(tmp_path, config):\n    \"\"\"Check the jupyter file naming is valid and can be created\"\"\"\n    scene_name = \"SimpleScene\"\n    config.scene_names = [scene_name]\n    file_name = _generate_file_name()\n    actual_path = tmp_path.with_name(file_name)\n    with actual_path.open(\"w\") as outfile:\n        outfile.write(\"\")\n        assert actual_path.exists()\n        assert actual_path.is_file()\n"
  },
  {
    "path": "tests/test_linear_transformation_scene.py",
    "content": "from manim import RIGHT, UP, LinearTransformationScene, Vector, VGroup\n\n__module_test__ = \"vector_space_scene\"\n\n\ndef test_ghost_vectors_len_and_types():\n    scene = LinearTransformationScene()\n    scene.leave_ghost_vectors = True\n\n    # prepare vectors (they require a vmobject as their target)\n    v1, v2 = Vector(RIGHT), Vector(RIGHT)\n    v1.target, v2.target = Vector(UP), Vector(UP)\n\n    # ghost_vector addition is in this method\n    scene.get_piece_movement((v1, v2))\n\n    ghosts = scene.get_ghost_vectors()\n    assert len(ghosts) == 1\n    # check if there are two vectors in the ghost vector VGroup\n    assert len(ghosts[0]) == 2\n\n    # check types of ghost vectors\n    assert isinstance(ghosts, VGroup)\n    assert isinstance(ghosts[0], VGroup)\n    assert all(isinstance(x, Vector) for x in ghosts[0])\n"
  },
  {
    "path": "tests/test_logging/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_logging/bad_tex_scene.py",
    "content": "from manim import Scene, Tex, TexTemplate\n\n\nclass BadTex(Scene):\n    def construct(self):\n        tex_template = TexTemplate(preamble=r\"\\usepackage{notapackage}\")\n        some_tex = r\"\\frac{1}{0}\"\n        my_tex = Tex(some_tex, tex_template=tex_template)\n        self.add(my_tex)\n"
  },
  {
    "path": "tests/test_logging/basic_scenes_error.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\n\n# This module is intended to raise an error.\n\n\nclass Error(Scene):\n    def construct(self):\n        raise Exception(\"An error has occurred\")\n"
  },
  {
    "path": "tests/test_logging/basic_scenes_square_to_circle.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\n\n# This module is used in the CLI tests in tests_CLi.py.\n\n\nclass SquareToCircle(Scene):\n    def construct(self):\n        self.play(Transform(Square(), Circle()))\n"
  },
  {
    "path": "tests/test_logging/basic_scenes_write_stuff.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\n\n# This module is used in the CLI tests in tests_CLi.py.\n\n\nclass WriteStuff(Scene):\n    def construct(self):\n        example_text = Tex(\"This is a some text\", tex_to_color_map={\"text\": YELLOW})\n        example_tex = MathTex(\n            \"\\\\sum_{k=1}^\\\\infty {1 \\\\over k^2} = {\\\\pi^2 \\\\over 6}\",\n        )\n        group = VGroup(example_text, example_tex)\n        group.arrange(DOWN)\n        group.width = config[\"frame_width\"] - 2 * LARGE_BUFF\n\n        self.play(Write(example_text))\n"
  },
  {
    "path": "tests/test_logging/test_logging.py",
    "content": "from __future__ import annotations\n\nfrom pathlib import Path\n\nfrom manim import capture\n\nfrom ..utils.logging_tester import *\n\n\n@logs_comparison(\n    \"BasicSceneLoggingTest.txt\",\n    \"logs/basic_scenes_square_to_circle_SquareToCircle.log\",\n)\ndef test_logging_to_file(tmp_path, python_version):\n    path_basic_scene = Path(\"tests/test_logging/basic_scenes_square_to_circle.py\")\n    command = [\n        python_version,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"-v\",\n        \"DEBUG\",\n        \"--log_to_file\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(path_basic_scene),\n        \"SquareToCircle\",\n    ]\n    _, err, exitcode = capture(command)\n    assert exitcode == 0, err\n\n\ndef test_error_logging(tmp_path, python_version):\n    path_error_scene = Path(\"tests/test_logging/basic_scenes_error.py\")\n\n    command = [\n        python_version,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(path_error_scene),\n    ]\n\n    out, err, exitcode = capture(command)\n    if err is None:\n        err = out\n    assert exitcode != 0\n    assert \"Traceback (most recent call last)\" in err\n\n\n@logs_comparison(\n    \"bad_tex_scene_BadTex.txt\",\n    \"logs/bad_tex_scene_BadTex.log\",\n)\ndef test_tex_error_logs(tmp_path, python_version):\n    bad_tex_scene = Path(\"tests/test_logging/bad_tex_scene.py\")\n    command = [\n        python_version,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--log_to_file\",\n        \"-v\",\n        \"INFO\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(bad_tex_scene),\n        \"BadTex\",\n    ]\n    _, err, exitcode = capture(command)\n    assert exitcode != 0\n    assert len(err) > 0\n"
  },
  {
    "path": "tests/test_plugins/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_plugins/simple_scenes.py",
    "content": "from __future__ import annotations\n\nfrom manim import *\n\n\nclass SquareToCircle(Scene):\n    def construct(self):\n        square = Square()\n        circle = Circle()\n        self.play(Transform(square, circle))\n"
  },
  {
    "path": "tests/test_plugins/test_plugins.py",
    "content": "from __future__ import annotations\n\nimport random\nimport string\nimport textwrap\nfrom pathlib import Path\n\nimport pytest\n\nfrom manim import capture\n\nplugin_pyproject_template = textwrap.dedent(\n    \"\"\"\\\n    [project]\n    name = \"{plugin_name}\"\n    authors = [{name = \"ManimCE Test Suite\"},]\n    version = \"0.1.0\"\n    description = \"A fantastic Manim plugin\"\n    requires-python = \">=3.9\"\n\n    [project.entry-points.\"manim.plugins\"]\n    \"{plugin_name}\" = \"{plugin_entrypoint}\"\n\n    [build-system]\n    requires = [\"hatchling\"]\n    build-backend = \"hatchling.build\"\n    \"\"\",\n)\n\nplugin_init_template = textwrap.dedent(\n    \"\"\"\\\n    from manim import *\n    {all_dec}\n    class {class_name}(VMobject):\n        def __init__(self):\n            super().__init__()\n            dot1 = Dot(fill_color=GREEN).shift(LEFT)\n            dot2 = Dot(fill_color=BLUE)\n            dot3 = Dot(fill_color=RED).shift(RIGHT)\n            self.dotgrid = VGroup(dot1, dot2, dot3)\n            self.add(self.dotgrid)\n\n        def update_dot(self):\n            self.dotgrid.become(self.dotgrid.shift(UP))\n    def {function_name}():\n        return [{class_name}]\n    \"\"\",\n)\n\ncfg_file_contents = textwrap.dedent(\n    \"\"\"\\\n        [CLI]\n        plugins = {plugin_name}\n    \"\"\",\n)\n\n\n@pytest.fixture\ndef simple_scenes_path():\n    return Path(__file__).parent / \"simple_scenes.py\"\n\n\ndef cfg_file_create(cfg_file_contents, path):\n    file_loc = (path / \"manim.cfg\").absolute()\n    file_loc.write_text(cfg_file_contents)\n    return file_loc\n\n\n@pytest.fixture\ndef random_string():\n    all_letters = string.ascii_lowercase\n    a = random.Random()\n    final_letters = [a.choice(all_letters) for _ in range(8)]\n    return \"\".join(final_letters)\n\n\ndef test_plugin_warning(tmp_path, python_version, simple_scenes_path):\n    cfg_file = cfg_file_create(\n        cfg_file_contents.format(plugin_name=\"DNEplugin\"),\n        tmp_path,\n    )\n    scene_name = \"SquareToCircle\"\n    command = [\n        python_version,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(cfg_file.parent),\n        \"--config_file\",\n        str(cfg_file),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command, cwd=str(cfg_file.parent))\n    assert exit_code == 0, err\n    assert \"Missing Plugins\" in out, \"Missing Plugins isn't in Output.\"\n\n\n@pytest.fixture\ndef create_plugin(tmp_path, python_version, random_string):\n    plugin_dir = tmp_path / \"plugin_dir\"\n    plugin_name = random_string\n\n    def _create_plugin(entry_point, class_name, function_name, all_dec=\"\"):\n        entry_point = entry_point.format(plugin_name=plugin_name)\n        module_dir = plugin_dir / plugin_name\n        module_dir.mkdir(parents=True, exist_ok=True)\n        (module_dir / \"__init__.py\").write_text(\n            plugin_init_template.format(\n                class_name=class_name,\n                function_name=function_name,\n                all_dec=all_dec,\n            ),\n        )\n        (plugin_dir / \"pyproject.toml\").write_text(\n            plugin_pyproject_template.format(\n                plugin_name=plugin_name,\n                plugin_entrypoint=entry_point,\n            ),\n        )\n        command = [\n            python_version,\n            \"-m\",\n            \"pip\",\n            \"install\",\n            str(plugin_dir.absolute()),\n        ]\n        out, err, exit_code = capture(command, cwd=str(plugin_dir))\n        print(out)\n        assert exit_code == 0, err\n        return {\n            \"module_dir\": module_dir,\n            \"plugin_name\": plugin_name,\n        }\n\n    yield _create_plugin\n    command = [python_version, \"-m\", \"pip\", \"uninstall\", plugin_name, \"-y\"]\n    out, err, exit_code = capture(command)\n    print(out)\n    assert exit_code == 0, err\n"
  },
  {
    "path": "tests/test_scene_rendering/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_scene_rendering/conftest.py",
    "content": "from __future__ import annotations\n\nfrom pathlib import Path\n\nimport pytest\n\n\n@pytest.fixture\ndef manim_cfg_file():\n    return Path(__file__).parent / \"manim.cfg\"\n\n\n@pytest.fixture\ndef simple_scenes_path():\n    return Path(__file__).parent / \"simple_scenes.py\"\n\n\n@pytest.fixture\ndef standard_config(config):\n    return config.digest_file(Path(__file__).parent.parent / \"standard_config.cfg\")\n\n\n@pytest.fixture\ndef using_temp_config(tmpdir, standard_config):\n    \"\"\"Standard fixture that makes tests use a standard_config.cfg with a temp dir.\"\"\"\n    standard_config.media_dir = tmpdir\n\n\n@pytest.fixture\ndef using_temp_opengl_config(tmpdir, standard_config, using_opengl_renderer):\n    \"\"\"Standard fixture that makes tests use a standard_config.cfg with a temp dir.\"\"\"\n    standard_config.media_dir = tmpdir\n\n\n@pytest.fixture\ndef disabling_caching(config):\n    config.disable_caching = True\n\n\n@pytest.fixture\ndef infallible_scenes_path():\n    return Path(__file__).parent / \"infallible_scenes.py\"\n\n\n@pytest.fixture\ndef force_window_config_write_to_movie(config):\n    config.force_window = True\n    config.write_to_movie = True\n\n\n@pytest.fixture\ndef force_window_config_pngs(config):\n    config.force_window = True\n    config.format = \"png\"\n"
  },
  {
    "path": "tests/test_scene_rendering/infallible_scenes.py",
    "content": "from __future__ import annotations\n\nfrom manim import Scene, Square\n\n\nclass Wait1(Scene):\n    def construct(self):\n        self.wait()\n\n\nclass Wait2(Scene):\n    def construct(self):\n        self.add(Square())\n\n\nclass Wait3(Scene):\n    def construct(self):\n        self.wait(2)\n"
  },
  {
    "path": "tests/test_scene_rendering/opengl/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_scene_rendering/opengl/test_caching_related_opengl.py",
    "content": "from __future__ import annotations\n\nimport sys\n\nimport pytest\n\nfrom manim import capture\n\nfrom ...utils.video_tester import video_comparison\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SceneWithMultipleWaitCallsWithNFlag.json\",\n    \"videos/simple_scenes/480p15/SceneWithMultipleWaitCalls.mp4\",\n)\ndef test_wait_skip(tmp_path, manim_cfg_file, simple_scenes_path):\n    # Test for PR #468. Intended to test if wait calls are correctly skipped.\n    scene_name = \"SceneWithMultipleWaitCalls\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"--write_to_movie\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-n\",\n        \"3\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SceneWithMultiplePlayCallsWithNFlag.json\",\n    \"videos/simple_scenes/480p15/SceneWithMultipleCalls.mp4\",\n)\ndef test_play_skip(tmp_path, manim_cfg_file, simple_scenes_path):\n    # Intended to test if play calls are correctly skipped.\n    scene_name = \"SceneWithMultipleCalls\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"--write_to_movie\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-n\",\n        \"3\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n"
  },
  {
    "path": "tests/test_scene_rendering/opengl/test_cli_flags_opengl.py",
    "content": "from __future__ import annotations\n\nimport sys\n\nimport numpy as np\nimport pytest\nfrom click.testing import CliRunner\nfrom PIL import Image\n\nfrom manim import capture, get_video_metadata\nfrom manim.__main__ import __version__, main\nfrom manim.utils.file_ops import add_version_before_extension\nfrom tests.utils.video_tester import video_comparison\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SquareToCircleWithDefaultValues.json\",\n    \"videos/simple_scenes/1080p60/SquareToCircle.mp4\",\n)\ndef test_basic_scene_with_default_values(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"--write_to_movie\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n\n@pytest.mark.slow\ndef test_resolution_flag(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"NoAnimations\"\n    # test different separators\n    resolutions = [\n        (720, 480, \";\"),\n        (1280, 720, \",\"),\n        (1920, 1080, \"-\"),\n        (2560, 1440, \";\"),\n        # (3840, 2160, \",\"),\n        # (640, 480, \"-\"),\n        # (800, 600, \";\"),\n    ]\n\n    for width, height, separator in resolutions:\n        command = [\n            sys.executable,\n            \"-m\",\n            \"manim\",\n            \"--media_dir\",\n            str(tmp_path),\n            \"--resolution\",\n            f\"{width}{separator}{height}\",\n            str(simple_scenes_path),\n            scene_name,\n        ]\n\n        _, err, exit_code = capture(command)\n        assert exit_code == 0, err\n\n        path = (\n            tmp_path / \"videos\" / \"simple_scenes\" / f\"{height}p60\" / f\"{scene_name}.mp4\"\n        )\n        meta = get_video_metadata(path)\n        assert (width, height) == (meta[\"width\"], meta[\"height\"])\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SquareToCircleWithlFlag.json\",\n    \"videos/simple_scenes/480p15/SquareToCircle.mp4\",\n)\ndef test_basic_scene_l_flag(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--write_to_movie\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SceneWithMultipleCallsWithNFlag.json\",\n    \"videos/simple_scenes/480p15/SceneWithMultipleCalls.mp4\",\n)\ndef test_n_flag(tmp_path, simple_scenes_path):\n    scene_name = \"SceneWithMultipleCalls\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--renderer\",\n        \"opengl\",\n        \"--write_to_movie\",\n        \"-n 3,6\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    _, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n\n@pytest.mark.slow\ndef test_s_flag_no_animations(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"NoAnimations\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"-s\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    exists = (tmp_path / \"videos\").exists()\n    assert not exists, \"running manim with -s flag rendered a video\"\n\n    is_empty = not any((tmp_path / \"images\" / \"simple_scenes\").iterdir())\n    assert not is_empty, \"running manim with -s flag did not render an image\"\n\n\n@pytest.mark.slow\ndef test_image_output_for_static_scene(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"StaticScene\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    exists = (tmp_path / \"videos\").exists()\n    assert not exists, \"running manim with static scene rendered a video\"\n\n    is_empty = not any((tmp_path / \"images\" / \"simple_scenes\").iterdir())\n    assert not is_empty, \"running manim without animations did not render an image\"\n\n\n@pytest.mark.slow\ndef test_no_image_output_with_interactive_embed(\n    tmp_path, manim_cfg_file, simple_scenes_path\n):\n    \"\"\"Check no image is output for a static scene when interactive embed is called\"\"\"\n    scene_name = \"InteractiveStaticScene\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    exists = (tmp_path / \"videos\").exists()\n    assert not exists, \"running manim with static scene rendered a video\"\n\n    is_empty = not any((tmp_path / \"images\" / \"simple_scenes\").iterdir())\n    assert is_empty, (\n        \"running manim static scene with interactive embed rendered an image\"\n    )\n\n\n@pytest.mark.slow\ndef test_no_default_image_output_with_non_static_scene(\n    tmp_path, manim_cfg_file, simple_scenes_path\n):\n    scene_name = \"SceneWithNonStaticWait\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    exists = (tmp_path / \"videos\").exists()\n    assert not exists, \"running manim with static scene rendered a video\"\n\n    is_empty = not any((tmp_path / \"images\" / \"simple_scenes\").iterdir())\n    assert is_empty, (\n        \"running manim static scene with interactive embed rendered an image\"\n    )\n\n\n@pytest.mark.slow\ndef test_image_output_for_static_scene_with_write_to_movie(\n    tmp_path, manim_cfg_file, simple_scenes_path\n):\n    scene_name = \"StaticScene\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--write_to_movie\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    is_empty = not any((tmp_path / \"videos\").iterdir())\n    assert not is_empty, \"running manim with static scene rendered a video\"\n\n    is_empty = not any((tmp_path / \"images\" / \"simple_scenes\").iterdir())\n    assert not is_empty, \"running manim without animations did not render an image\"\n\n\n@pytest.mark.slow\ndef test_s_flag(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"-s\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    exists = (tmp_path / \"videos\").exists()\n    assert not exists, \"running manim with -s flag rendered a video\"\n\n    is_empty = not any((tmp_path / \"images\" / \"simple_scenes\").iterdir())\n    assert not is_empty, \"running manim with -s flag did not render an image\"\n\n\n@pytest.mark.slow\ndef test_r_flag(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"-s\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-r\",\n        \"200,100\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    is_not_empty = any((tmp_path / \"images\").iterdir())\n    assert is_not_empty, \"running manim with -s, -r flag did not render a file\"\n\n    filename = add_version_before_extension(\n        tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle.png\",\n    )\n    assert np.asarray(Image.open(filename)).shape == (100, 200, 4)\n\n\n@pytest.mark.slow\ndef test_a_flag(tmp_path, manim_cfg_file, infallible_scenes_path):\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"--write_to_movie\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-a\",\n        str(infallible_scenes_path),\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    one_is_not_empty = (\n        tmp_path / \"videos\" / \"infallible_scenes\" / \"480p15\" / \"Wait1.mp4\"\n    ).is_file()\n    assert one_is_not_empty, \"running manim with -a flag did not render the first scene\"\n\n    two_is_not_empty = (\n        tmp_path / \"images\" / \"infallible_scenes\" / f\"Wait2_ManimCE_v{__version__}.png\"\n    ).is_file()\n    assert two_is_not_empty, (\n        \"running manim with -a flag did not render an image, possible leak of the config dictionary\"\n    )\n\n    three_is_not_empty = (\n        tmp_path / \"videos\" / \"infallible_scenes\" / \"480p15\" / \"Wait3.mp4\"\n    ).is_file()\n    assert three_is_not_empty, (\n        \"running manim with -a flag did not render the second scene\"\n    )\n\n\n@pytest.mark.slow\ndef test_custom_folders(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"-s\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--custom_folders\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    exists = (tmp_path / \"videos\").exists()\n    assert not exists, \"--custom_folders produced a 'videos/' dir\"\n\n    exists = add_version_before_extension(tmp_path / \"SquareToCircle.png\").exists()\n    assert exists, \"--custom_folders did not produce the output file\"\n\n\n@pytest.mark.slow\ndef test_dash_as_filename(tmp_path):\n    code = (\n        \"class Test(Scene):\\n\"\n        \"    def construct(self):\\n\"\n        \"        self.add(Circle())\\n\"\n        \"        self.wait()\"\n    )\n    command = [\n        \"-ql\",\n        \"--renderer\",\n        \"opengl\",\n        \"-s\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-\",\n    ]\n    runner = CliRunner()\n    result = runner.invoke(main, command, input=code)\n    assert result.exit_code == 0\n    exists = add_version_before_extension(\n        tmp_path / \"images\" / \"-\" / \"Test.png\",\n    ).exists()\n    assert exists, result.output\n\n\n@pytest.mark.slow\ndef test_gif_format_output(tmp_path, manim_cfg_file, simple_scenes_path):\n    \"\"\"Test only gif created with manim version in file name when --format gif is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"gif\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mp4\"\n    )\n    assert not unexpected_mp4_path.exists(), \"unexpected mp4 file found at \" + str(\n        unexpected_mp4_path,\n    )\n\n    expected_gif_path = add_version_before_extension(\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.gif\"\n    )\n    assert expected_gif_path.exists(), \"gif file not found at \" + str(expected_gif_path)\n\n\n@pytest.mark.slow\ndef test_mp4_format_output(tmp_path, manim_cfg_file, simple_scenes_path):\n    \"\"\"Test only mp4 created without manim version in file name when --format mp4 is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"mp4\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_gif_path = add_version_before_extension(\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.gif\"\n    )\n    assert not unexpected_gif_path.exists(), \"unexpected gif file found at \" + str(\n        unexpected_gif_path,\n    )\n\n    expected_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mp4\"\n    )\n    assert expected_mp4_path.exists(), \"expected mp4 file not found at \" + str(\n        expected_mp4_path,\n    )\n\n\n@pytest.mark.slow\ndef test_videos_not_created_when_png_format_set(\n    tmp_path,\n    manim_cfg_file,\n    simple_scenes_path,\n):\n    \"\"\"Test mp4 and gifs are not created when --format png is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"png\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_gif_path = add_version_before_extension(\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.gif\"\n    )\n    assert not unexpected_gif_path.exists(), \"unexpected gif file found at \" + str(\n        unexpected_gif_path,\n    )\n\n    unexpected_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mp4\"\n    )\n    assert not unexpected_mp4_path.exists(), \"expected mp4 file not found at \" + str(\n        unexpected_mp4_path,\n    )\n\n\n@pytest.mark.slow\ndef test_images_are_created_when_png_format_set(\n    tmp_path,\n    manim_cfg_file,\n    simple_scenes_path,\n):\n    \"\"\"Test images are created in media directory when --format png is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"png\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    expected_png_path = tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle0000.png\"\n    assert expected_png_path.exists(), \"png file not found at \" + str(expected_png_path)\n\n\n@pytest.mark.slow\ndef test_images_are_zero_padded_when_zero_pad_set(\n    tmp_path,\n    manim_cfg_file,\n    simple_scenes_path,\n):\n    \"\"\"Test images are zero padded when --format png and --zero_pad n are set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"png\",\n        \"--zero_pad\",\n        \"3\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_png_path = tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle0.png\"\n    assert not unexpected_png_path.exists(), \"non zero padded png file found at \" + str(\n        unexpected_png_path,\n    )\n\n    expected_png_path = tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle000.png\"\n    assert expected_png_path.exists(), \"png file not found at \" + str(expected_png_path)\n\n\n@pytest.mark.slow\ndef test_webm_format_output(tmp_path, manim_cfg_file, simple_scenes_path):\n    \"\"\"Test only webm created when --format webm is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"webm\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mp4\"\n    )\n    assert not unexpected_mp4_path.exists(), \"unexpected mp4 file found at \" + str(\n        unexpected_mp4_path,\n    )\n\n    expected_webm_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.webm\"\n    )\n    assert expected_webm_path.exists(), \"expected webm file not found at \" + str(\n        expected_webm_path,\n    )\n\n\n@pytest.mark.slow\ndef test_default_format_output_for_transparent_flag(\n    tmp_path,\n    manim_cfg_file,\n    simple_scenes_path,\n):\n    \"\"\"Test .mov is created by default when transparent flag is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--write_to_movie\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-t\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_webm_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.webm\"\n    )\n    assert not unexpected_webm_path.exists(), \"unexpected webm file found at \" + str(\n        unexpected_webm_path,\n    )\n\n    expected_mov_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mov\"\n    )\n    assert expected_mov_path.exists(), \"expected .mov file not found at \" + str(\n        expected_mov_path,\n    )\n\n\n@pytest.mark.slow\ndef test_mov_can_be_set_as_output_format(tmp_path, manim_cfg_file, simple_scenes_path):\n    \"\"\"Test .mov is created by when set using --format mov arg\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--renderer\",\n        \"opengl\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"mov\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_webm_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.webm\"\n    )\n    assert not unexpected_webm_path.exists(), \"unexpected webm file found at \" + str(\n        unexpected_webm_path,\n    )\n\n    expected_mov_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mov\"\n    )\n    assert expected_mov_path.exists(), \"expected .mov file not found at \" + str(\n        expected_mov_path,\n    )\n"
  },
  {
    "path": "tests/test_scene_rendering/opengl/test_opengl_renderer.py",
    "content": "from __future__ import annotations\n\nimport platform\nfrom unittest.mock import Mock\n\nimport numpy as np\nimport pytest\n\nfrom manim.renderer.opengl_renderer import OpenGLRenderer\nfrom tests.assert_utils import assert_file_exists\nfrom tests.test_scene_rendering.simple_scenes import *\n\n\ndef test_write_to_movie_disables_window(\n    config, using_temp_opengl_config, disabling_caching\n):\n    \"\"\"write_to_movie should disable window by default\"\"\"\n    scene = SquareToCircle()\n    renderer = scene.renderer\n    renderer.update_frame = Mock(wraps=renderer.update_frame)\n    scene.render()\n    assert renderer.window is None\n    assert_file_exists(config.output_file)\n\n\n@pytest.mark.skip(reason=\"Temporarily skip due to failing in Windows CI\")\ndef test_force_window_opengl_render_with_movies(\n    config,\n    using_temp_opengl_config,\n    force_window_config_write_to_movie,\n    disabling_caching,\n):\n    \"\"\"force_window creates window when write_to_movie is set\"\"\"\n    scene = SquareToCircle()\n    renderer = scene.renderer\n    renderer.update_frame = Mock(wraps=renderer.update_frame)\n    scene.render()\n    assert renderer.window is not None\n    assert_file_exists(config[\"output_file\"])\n    renderer.window.close()\n\n\n@pytest.mark.skipif(\n    platform.processor() == \"aarch64\", reason=\"Fails on Linux-ARM runners\"\n)\ndef test_force_window_opengl_render_with_format(\n    using_temp_opengl_config,\n    force_window_config_pngs,\n    disabling_caching,\n):\n    \"\"\"force_window creates window when format is set\"\"\"\n    scene = SquareToCircle()\n    renderer = scene.renderer\n    renderer.update_frame = Mock(wraps=renderer.update_frame)\n    scene.render()\n    assert renderer.window is not None\n    renderer.window.close()\n\n\ndef test_get_frame_with_preview_disabled(config, using_opengl_renderer):\n    \"\"\"Get frame is able to fetch frame with the correct dimensions when preview is disabled\"\"\"\n    config.preview = False\n\n    scene = SquareToCircle()\n    assert isinstance(scene.renderer, OpenGLRenderer)\n    assert not config.preview\n\n    renderer = scene.renderer\n    renderer.update_frame(scene)\n    frame = renderer.get_frame()\n\n    # height and width are flipped\n    assert renderer.get_pixel_shape()[0] == frame.shape[1]\n    assert renderer.get_pixel_shape()[1] == frame.shape[0]\n\n\n@pytest.mark.slow\ndef test_get_frame_with_preview_enabled(config, using_opengl_renderer):\n    \"\"\"Get frame is able to fetch frame with the correct dimensions when preview is enabled\"\"\"\n    config.preview = True\n\n    scene = SquareToCircle()\n    assert isinstance(scene.renderer, OpenGLRenderer)\n    assert config.preview is True\n\n    renderer = scene.renderer\n    renderer.update_frame(scene)\n    frame = renderer.get_frame()\n\n    # height and width are flipped\n    assert renderer.get_pixel_shape()[0] == frame.shape[1]\n    assert renderer.get_pixel_shape()[1] == frame.shape[0]\n\n\ndef test_pixel_coords_to_space_coords(config, using_opengl_renderer):\n    config.preview = True\n\n    scene = SquareToCircle()\n    assert isinstance(scene.renderer, OpenGLRenderer)\n\n    renderer = scene.renderer\n    renderer.update_frame(scene)\n\n    px, py = 3, 2\n    pw, ph = renderer.get_pixel_shape()\n    _, fh = renderer.camera.get_shape()\n    fc = renderer.camera.get_center()\n\n    ex = fc[0] + (fh / ph) * (px - pw / 2)\n    ey = fc[1] + (fh / ph) * (py - ph / 2)\n    ez = fc[2]\n\n    assert (\n        renderer.pixel_coords_to_space_coords(px, py) == np.array([ex, ey, ez])\n    ).all()\n    assert (\n        renderer.pixel_coords_to_space_coords(px, py, top_left=True)\n        == np.array([ex, -ey, ez])\n    ).all()\n"
  },
  {
    "path": "tests/test_scene_rendering/opengl/test_play_logic_opengl.py",
    "content": "from __future__ import annotations\n\nimport sys\nfrom unittest.mock import Mock\n\nimport pytest\n\nfrom manim import (\n    Scene,\n    ValueTracker,\n    np,\n)\n\nfrom ..simple_scenes import (\n    SceneForFrozenFrameTests,\n    SceneWithMultipleCalls,\n    SceneWithNonStaticWait,\n    SceneWithSceneUpdater,\n    SceneWithStaticWait,\n    SquareToCircle,\n)\n\n\n@pytest.mark.skipif(\n    sys.version_info < (3, 8),\n    reason=\"Mock object has a different implementation in python 3.7, which makes it broken with this logic.\",\n)\n@pytest.mark.parametrize(\"frame_rate\", argvalues=[15, 30, 60])\ndef test_t_values(config, using_temp_opengl_config, disabling_caching, frame_rate):\n    \"\"\"Test that the framerate corresponds to the number of t values generated\"\"\"\n    config.frame_rate = frame_rate\n    scene = SquareToCircle()\n    scene.update_to_time = Mock()\n    scene.render()\n    assert scene.update_to_time.call_count == config[\"frame_rate\"]\n    np.testing.assert_allclose(\n        ([call.args[0] for call in scene.update_to_time.call_args_list]),\n        np.arange(0, 1, 1 / config[\"frame_rate\"]),\n    )\n\n\ndef test_t_values_with_skip_animations(using_temp_opengl_config, disabling_caching):\n    \"\"\"Test the behaviour of scene.skip_animations\"\"\"\n    scene = SquareToCircle()\n    scene.update_to_time = Mock()\n    scene.renderer._original_skipping_status = True\n    scene.render()\n    assert scene.update_to_time.call_count == 1\n    np.testing.assert_almost_equal(\n        scene.update_to_time.call_args.args[0],\n        1.0,\n    )\n\n\ndef test_static_wait_detection(using_temp_opengl_config, disabling_caching):\n    \"\"\"Test if a static wait (wait that freeze the frame) is correctly detected\"\"\"\n    scene = SceneWithStaticWait()\n    scene.render()\n    # Test is is_static_wait of the Wait animation has been set to True by compile_animation_ata\n    assert scene.animations[0].is_static_wait\n    assert scene.is_current_animation_frozen_frame()\n\n\ndef test_non_static_wait_detection(using_temp_opengl_config, disabling_caching):\n    scene = SceneWithNonStaticWait()\n    scene.render()\n    assert not scene.animations[0].is_static_wait\n    assert not scene.is_current_animation_frozen_frame()\n    scene = SceneWithSceneUpdater()\n    scene.render()\n    assert not scene.animations[0].is_static_wait\n    assert not scene.is_current_animation_frozen_frame()\n\n\ndef test_frozen_frame(using_temp_opengl_config, disabling_caching):\n    scene = SceneForFrozenFrameTests()\n    scene.render()\n    assert scene.mobject_update_count == 0\n    assert scene.scene_update_count == 0\n\n\n@pytest.mark.xfail(reason=\"Should be fixed in #2133\")\ndef test_t_values_with_cached_data(using_temp_opengl_config):\n    \"\"\"Test the proper generation and use of the t values when an animation is cached.\"\"\"\n    scene = SceneWithMultipleCalls()\n    # Mocking the file_writer will skip all the writing process.\n    scene.renderer.file_writer = Mock(scene.renderer.file_writer)\n    # Simulate that all animations are cached.\n    scene.renderer.file_writer.is_already_cached.return_value = True\n    scene.update_to_time = Mock()\n\n    scene.render()\n    assert scene.update_to_time.call_count == 10\n\n\n@pytest.mark.xfail(reason=\"Not currently handled correctly for opengl\")\ndef test_t_values_save_last_frame(config, using_temp_opengl_config):\n    \"\"\"Test that there is only one t value handled when only saving the last frame\"\"\"\n    config.save_last_frame = True\n    scene = SquareToCircle()\n    scene.update_to_time = Mock()\n    scene.render()\n    scene.update_to_time.assert_called_once_with(1)\n\n\ndef test_animate_with_changed_custom_attribute(using_temp_opengl_config):\n    \"\"\"Test that animating the change of a custom attribute\n    using the animate syntax works correctly.\n    \"\"\"\n\n    class CustomAnimateScene(Scene):\n        def construct(self):\n            vt = ValueTracker(0)\n            vt.custom_attribute = \"hello\"\n            self.play(vt.animate.set_value(42).set(custom_attribute=\"world\"))\n            assert vt.get_value() == 42\n            assert vt.custom_attribute == \"world\"\n\n    CustomAnimateScene().render()\n"
  },
  {
    "path": "tests/test_scene_rendering/simple_scenes.py",
    "content": "from __future__ import annotations\n\nfrom enum import Enum\n\nfrom manim import *\n\n__all__ = [\n    \"SquareToCircle\",\n    \"SceneWithMultipleCalls\",\n    \"SceneWithMultipleWaitCalls\",\n    \"NoAnimations\",\n    \"SceneWithStaticWait\",\n    \"SceneWithSceneUpdater\",\n    \"SceneForFrozenFrameTests\",\n    \"SceneWithNonStaticWait\",\n    \"StaticScene\",\n    \"InteractiveStaticScene\",\n    \"SceneWithSections\",\n    \"ElaborateSceneWithSections\",\n]\n\n\nclass SquareToCircle(Scene):\n    def construct(self):\n        square = Square()\n        circle = Circle()\n        self.play(Transform(square, circle))\n\n\nclass SceneWithMultipleCalls(Scene):\n    def construct(self):\n        number = Integer(0)\n        self.add(number)\n        for _i in range(10):\n            self.play(Animation(Square()))\n\n\nclass SceneWithMultipleWaitCalls(Scene):\n    def construct(self):\n        self.play(Create(Square()))\n        self.wait(1)\n        self.play(Create(Square().shift(DOWN)))\n        self.wait(1)\n        self.play(Create(Square().shift(2 * DOWN)))\n        self.wait(1)\n        self.play(Create(Square().shift(3 * DOWN)))\n        self.wait(1)\n\n\nclass NoAnimations(Scene):\n    def construct(self):\n        dot = Dot().set_color(GREEN)\n        self.add(dot)\n        self.wait(0.1)\n\n\nclass SceneWithStaticWait(Scene):\n    def construct(self):\n        self.add(Square())\n        self.wait()\n\n\nclass SceneWithSceneUpdater(Scene):\n    def construct(self):\n        self.add(Square())\n        self.add_updater(lambda dt: 42)\n        self.wait()\n\n\nclass SceneForFrozenFrameTests(Scene):\n    def construct(self):\n        self.mobject_update_count = 0\n        self.scene_update_count = 0\n\n        def increment_mobject_update_count(mob, dt):\n            self.mobject_update_count += 1\n\n        def increment_scene_update_count(dt):\n            self.scene_update_count += 1\n\n        s = Square()\n        s.add_updater(increment_mobject_update_count)\n        self.add(s)\n        self.add_updater(increment_scene_update_count)\n\n        self.wait(frozen_frame=True)\n\n\nclass SceneWithNonStaticWait(Scene):\n    def construct(self):\n        s = Square()\n        # Non static wait are triggered by mobject with time based updaters.\n        s.add_updater(lambda mob, dt: None)\n        self.add(s)\n        self.wait()\n\n\nclass StaticScene(Scene):\n    def construct(self):\n        dot = Dot().set_color(GREEN)\n        self.add(dot)\n\n\nclass InteractiveStaticScene(Scene):\n    def construct(self):\n        dot = Dot().set_color(GREEN)\n        self.add(dot)\n        self.interactive_mode = True\n\n\nclass SceneWithSections(Scene):\n    def construct(self):\n        # this would be defined in a third party application using the segmented video API\n        class PresentationSectionType(str, Enum):\n            # start, end, wait for continuation by user\n            NORMAL = \"presentation.normal\"\n            # start, end, immediately continue to next section\n            SKIP = \"presentation.skip\"\n            # start, end, restart, immediately continue to next section when continued by user\n            LOOP = \"presentation.loop\"\n            # start, end, restart, finish animation first when user continues\n            COMPLETE_LOOP = \"presentation.complete_loop\"\n\n        # this animation is part of the first, automatically created section\n        self.wait()\n\n        self.next_section()\n        self.wait(2)\n\n        self.next_section(name=\"test\")\n        self.wait()\n\n        self.next_section(\n            \"Prepare For Unforeseen Consequences.\", DefaultSectionType.NORMAL\n        )\n        self.wait(2)\n\n        self.next_section(section_type=PresentationSectionType.SKIP)\n        self.wait()\n\n        self.next_section(\n            name=\"this section should be removed as it doesn't contain any animations\"\n        )\n\n\nclass ElaborateSceneWithSections(Scene):\n    def construct(self):\n        # the first automatically created section should be deleted <- it's empty\n        self.next_section(\"create square\")\n        square = Square()\n        self.play(FadeIn(square))\n        self.wait()\n\n        self.next_section(\"transform to circle\")\n        circle = Circle()\n        self.play(Transform(square, circle))\n        self.wait()\n\n        # this section will be entirely skipped\n        self.next_section(\"skipped animations section\", skip_animations=True)\n        circle = Circle()\n        self.play(Transform(square, circle))\n        self.wait()\n\n        self.next_section(\"fade out\")\n        self.play(FadeOut(square))\n        self.wait()\n\n\nclass SceneWithRandomness(Scene):\n    def construct(self):\n        dots = VGroup()\n        for _ in range(10):\n            dot = Dot(\n                point=np.random.uniform(-3, 3, size=3),  # noqa: NPY002\n            )\n            dots.add(dot)\n        self.add(dots)\n        self.wait()\n"
  },
  {
    "path": "tests/test_scene_rendering/test_caching_related.py",
    "content": "from __future__ import annotations\n\nimport sys\n\nimport pytest\n\nfrom manim import capture\n\nfrom ..utils.video_tester import *\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SceneWithMultipleWaitCallsWithNFlag.json\",\n    \"videos/simple_scenes/480p15/SceneWithMultipleWaitCalls.mp4\",\n)\ndef test_wait_skip(tmp_path, manim_cfg_file, simple_scenes_path):\n    # Test for PR #468. Intended to test if wait calls are correctly skipped.\n    scene_name = \"SceneWithMultipleWaitCalls\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-n\",\n        \"3\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SceneWithMultiplePlayCallsWithNFlag.json\",\n    \"videos/simple_scenes/480p15/SceneWithMultipleCalls.mp4\",\n)\ndef test_play_skip(tmp_path, manim_cfg_file, simple_scenes_path):\n    # Intended to test if play calls are correctly skipped.\n    scene_name = \"SceneWithMultipleCalls\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-n\",\n        \"3\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n"
  },
  {
    "path": "tests/test_scene_rendering/test_cairo_renderer.py",
    "content": "from __future__ import annotations\n\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom manim import *\n\nfrom ..assert_utils import assert_file_exists\nfrom .simple_scenes import *\n\n\ndef test_render(using_temp_config, disabling_caching):\n    scene = SquareToCircle()\n    renderer = scene.renderer\n    renderer.update_frame = Mock(wraps=renderer.update_frame)\n    renderer.add_frame = Mock(wraps=renderer.add_frame)\n    scene.render()\n    assert renderer.add_frame.call_count == config[\"frame_rate\"]\n    assert renderer.update_frame.call_count == config[\"frame_rate\"]\n    assert_file_exists(config[\"output_file\"])\n\n\ndef test_skipping_status_with_from_to_and_up_to(using_temp_config, disabling_caching):\n    \"\"\"Test if skip_animations is well updated when -n flag is passed\"\"\"\n    config.from_animation_number = 2\n    config.upto_animation_number = 6\n\n    class SceneWithMultipleCalls(Scene):\n        def construct(self):\n            number = Integer(0)\n            self.add(number)\n            for i in range(10):\n                self.play(Animation(Square()))\n\n                assert ((i >= 2) and (i <= 6)) or self.renderer.skip_animations\n\n    SceneWithMultipleCalls().render()\n\n\n@pytest.mark.xfail(reason=\"caching issue\")\ndef test_when_animation_is_cached(using_temp_config):\n    partial_movie_files = []\n    for _ in range(2):\n        # Render several times to generate a cache.\n        # In some edgy cases and on some OS, a same scene can produce\n        # a (finite, generally 2) number of different hash. In this case, the scene wouldn't be detected as cached, making the test fail.\n        scene = SquareToCircle()\n        scene.render()\n        partial_movie_files.append(scene.renderer.file_writer.partial_movie_files)\n    scene = SquareToCircle()\n    scene.update_to_time = Mock()\n    scene.render()\n    assert scene.renderer.file_writer.is_already_cached(\n        scene.renderer.animations_hashes[0],\n    )\n    # Check that the same partial movie files has been used (with he same hash).\n    # As there might have been several hashes, a list is used.\n    assert scene.renderer.file_writer.partial_movie_files in partial_movie_files\n    # Check that manim correctly skipped the animation.\n    scene.update_to_time.assert_called_once_with(1)\n    # Check that the output video has been generated.\n    assert_file_exists(config[\"output_file\"])\n\n\ndef test_hash_logic_is_not_called_when_caching_is_disabled(\n    using_temp_config,\n    disabling_caching,\n):\n    with patch(\"manim.renderer.cairo_renderer.get_hash_from_play_call\") as mocked:\n        scene = SquareToCircle()\n        scene.render()\n        mocked.assert_not_called()\n        assert_file_exists(config[\"output_file\"])\n\n\ndef test_hash_logic_is_called_when_caching_is_enabled(using_temp_config):\n    from manim.renderer.cairo_renderer import get_hash_from_play_call\n\n    with patch(\n        \"manim.renderer.cairo_renderer.get_hash_from_play_call\",\n        wraps=get_hash_from_play_call,\n    ) as mocked:\n        scene = SquareToCircle()\n        scene.render()\n        mocked.assert_called_once()\n"
  },
  {
    "path": "tests/test_scene_rendering/test_cli_flags.py",
    "content": "from __future__ import annotations\n\nimport sys\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\nfrom click.testing import CliRunner\nfrom PIL import Image\n\nfrom manim import capture, get_video_metadata\nfrom manim.__main__ import __version__, main\nfrom manim.utils.file_ops import add_version_before_extension\n\nfrom ..utils.video_tester import video_comparison\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SquareToCircleWithDefaultValues.json\",\n    \"videos/simple_scenes/1080p60/SquareToCircle.mp4\",\n)\ndef test_basic_scene_with_default_values(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n\n@pytest.mark.slow\ndef test_resolution_flag(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"NoAnimations\"\n    # test different separators\n    resolutions = [\n        (720, 480, \";\"),\n        (1280, 720, \",\"),\n        (1920, 1080, \"-\"),\n        (2560, 1440, \";\"),\n        # (3840, 2160, \",\"),\n        # (640, 480, \"-\"),\n        # (800, 600, \";\"),\n    ]\n\n    for width, height, separator in resolutions:\n        command = [\n            sys.executable,\n            \"-m\",\n            \"manim\",\n            \"--media_dir\",\n            str(tmp_path),\n            \"--resolution\",\n            f\"{width}{separator}{height}\",\n            str(simple_scenes_path),\n            scene_name,\n        ]\n\n        _, err, exit_code = capture(command)\n        assert exit_code == 0, err\n\n        path = (\n            tmp_path / \"videos\" / \"simple_scenes\" / f\"{height}p60\" / f\"{scene_name}.mp4\"\n        )\n        meta = get_video_metadata(path)\n        assert (width, height) == (meta[\"width\"], meta[\"height\"])\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SquareToCircleWithlFlag.json\",\n    \"videos/simple_scenes/480p15/SquareToCircle.mp4\",\n)\ndef test_basic_scene_l_flag(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SceneWithMultipleCallsWithNFlag.json\",\n    \"videos/simple_scenes/480p15/SceneWithMultipleCalls.mp4\",\n)\ndef test_n_flag(tmp_path, simple_scenes_path):\n    scene_name = \"SceneWithMultipleCalls\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"-n 3,6\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    _, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n\n@pytest.mark.slow\ndef test_s_flag_no_animations(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"NoAnimations\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"-s\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    exists = (tmp_path / \"videos\").exists()\n    assert not exists, \"running manim with -s flag rendered a video\"\n\n    is_empty = not any((tmp_path / \"images\" / \"simple_scenes\").iterdir())\n    assert not is_empty, \"running manim with -s flag did not render an image\"\n\n\n@pytest.mark.slow\ndef test_s_flag(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"-s\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    exists = (tmp_path / \"videos\").exists()\n    assert not exists, \"running manim with -s flag rendered a video\"\n\n    is_empty = not any((tmp_path / \"images\" / \"simple_scenes\").iterdir())\n    assert not is_empty, \"running manim with -s flag did not render an image\"\n\n\n@pytest.mark.slow\ndef test_s_flag_opengl_renderer(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"-s\",\n        \"--renderer\",\n        \"opengl\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    exists = (tmp_path / \"videos\").exists()\n    assert not exists, \"running manim with -s flag rendered a video\"\n\n    is_empty = not any((tmp_path / \"images\" / \"simple_scenes\").iterdir())\n    assert not is_empty, \"running manim with -s flag did not render an image\"\n\n\n@pytest.mark.slow\ndef test_r_flag(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"-s\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-r\",\n        \"200,100\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    is_not_empty = any((tmp_path / \"images\").iterdir())\n    assert is_not_empty, \"running manim with -s, -r flag did not render a file\"\n\n    filename = add_version_before_extension(\n        tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle.png\",\n    )\n    assert np.asarray(Image.open(filename)).shape == (100, 200, 4)\n\n\n@pytest.mark.slow\ndef test_a_flag(tmp_path, manim_cfg_file, infallible_scenes_path):\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-a\",\n        str(infallible_scenes_path),\n    ]\n    _, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    one_is_not_empty = (\n        tmp_path / \"videos\" / \"infallible_scenes\" / \"480p15\" / \"Wait1.mp4\"\n    ).is_file()\n    assert one_is_not_empty, \"running manim with -a flag did not render the first scene\"\n\n    two_is_not_empty = (\n        tmp_path / \"images\" / \"infallible_scenes\" / f\"Wait2_ManimCE_v{__version__}.png\"\n    ).is_file()\n    assert two_is_not_empty, (\n        \"running manim with -a flag did not render an image, possible leak of the config dictionary.\"\n    )\n\n    three_is_not_empty = (\n        tmp_path / \"videos\" / \"infallible_scenes\" / \"480p15\" / \"Wait3.mp4\"\n    ).is_file()\n    assert three_is_not_empty, (\n        \"running manim with -a flag did not render the second scene\"\n    )\n\n\n@pytest.mark.slow\ndef test_custom_folders(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"-s\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--custom_folders\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    exists = (tmp_path / \"videos\").exists()\n    assert not exists, \"--custom_folders produced a 'videos/' dir\"\n\n    exists = add_version_before_extension(tmp_path / \"SquareToCircle.png\").exists()\n    assert exists, \"--custom_folders did not produce the output file\"\n\n\n@pytest.mark.slow\ndef test_custom_output_name_gif(tmp_path, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    custom_name = \"custom_name\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format=gif\",\n        \"-o\",\n        custom_name,\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    wrong_gif_path = add_version_before_extension(\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / f\"{scene_name}.gif\"\n    )\n\n    assert not wrong_gif_path.exists(), (\n        \"The gif file does not respect the custom name: \" + custom_name + \".gif\"\n    )\n\n    unexpected_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / str(custom_name + \".mp4\")\n    )\n\n    assert not unexpected_mp4_path.exists(), \"Found an unexpected mp4 file at \" + str(\n        unexpected_mp4_path\n    )\n\n    expected_gif_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / str(custom_name + \".gif\")\n    )\n\n    assert expected_gif_path.exists(), \"gif file not found at \" + str(expected_gif_path)\n\n\n@pytest.mark.slow\ndef test_custom_output_name_mp4(tmp_path, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    custom_name = \"custom_name\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-o\",\n        custom_name,\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    wrong_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / str(scene_name + \".mp4\")\n    )\n\n    assert not wrong_mp4_path.exists(), (\n        \"The mp4 file does not respect the custom name: \" + custom_name + \".mp4\"\n    )\n\n    unexpected_gif_path = add_version_before_extension(\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / f\"{custom_name}.gif\"\n    )\n    assert not unexpected_gif_path.exists(), \"Found an unexpected gif file at \" + str(\n        unexpected_gif_path\n    )\n\n    expected_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / str(custom_name + \".mp4\")\n    )\n\n    assert expected_mp4_path.exists(), \"mp4 file not found at \" + str(expected_mp4_path)\n\n\n@pytest.mark.slow\ndef test_dash_as_filename(tmp_path):\n    code = (\n        \"class Test(Scene):\\n\"\n        \"    def construct(self):\\n\"\n        \"        self.add(Circle())\\n\"\n        \"        self.wait()\"\n    )\n    command = [\n        \"-ql\",\n        \"-s\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-\",\n    ]\n    runner = CliRunner()\n    result = runner.invoke(main, command, input=code)\n    assert result.exit_code == 0\n    exists = add_version_before_extension(\n        tmp_path / \"images\" / \"-\" / \"Test.png\",\n    ).exists()\n    assert exists, result.output\n\n\n@pytest.mark.slow\ndef test_gif_format_output(tmp_path, manim_cfg_file, simple_scenes_path):\n    \"\"\"Test only gif created with manim version in file name when --format gif is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"gif\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mp4\"\n    )\n    assert not unexpected_mp4_path.exists(), \"unexpected mp4 file found at \" + str(\n        unexpected_mp4_path,\n    )\n\n    expected_gif_path = add_version_before_extension(\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.gif\"\n    )\n    assert expected_gif_path.exists(), \"gif file not found at \" + str(expected_gif_path)\n\n\n@pytest.mark.slow\ndef test_mp4_format_output(tmp_path, manim_cfg_file, simple_scenes_path):\n    \"\"\"Test only mp4 created without manim version in file name when --format mp4 is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"mp4\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_gif_path = add_version_before_extension(\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.gif\"\n    )\n    assert not unexpected_gif_path.exists(), \"unexpected gif file found at \" + str(\n        unexpected_gif_path,\n    )\n\n    expected_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mp4\"\n    )\n    assert expected_mp4_path.exists(), \"expected mp4 file not found at \" + str(\n        expected_mp4_path,\n    )\n\n\n@pytest.mark.slow\ndef test_videos_not_created_when_png_format_set(\n    tmp_path,\n    manim_cfg_file,\n    simple_scenes_path,\n):\n    \"\"\"Test mp4 and gifs are not created when --format png is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"png\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_gif_path = add_version_before_extension(\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.gif\"\n    )\n    assert not unexpected_gif_path.exists(), \"unexpected gif file found at \" + str(\n        unexpected_gif_path,\n    )\n\n    unexpected_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mp4\"\n    )\n    assert not unexpected_mp4_path.exists(), \"expected mp4 file not found at \" + str(\n        unexpected_mp4_path,\n    )\n\n\n@pytest.mark.slow\ndef test_images_are_created_when_png_format_set(\n    tmp_path,\n    manim_cfg_file,\n    simple_scenes_path,\n):\n    \"\"\"Test images are created in media directory when --format png is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"png\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    expected_png_path = tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle0000.png\"\n    assert expected_png_path.exists(), \"png file not found at \" + str(expected_png_path)\n\n\n@pytest.mark.slow\ndef test_images_are_created_when_png_format_set_for_opengl(\n    tmp_path,\n    manim_cfg_file,\n    simple_scenes_path,\n):\n    \"\"\"Test images are created in media directory when --format png is set for opengl\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--renderer\",\n        \"opengl\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"png\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    expected_png_path = tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle0000.png\"\n    assert expected_png_path.exists(), \"png file not found at \" + str(expected_png_path)\n\n\n@pytest.mark.slow\ndef test_images_are_zero_padded_when_zero_pad_set(\n    tmp_path,\n    manim_cfg_file,\n    simple_scenes_path,\n):\n    \"\"\"Test images are zero padded when --format png and --zero_pad n are set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"png\",\n        \"--zero_pad\",\n        \"3\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_png_path = tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle0.png\"\n    assert not unexpected_png_path.exists(), \"non zero padded png file found at \" + str(\n        unexpected_png_path,\n    )\n\n    expected_png_path = tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle000.png\"\n    assert expected_png_path.exists(), \"png file not found at \" + str(expected_png_path)\n\n\n@pytest.mark.slow\ndef test_images_are_zero_padded_when_zero_pad_set_for_opengl(\n    tmp_path,\n    manim_cfg_file,\n    simple_scenes_path,\n):\n    \"\"\"Test images are zero padded when --format png and --zero_pad n are set with the opengl renderer\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--renderer\",\n        \"opengl\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"png\",\n        \"--zero_pad\",\n        \"3\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_png_path = tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle0.png\"\n    assert not unexpected_png_path.exists(), \"non zero padded png file found at \" + str(\n        unexpected_png_path,\n    )\n\n    expected_png_path = tmp_path / \"images\" / \"simple_scenes\" / \"SquareToCircle000.png\"\n    assert expected_png_path.exists(), \"png file not found at \" + str(expected_png_path)\n\n\n@pytest.mark.slow\ndef test_webm_format_output(tmp_path, manim_cfg_file, simple_scenes_path):\n    \"\"\"Test only webm created when --format webm is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"webm\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_mp4_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mp4\"\n    )\n    assert not unexpected_mp4_path.exists(), \"unexpected mp4 file found at \" + str(\n        unexpected_mp4_path,\n    )\n\n    expected_webm_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.webm\"\n    )\n    assert expected_webm_path.exists(), \"expected webm file not found at \" + str(\n        expected_webm_path,\n    )\n\n\n@pytest.mark.slow\ndef test_default_format_output_for_transparent_flag(\n    tmp_path,\n    manim_cfg_file,\n    simple_scenes_path,\n):\n    \"\"\"Test .mov is created by default when transparent flag is set\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"-t\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_webm_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.webm\"\n    )\n    assert not unexpected_webm_path.exists(), \"unexpected webm file found at \" + str(\n        unexpected_webm_path,\n    )\n\n    expected_mov_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mov\"\n    )\n    assert expected_mov_path.exists(), \"expected .mov file not found at \" + str(\n        expected_mov_path,\n    )\n\n\n@pytest.mark.slow\ndef test_mov_can_be_set_as_output_format(tmp_path, manim_cfg_file, simple_scenes_path):\n    \"\"\"Test .mov is created by when set using --format mov arg\"\"\"\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--format\",\n        \"mov\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    unexpected_webm_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.webm\"\n    )\n    assert not unexpected_webm_path.exists(), \"unexpected webm file found at \" + str(\n        unexpected_webm_path,\n    )\n\n    expected_mov_path = (\n        tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / \"SquareToCircle.mov\"\n    )\n    assert expected_mov_path.exists(), \"expected .mov file not found at \" + str(\n        expected_mov_path,\n    )\n\n\n@pytest.mark.slow\ndef test_reproducible_animation(tmp_path: Path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SceneWithRandomness\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--seed\",\n        \"42\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    first_path = tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\" / f\"{scene_name}.mp4\"\n\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        \"--seed\",\n        \"42\",\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    second_path = first_path.with_name(scene_name).with_suffix(\".mp4\")\n\n    with open(first_path, \"rb\") as f1, open(second_path, \"rb\") as f2:\n        first_data = f1.read()\n        second_data = f2.read()\n        assert first_data == second_data, \"Videos with the same seed differ.\"\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"InputFileViaCfg.json\",\n    \"videos/simple_scenes/480p15/SquareToCircle.mp4\",\n)\ndef test_input_file_via_cfg(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    (tmp_path / \"manim.cfg\").write_text(\n        f\"\"\"\n[CLI]\ninput_file = {simple_scenes_path}\n        \"\"\"\n    )\n\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        \".\",\n        str(tmp_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command, cwd=tmp_path)\n    assert exit_code == 0, err\n\n\n@pytest.mark.slow\ndef test_dry_run_via_config_file_no_output(tmp_path, simple_scenes_path):\n    \"\"\"Test that no file is created when dry_run is set to true in a config file.\"\"\"\n    scene_name = \"SquareToCircle\"\n    config_file = tmp_path / \"test_config.cfg\"\n    config_file.write_text(\n        \"\"\"\n[CLI]\ndry_run = true\n\"\"\"\n    )\n\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--config_file\",\n        str(config_file),\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    out, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    assert not (tmp_path / \"videos\").exists(), \"videos folder was created in dry_run\"\n    assert not (tmp_path / \"images\").exists(), \"images folder was created in dry_run\"\n"
  },
  {
    "path": "tests/test_scene_rendering/test_file_writer.py",
    "content": "import sys\nfrom fractions import Fraction\nfrom pathlib import Path\n\nimport av\nimport numpy as np\nimport pytest\n\nfrom manim import DR, Circle, Create, Scene, Star, tempconfig\nfrom manim.scene.scene_file_writer import to_av_frame_rate\nfrom manim.utils.commands import capture, get_video_metadata\n\n\nclass StarScene(Scene):\n    def construct(self):\n        circle = Circle(fill_opacity=1, color=\"#ff0000\")\n        circle.to_corner(DR).shift(DR)\n        self.add(circle)\n        star = Star()\n        self.play(Create(star))\n        click_path = (\n            Path(__file__).parent.parent.parent\n            / \"docs\"\n            / \"source\"\n            / \"_static\"\n            / \"click.wav\"\n        )\n        self.add_sound(click_path)\n        self.wait()\n\n\n@pytest.mark.slow\n@pytest.mark.parametrize(\n    \"transparent\",\n    [False, True],\n)\ndef test_gif_writing(config, tmp_path, transparent):\n    output_filename = f\"gif_{'transparent' if transparent else 'opaque'}\"\n    with tempconfig(\n        {\n            \"media_dir\": tmp_path,\n            \"quality\": \"low_quality\",\n            \"format\": \"gif\",\n            \"transparent\": transparent,\n            \"output_file\": output_filename,\n        }\n    ):\n        StarScene().render()\n\n    video_path = tmp_path / \"videos\" / \"480p15\" / f\"{output_filename}.gif\"\n    assert video_path.exists()\n    metadata = get_video_metadata(video_path)\n    # reported duration + avg_frame_rate is slightly off for gifs\n    del metadata[\"duration\"], metadata[\"avg_frame_rate\"]\n    target_metadata = {\n        \"width\": 854,\n        \"height\": 480,\n        \"nb_frames\": \"30\",\n        \"codec_name\": \"gif\",\n        \"pix_fmt\": \"bgra\",\n    }\n    assert metadata == target_metadata\n\n    with av.open(video_path) as container:\n        first_frame = next(container.decode(video=0))\n        frame_format = \"argb\" if transparent else \"rgb24\"\n        first_frame = first_frame.to_ndarray(format=frame_format)\n\n    target_rgba_corner = (\n        np.array([0, 255, 255, 255], dtype=np.uint8)\n        if transparent\n        else np.array([0, 0, 0], dtype=np.uint8)\n    )\n    np.testing.assert_array_equal(first_frame[0, 0], target_rgba_corner)\n\n    target_rgba_center = (\n        np.array([255, 255, 0, 0])  # components (A, R, G, B)\n        if transparent\n        else np.array([255, 0, 0], dtype=np.uint8)\n    )\n    np.testing.assert_allclose(first_frame[-1, -1], target_rgba_center, atol=5)\n\n\n@pytest.mark.slow\n@pytest.mark.parametrize(\n    (\"format\", \"transparent\", \"codec\", \"pixel_format\"),\n    [\n        (\"mp4\", False, \"h264\", \"yuv420p\"),\n        (\"mov\", False, \"h264\", \"yuv420p\"),\n        (\"mov\", True, \"qtrle\", \"argb\"),\n        (\"webm\", False, \"vp9\", \"yuv420p\"),\n        (\"webm\", True, \"vp9\", \"yuv420p\"),\n    ],\n)\ndef test_codecs(config, tmp_path, format, transparent, codec, pixel_format):\n    output_filename = f\"codec_{format}_{'transparent' if transparent else 'opaque'}\"\n    with tempconfig(\n        {\n            \"media_dir\": tmp_path,\n            \"quality\": \"low_quality\",\n            \"format\": format,\n            \"transparent\": transparent,\n            \"output_file\": output_filename,\n        }\n    ):\n        StarScene().render()\n\n    video_path = tmp_path / \"videos\" / \"480p15\" / f\"{output_filename}.{format}\"\n    assert video_path.exists()\n    metadata = get_video_metadata(video_path)\n    target_metadata = {\n        \"width\": 854,\n        \"height\": 480,\n        \"nb_frames\": \"30\",\n        \"duration\": \"2.000000\",\n        \"avg_frame_rate\": \"15/1\",\n        \"codec_name\": codec,\n        \"pix_fmt\": pixel_format,\n    }\n    assert metadata == target_metadata\n\n    with av.open(video_path) as container:\n        if transparent and format == \"webm\":\n            from av.codec.context import CodecContext\n\n            context = CodecContext.create(\"libvpx-vp9\", \"r\")\n            packet = next(container.demux(video=0))\n            first_frame = context.decode(packet)[0].to_ndarray(format=\"argb\")\n        else:\n            first_frame = next(container.decode(video=0)).to_ndarray()\n\n        has_samples = [\n            np.any(frame.to_ndarray()) for frame in container.decode(audio=0)\n        ]\n        assert any(has_samples), \"All audio samples are zero, this is not intended\"\n\n    target_rgba_corner = (\n        np.array([0, 0, 0, 0]) if transparent else np.array(16, dtype=np.uint8)\n    )\n    np.testing.assert_array_equal(first_frame[0, 0], target_rgba_corner)\n\n    target_rgba_center = (\n        np.array([255, 255, 0, 0])  # components (A, R, G, B)\n        if transparent\n        else np.array(240, dtype=np.uint8)\n    )\n    np.testing.assert_allclose(first_frame[-1, -1], target_rgba_center, atol=5)\n\n\ndef test_scene_with_non_raw_or_wav_audio(config, manim_caplog):\n    class SceneWithMP3(Scene):\n        def construct(self):\n            file_path = Path(__file__).parent / \"click.mp3\"\n            self.add_sound(file_path)\n            self.wait()\n\n    SceneWithMP3().render()\n    assert \"click.mp3 to .wav\" in manim_caplog.text\n\n\n@pytest.mark.slow\ndef test_unicode_partial_movie(config, tmpdir, simple_scenes_path):\n    # Characters that failed for a user on Windows\n    # due to its weird default encoding.\n    unicode_str = \"三角函数\"\n\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"--media_dir\",\n        str(tmpdir / unicode_str),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n\n    _, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n\ndef test_frame_rates():\n    assert to_av_frame_rate(25) == Fraction(25, 1)\n    assert to_av_frame_rate(24.0) == Fraction(24, 1)\n    assert to_av_frame_rate(23.976) == Fraction(24 * 1000, 1001)\n    assert to_av_frame_rate(23.98) == Fraction(24 * 1000, 1001)\n    assert to_av_frame_rate(59.94) == Fraction(60 * 1000, 1001)\n"
  },
  {
    "path": "tests/test_scene_rendering/test_play_logic.py",
    "content": "from __future__ import annotations\n\nimport sys\nfrom unittest.mock import Mock\n\nimport pytest\n\nfrom manim import (\n    Dot,\n    Mobject,\n    Scene,\n    ValueTracker,\n    Wait,\n    np,\n)\n\nfrom .simple_scenes import (\n    SceneForFrozenFrameTests,\n    SceneWithMultipleCalls,\n    SceneWithNonStaticWait,\n    SceneWithSceneUpdater,\n    SceneWithStaticWait,\n    SquareToCircle,\n)\n\n\n@pytest.mark.parametrize(\"frame_rate\", argvalues=[15, 30, 60])\ndef test_t_values(config, using_temp_config, disabling_caching, frame_rate):\n    \"\"\"Test that the framerate corresponds to the number of t values generated\"\"\"\n    config.frame_rate = frame_rate\n    scene = SquareToCircle()\n    scene.update_to_time = Mock()\n    scene.render()\n    assert scene.update_to_time.call_count == config[\"frame_rate\"]\n    np.testing.assert_allclose(\n        ([call.args[0] for call in scene.update_to_time.call_args_list]),\n        np.arange(0, 1, 1 / config[\"frame_rate\"]),\n    )\n\n\n@pytest.mark.skipif(\n    sys.version_info < (3, 8),\n    reason=\"Mock object has a different implementation in python 3.7, which makes it broken with this logic.\",\n)\ndef test_t_values_with_skip_animations(using_temp_config, disabling_caching):\n    \"\"\"Test the behaviour of scene.skip_animations\"\"\"\n    scene = SquareToCircle()\n    scene.update_to_time = Mock()\n    scene.renderer._original_skipping_status = True\n    scene.render()\n    assert scene.update_to_time.call_count == 1\n    np.testing.assert_almost_equal(\n        scene.update_to_time.call_args.args[0],\n        1.0,\n    )\n\n\ndef test_static_wait_detection(using_temp_config, disabling_caching):\n    \"\"\"Test if a static wait (wait that freeze the frame) is correctly detected\"\"\"\n    scene = SceneWithStaticWait()\n    scene.render()\n    # Test is is_static_wait of the Wait animation has been set to True by compile_animation_ata\n    assert scene.animations[0].is_static_wait\n    assert scene.is_current_animation_frozen_frame()\n\n\ndef test_non_static_wait_detection(using_temp_config, disabling_caching):\n    scene = SceneWithNonStaticWait()\n    scene.render()\n    assert not scene.animations[0].is_static_wait\n    assert not scene.is_current_animation_frozen_frame()\n    scene = SceneWithSceneUpdater()\n    scene.render()\n    assert not scene.animations[0].is_static_wait\n    assert not scene.is_current_animation_frozen_frame()\n\n\ndef test_wait_with_stop_condition(using_temp_config, disabling_caching):\n    class TestScene(Scene):\n        def construct(self):\n            self.wait_until(lambda: self.time >= 1)\n            assert self.time >= 1\n            d = Dot()\n            d.add_updater(lambda mobj, dt: self.add(Mobject()))\n            self.add(d)\n            self.play(Wait(run_time=5, stop_condition=lambda: len(self.mobjects) > 5))\n            assert len(self.mobjects) > 5\n            assert self.time < 2\n\n    scene = TestScene()\n    scene.render()\n\n\ndef test_frozen_frame(using_temp_config, disabling_caching):\n    scene = SceneForFrozenFrameTests()\n    scene.render()\n    assert scene.mobject_update_count == 0\n    assert scene.scene_update_count == 0\n\n\ndef test_t_values_with_cached_data(using_temp_config):\n    \"\"\"Test the proper generation and use of the t values when an animation is cached.\"\"\"\n    scene = SceneWithMultipleCalls()\n    # Mocking the file_writer will skip all the writing process.\n    scene.renderer.file_writer = Mock(scene.renderer.file_writer)\n    scene.renderer.update_skipping_status = Mock()\n    # Simulate that all animations are cached.\n    scene.renderer.file_writer.is_already_cached.return_value = True\n    scene.update_to_time = Mock()\n\n    scene.render()\n    assert scene.update_to_time.call_count == 10\n\n\ndef test_t_values_save_last_frame(config, using_temp_config):\n    \"\"\"Test that there is only one t value handled when only saving the last frame\"\"\"\n    config.save_last_frame = True\n    scene = SquareToCircle()\n    scene.update_to_time = Mock()\n    scene.render()\n    scene.update_to_time.assert_called_once_with(1)\n\n\ndef test_animate_with_changed_custom_attribute(using_temp_config):\n    \"\"\"Test that animating the change of a custom attribute\n    using the animate syntax works correctly.\n    \"\"\"\n\n    class CustomAnimateScene(Scene):\n        def construct(self):\n            vt = ValueTracker(0)\n            vt.custom_attribute = \"hello\"\n            self.play(vt.animate.set_value(42).set(custom_attribute=\"world\"))\n            assert vt.get_value() == 42\n            assert vt.custom_attribute == \"world\"\n\n    CustomAnimateScene().render()\n"
  },
  {
    "path": "tests/test_scene_rendering/test_sections.py",
    "content": "from __future__ import annotations\n\nimport sys\n\nimport pytest\n\nfrom manim import capture\nfrom tests.assert_utils import assert_dir_exists, assert_dir_not_exists\n\nfrom ..utils.video_tester import video_comparison\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SceneWithDisabledSections.json\",\n    \"videos/simple_scenes/480p15/SquareToCircle.mp4\",\n)\ndef test_no_sections(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    _, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    scene_dir = tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\"\n    assert_dir_exists(scene_dir)\n    assert_dir_not_exists(scene_dir / \"sections\")\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SceneWithEnabledSections.json\",\n    \"videos/simple_scenes/480p15/SquareToCircle.mp4\",\n)\ndef test_sections(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SquareToCircle\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--save_sections\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    _, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n    scene_dir = tmp_path / \"videos\" / \"simple_scenes\" / \"480p15\"\n    assert_dir_exists(scene_dir)\n    assert_dir_exists(scene_dir / \"sections\")\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SceneWithSections.json\",\n    \"videos/simple_scenes/480p15/SceneWithSections.mp4\",\n)\ndef test_many_sections(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"SceneWithSections\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--save_sections\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    _, err, exit_code = capture(command)\n    assert exit_code == 0, err\n\n\n@pytest.mark.slow\n@video_comparison(\n    \"SceneWithSkipAnimations.json\",\n    \"videos/simple_scenes/480p15/ElaborateSceneWithSections.mp4\",\n)\ndef test_skip_animations(tmp_path, manim_cfg_file, simple_scenes_path):\n    scene_name = \"ElaborateSceneWithSections\"\n    command = [\n        sys.executable,\n        \"-m\",\n        \"manim\",\n        \"-ql\",\n        \"--save_sections\",\n        \"--media_dir\",\n        str(tmp_path),\n        str(simple_scenes_path),\n        scene_name,\n    ]\n    _, err, exit_code = capture(command)\n    assert exit_code == 0, err\n"
  },
  {
    "path": "tests/utils/__init__.py",
    "content": ""
  },
  {
    "path": "tests/utils/logging_tester.py",
    "content": "from __future__ import annotations\n\nimport itertools\nimport json\nimport os\nfrom functools import wraps\nfrom pathlib import Path\n\nimport pytest\n\n\ndef _check_logs(reference_logfile_path: Path, generated_logfile_path: Path) -> None:\n    with reference_logfile_path.open() as reference_logfile:\n        reference_logs = reference_logfile.readlines()\n    with generated_logfile_path.open() as generated_logfile:\n        generated_logs = generated_logfile.readlines()\n    diff = abs(len(reference_logs) - len(generated_logs))\n    if len(reference_logs) != len(generated_logs):\n        msg_assert = \"\"\n        if len(reference_logs) > len(generated_logs):\n            msg_assert += f\"Logs generated are SHORTER than the expected logs. There are {diff} extra logs.\\n\"\n            msg_assert += \"Last log of the generated log is : \\n\"\n            msg_assert += generated_logs[-1]\n        else:\n            msg_assert += f\"Logs generated are LONGER than the expected logs.\\n There are {diff} extra logs :\\n\"\n            for log in generated_logs[len(reference_logs) :]:\n                msg_assert += log\n        msg_assert += f\"\\nPath of reference log: {reference_logfile}\\nPath of generated logs: {generated_logfile}\"\n        pytest.fail(msg_assert)\n\n    for index, ref, gen in zip(\n        itertools.count(), reference_logs, generated_logs, strict=False\n    ):\n        # As they are string, we only need to check if they are equal. If they are not, we then compute a more precise difference, to debug.\n        if ref == gen:\n            continue\n        ref_log = json.loads(ref)\n        gen_log = json.loads(gen)\n        diff_keys = [\n            d1[0]\n            for d1, d2 in zip(ref_log.items(), gen_log.items(), strict=False)\n            if d1[1] != d2[1]\n        ]\n        # \\n and \\t don't not work in f-strings.\n        newline = \"\\n\"\n        tab = \"\\t\"\n        assert len(diff_keys) == 0, (\n            f\"Logs don't match at {index} log. : \\n{newline.join([f'In {key} field, got -> {newline}{tab}{repr(gen_log[key])}. {newline}Expected : -> {newline}{tab}{repr(ref_log[key])}.' for key in diff_keys])}\"\n            + f\"\\nPath of reference log: {reference_logfile}\\nPath of generated logs: {generated_logfile}\"\n        )\n\n\ndef logs_comparison(\n    control_data_file: str | os.PathLike, log_path_from_media_dir: str | os.PathLike\n):\n    \"\"\"Decorator used for any test that needs to check logs.\n\n    Parameters\n    ----------\n    control_data_file\n        Name of the control data file, i.e. .log that will be compared to the outputted logs.\n        .. warning:: You don't have to pass the path here.\n        .. example:: \"SquareToCircleWithLFlag.log\"\n\n    log_path_from_media_dir\n        The path of the .log generated, from the media dir. Example: /logs/Square.log.\n\n    Returns\n    -------\n    Callable[[Any], Any]\n        The test wrapped with which we are going to make the comparison.\n    \"\"\"\n    control_data_file = Path(control_data_file)\n    log_path_from_media_dir = Path(log_path_from_media_dir)\n\n    def decorator(f):\n        @wraps(f)\n        def wrapper(*args, **kwargs):\n            # NOTE : Every args goes seemingly in kwargs instead of args; this is perhaps Pytest.\n            result = f(*args, **kwargs)\n            tmp_path = kwargs[\"tmp_path\"]\n            tests_directory = Path(__file__).absolute().parent.parent\n            control_data_path = (\n                tests_directory / \"control_data\" / \"logs_data\" / control_data_file\n            )\n            path_log_generated = tmp_path / log_path_from_media_dir\n            # The following will say precisely which subdir does not exist.\n            if not path_log_generated.exists():\n                for parent in reversed(path_log_generated.parents):\n                    if not parent.exists():\n                        pytest.fail(\n                            f\"'{parent.name}' does not exist in '{parent.parent}' (which exists). \",\n                        )\n                        break\n            _check_logs(control_data_path, path_log_generated)\n            return result\n\n        return wrapper\n\n    return decorator\n"
  },
  {
    "path": "tests/utils/test_polylabels.py",
    "content": "import numpy as np\nimport pytest\n\nfrom manim.utils.polylabel import Cell, Polygon, polylabel\n\n\n# Test simple square and square with a hole for inside/outside logic\n@pytest.mark.parametrize(\n    (\"rings\", \"inside_points\", \"outside_points\"),\n    [\n        (\n            # Simple square: basic convex polygon\n            [[[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]]],  # rings\n            [\n                [2, 2],\n                [1, 1],\n                [3.9, 3.9],\n                [0, 0],\n                [2, 0],\n                [0, 2],\n                [0, 4],\n                [4, 0],\n                [4, 2],\n                [2, 4],\n                [4, 4],\n            ],  # inside points\n            [[-1, -1], [5, 5], [4.1, 2]],  # outside points\n        ),\n        (\n            # Square with a square hole (donut shape): tests handling of interior voids\n            [\n                [[1, 1], [5, 1], [5, 5], [1, 5], [1, 1]],\n                [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]],\n            ],  # rings\n            [[1.5, 1.5], [3, 1.5], [1.5, 3]],  # inside points\n            [[3, 3], [6, 6], [0, 0]],  # outside points\n        ),\n        (\n            # Non-convex polygon (same shape as flags used in Brazilian june festivals)\n            [[[0, 0], [2, 2], [4, 0], [4, 4], [0, 4], [0, 0]]],  # rings\n            [[1, 3], [3.9, 3.9], [2, 3.5]],  # inside points\n            [\n                [0.1, 0],\n                [1, 0],\n                [2, 0],\n                [2, 1],\n                [2, 1.9],\n                [3, 0],\n                [3.9, 0],\n            ],  # outside points\n        ),\n    ],\n)\ndef test_polygon_inside_outside(rings, inside_points, outside_points):\n    polygon = Polygon(rings)\n    for point in inside_points:\n        assert polygon.inside(point)\n\n    for point in outside_points:\n        assert not polygon.inside(point)\n\n\n# Test distance calculation with known expected distances\n@pytest.mark.parametrize(\n    (\"rings\", \"points\", \"expected_distance\"),\n    [\n        (\n            [[[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]]],  # rings\n            [[2, 2]],  # points\n            2.0,  # Distance from center to closest edge in square\n        ),\n        (\n            [[[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]]],  # rings\n            [[0, 0], [2, 0], [4, 2], [2, 4], [0, 2]],  # points\n            0.0,  # On the edge\n        ),\n        (\n            [[[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]]],  # rings\n            [[5, 5]],  # points\n            -np.sqrt(2),  # Outside and diagonally offset\n        ),\n    ],\n)\ndef test_polygon_compute_distance(rings, points, expected_distance):\n    polygon = Polygon(rings)\n    for point in points:\n        result = polygon.compute_distance(np.array(point))\n        assert pytest.approx(result, rel=1e-3) == expected_distance\n\n\n@pytest.mark.parametrize(\n    (\"center\", \"h\", \"rings\"),\n    [\n        (\n            [2, 2],  # center\n            1.0,  # h\n            [[[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]]],  # rings\n        ),\n        (\n            [3, 1.5],  # center\n            0.5,  # h\n            [\n                [[1, 1], [5, 1], [5, 5], [1, 5], [1, 1]],\n                [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]],\n            ],  # rings\n        ),\n    ],\n)\ndef test_cell(center, h, rings):\n    polygon = Polygon(rings)\n    cell = Cell(center, h, polygon)\n    assert isinstance(cell.d, float)\n    assert isinstance(cell.p, float)\n    assert np.allclose(cell.c, center)\n    assert cell.h == h\n\n    other = Cell(np.add(center, [0.1, 0.1]), h, polygon)\n    assert (cell < other) == (cell.d < other.d)\n    assert (cell > other) == (cell.d > other.d)\n    assert (cell <= other) == (cell.d <= other.d)\n    assert (cell >= other) == (cell.d >= other.d)\n\n\n@pytest.mark.parametrize(\n    (\"rings\", \"expected_centers\"),\n    [\n        (\n            # Simple square: basic convex polygon\n            [[[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]]],\n            [[2.0, 2.0]],  # single correct pole of inaccessibility\n        ),\n        (\n            # Square with a square hole (donut shape): tests handling of interior voids\n            [\n                [[1, 1], [5, 1], [5, 5], [1, 5], [1, 1]],\n                [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]],\n            ],\n            [  # any of the four pole of inaccessibility options\n                [1.5, 1.5],\n                [1.5, 4.5],\n                [4.5, 1.5],\n                [4.5, 4.5],\n            ],\n        ),\n    ],\n)\ndef test_polylabel(rings, expected_centers):\n    # Add third dimension to conform to polylabel input format\n    rings_3d = [np.column_stack([ring, np.zeros(len(ring))]) for ring in rings]\n    result = polylabel(rings_3d, precision=0.01)\n\n    assert isinstance(result, Cell)\n    assert result.h <= 0.01\n    assert result.d >= 0.0\n\n    match_found = any(np.allclose(result.c, ec, atol=0.1) for ec in expected_centers)\n    assert match_found, f\"Expected one of {expected_centers}, but got {result.c}\"\n"
  },
  {
    "path": "tests/utils/testing_utils.py",
    "content": "from __future__ import annotations\n\nimport inspect\nimport sys\n\n\ndef get_scenes_to_test(module_name: str):\n    \"\"\"Get all Test classes of the module from which it is called. Used to fetch all the SceneTest of the module.\n\n    Parameters\n    ----------\n    module_name\n        The name of the module tested.\n\n    Returns\n    -------\n    List[:class:`type`]\n        The list of all the classes of the module.\n    \"\"\"\n    return inspect.getmembers(\n        sys.modules[module_name],\n        lambda m: inspect.isclass(m) and m.__module__ == module_name,\n    )\n"
  },
  {
    "path": "tests/utils/video_tester.py",
    "content": "from __future__ import annotations\n\nimport json\nimport os\nfrom functools import wraps\nfrom pathlib import Path\nfrom typing import Any\n\nfrom manim import get_video_metadata\n\nfrom ..assert_utils import assert_shallow_dict_compare\nfrom ..helpers.video_utils import get_section_dir_layout, get_section_index\n\n\ndef load_control_data(path_to_data: Path) -> Any:\n    with path_to_data.open() as f:\n        return json.load(f)\n\n\ndef check_video_data(path_control_data: Path, path_video_gen: Path) -> None:\n    \"\"\"Compare control data with generated output.\n    Used abbreviations:\n        exp  -> expected\n        gen  -> generated\n        sec  -> section\n        meta -> metadata\n    \"\"\"\n    # movie file specification\n    path_sec_gen = path_video_gen.parent.absolute() / \"sections\"\n    control_data = load_control_data(path_control_data)\n    movie_meta_gen = get_video_metadata(path_video_gen)\n    movie_meta_exp = control_data[\"movie_metadata\"]\n\n    assert_shallow_dict_compare(\n        movie_meta_gen, movie_meta_exp, \"Movie file metadata mismatch:\"\n    )\n\n    # sections directory layout\n    sec_dir_layout_gen = set(get_section_dir_layout(path_sec_gen))\n    sec_dir_layout_exp = set(control_data[\"section_dir_layout\"])\n\n    unexp_gen = sec_dir_layout_gen - sec_dir_layout_exp\n    ungen_exp = sec_dir_layout_exp - sec_dir_layout_gen\n    if len(unexp_gen) or len(ungen_exp):\n        dif = [f\"'{dif}' got unexpectedly generated\" for dif in unexp_gen] + [\n            f\"'{dif}' didn't get generated\" for dif in ungen_exp\n        ]\n        mismatch = \"\\n\".join(dif)\n        raise AssertionError(f\"Sections don't match:\\n{mismatch}\")\n\n    # sections index file\n    scene_name = path_video_gen.stem\n    path_sec_index_gen = path_sec_gen / f\"{scene_name}.json\"\n    sec_index_gen = get_section_index(path_sec_index_gen)\n    sec_index_exp = control_data[\"section_index\"]\n\n    if len(sec_index_gen) != len(sec_index_exp):\n        raise AssertionError(\n            f\"expected {len(sec_index_exp)} sections ({', '.join([el['name'] for el in sec_index_exp])}), but {len(sec_index_gen)} ({', '.join([el['name'] for el in sec_index_gen])}) got generated (in '{path_sec_index_gen}')\"\n        )\n    # check individual sections\n    for sec_gen, sec_exp in zip(sec_index_gen, sec_index_exp, strict=True):\n        assert_shallow_dict_compare(\n            sec_gen,\n            sec_exp,\n            # using json to pretty print dicts\n            f\"Section {json.dumps(sec_gen, indent=4)} (in '{path_sec_index_gen}') doesn't match expected Section (in '{json.dumps(sec_exp, indent=4)}'):\",\n        )\n\n\ndef video_comparison(\n    control_data_file: str | os.PathLike, scene_path_from_media_dir: str | os.PathLike\n):\n    \"\"\"Decorator used for any test that needs to check a rendered scene/video.\n\n    .. warning::\n        The directories, such as the movie dir or sections dir, are expected to abide by the default.\n        This requirement could be dropped if the manim config were to be accessible from ``wrapper`` like in ``frames_comparison.py``.\n\n    Parameters\n    ----------\n    control_data_file\n        Name of the control data file, i.e. the .json containing all the pre-rendered references of the scene tested.\n        .. warning:: You don't have to pass the path here.\n\n    scene_path_from_media_dir\n        The path of the scene generated, from the media dir. Example: /videos/1080p60/SquareToCircle.mp4.\n\n    See Also\n    --------\n    tests/helpers/video_utils.py : create control data\n    \"\"\"\n    control_data_file = Path(control_data_file)\n    scene_path_from_media_dir = Path(scene_path_from_media_dir)\n\n    def decorator(f):\n        @wraps(f)\n        def wrapper(*args, **kwargs):\n            # NOTE : Every args goes seemingly in kwargs instead of args; this is perhaps Pytest.\n            result = f(*args, **kwargs)\n            tmp_path = kwargs[\"tmp_path\"]\n            tests_directory = Path(__file__).absolute().parent.parent\n            path_control_data = (\n                tests_directory / \"control_data\" / \"videos_data\" / control_data_file\n            )\n            path_video_gen = tmp_path / scene_path_from_media_dir\n            if not path_video_gen.exists():\n                for parent in reversed(path_video_gen.parents):\n                    if not parent.exists():\n                        raise AssertionError(\n                            f\"'{parent.name}' does not exist in '{parent.parent}' (which exists). \",\n                        )\n            # TODO: use when pytest --set_test option\n            # save_control_data_from_video(path_video_gen, control_data_file.stem)\n            check_video_data(path_control_data, path_video_gen)\n            return result\n\n        return wrapper\n\n    return decorator\n"
  }
]