Skip to main content

Manim Vision: spatial collision intelligence for Manim scenes.

Project description

Manim Vision

Manim Vision adds production-oriented 2D spatial collision awareness to Manim Community scenes. It tracks VMobject geometry in the background, detects overlaps with Shapely and a STRtree broad phase, and emits JSON “spatial health” reports (with suggested shift(...) fix strings) to help you find unintentional object overlap while you build animations.

PyPI pip install manim-vision
Python 3.10, 3.11, or 3.12
License MIT

Table of contents


What it does

  • Hooks your live Scene so add, play, and remove participate in a collision pipeline (via a dynamically merged mixin; your scene class is unchanged at import time).
  • Tracks every visible leaf VMobject in the mobject family of each add() call (e.g. each Square and Text inside a VGroup — not only the group’s root), then refreshes that geometry from live point data after each play, so overlaps between siblings (arrow vs cell, two boxes, label vs shape, …) are seen by the 2D engine.
  • Wraps each root mobject in add with a transparent proxy that refreshes stored geometry when you call common spatial methods on the root only (shift, scale, rotate, move_to, next_to, align_to, set_x / set_y / set_z, stretch, apply_matrix, apply_function); submobject motion is still captured in the per-play resync.
  • Detects pairwise overlaps using Shapely (narrow phase, with DE-9IM / intersection area) on top of a Shapely STRtree for broad phase.
  • Relaxes overlapping pairs with an internal force-based iteration and computes MTV-style separation hints (ConstraintSolver).
  • Emits a check digest (one JSON per play by default) to media/manim_vision/<SceneName>_check_digest.jsonl, with optional per-collision Schema-validated JSONL when you set MANIM_VISION_PER_PAIR_JSONL=1 (see Telemetry output).

Collision work runs on a dedicated single-worker thread pool so the main animation thread is not blocked by geometry queries.


Installation

pip install manim-vision

Dependencies are declared in pyproject.toml and include at least: manim, shapely, wrapt, numpy, and jsonschema.


Quick start

Call ManimVision.monitor(self) early in construct() (after you have a real Scene instance). Use your scene as usual: add, play, and remove are instrumented automatically.

from manim import BLUE, RED, Create, Circle, Scene, Square
from manim_vision import ManimVision


class MyScene(Scene):
    def construct(self):
        ManimVision.monitor(self)

        a = Circle(radius=1, color=BLUE)
        b = Square(side_length=1.2, color=RED)
        b.next_to(a, RIGHT, buff=0)  # may overlap — reported if so

        self.add(a, b)
        self.play(Create(a), Create(b))

        ManimVision.shutdown(self)  # recommended: see below

Lazy import: manim_vision loads lightweight symbols (ManimVisionError, etc.) immediately; ManimVision is loaded from manim_vision.core the first time you access it, so imports stay cheap when Manim is not yet needed.


Shutting down cleanly

ManimVision.shutdown(self) (or the mixin’s shutdown() on the scene) waits for queued collision jobs and shuts down the worker thread pool before the scene / process tears down. Use it at the end of construct() or after your last add / play in long or scripted runs to avoid pending work or pool warnings at exit.


How it works (architecture)

  1. ManimVision.monitor(scene) checks that scene is a Manim Scene, then attaches an engine, solver, telemetry dispatcher, registry lock, and executor to the instance. It rebases scene.__class__ to a new type that prepends ManimVisionSceneMixin in the MRO so add / play / remove are overridden while the rest of your class behaves as before.
  2. add wraps each VMobject in a ManimVisionMobjectProxy, which registers it with PrecisionGeometryEngine and updates geometry after spatial mutators.
  3. After add and play, a collision check is submitted to the executor. Under the scene lock, the engine checks collisions, the solver applies relaxation and MTV math, and the TelemetryDispatcher writes JSON to the configured stream (default stdout).
  4. remove deregisters mobjects from the engine’s registry.

Internal pieces (for reading the code or building on top of the library):

Component Role
GeometryAdapter Converts VMobject outlines to Shapely geometry (with validation / error handling).
PrecisionGeometryEngine Registry, STRtree queries, CollisionResult build-out.
ConstraintSolver MTV / SAT-style hints, force relaxation, shift(...) fix string generation.
TelemetryDispatcher Builds payloads, validates against JSON Schema, writes JSON lines.

Telemetry output

By default, Manim Vision appends to files under your Manim media tree (see config.media_dir, often ./media):

  • media/manim_vision/<SceneName>_check_digest.jsonlone JSON object per play collision check (intended for LLM feedback and self-iterating scripts). It includes suppressed hit counts, actionable_merged (one entry per semantic pair, keeping the maximum overlap area in that play), and suggested fix_suggestion / resolution_mtv for that representative. This is the main volume-efficient channel.
  • media/manim_vision/<SceneName>_spatial.jsonllegacy per-collision JSONL (Schema-validated) only when you set MANIM_VISION_PER_PAIR_JSONL=1. Otherwise it stays unused so huge scenes do not emit tens of thousands of near-duplicate lines.
  • media/manim_vision/<SceneName>_spatial_log.txt — a one-line digest summary for each play check; the older multi-line per-collision blocks are written only in per-pair mode (same env var).

Override the directory with MANIM_VISION_REPORT_DIR, or set MANIM_VISION_REPORT_STDOUT=1 to also print pretty JSON to the terminal. When running tests or passing a custom StringIO to TelemetryDispatcher, the pretty JSON still goes to that stream only (no files).

The payload fields are such as:

  • timestamp — ISO-8601 UTC
  • scene_name — Sanitized scene class name
  • error_type — e.g. OVERLAP (see schema for allowed values)
  • colliding_entities — String labels ClassName_id for the two mobjects
  • overlap_area — Positive float in world units²
  • resolution_mtvx, y, z components (2D analysis uses z: 0)
  • fix_suggestion — Suggested Manim code, often chained shift(UP * …).shift(RIGHT * …) style

The contract is defined in code as MANIM_VISION_SPATIAL_REPORT_SCHEMA in manim_vision/telemetry/schema.py. Invalid payloads raise ManimVisionSchemaError. Report file handles are closed when you call ManimVision.shutdown(self) (or the scene’s shutdown()).

Geometry “skips” (Text with no points yet, empty Mobject, etc.) are expected in many Manim scripts. They are logged at DEBUG by default so the console is not spammed. Set MANIM_VISION_VERBOSE_GEO=1 if you need every skip at WARNING when debugging the adapter.

Readable volume (LLM- and log-friendly):

  • Check digest (default) — one row per play in *_check_digest.jsonl; collisions are grouped by the same semantic pair of labels, so repeated frames of the same mistake do not multiply rows. Set MANIM_VISION_PER_PAIR_JSONL=1 only if you need the full schema-per-pair *_spatial.jsonl for tooling that expects it.
  • Intentional layout (not reported as actionable): a Text / MathTex mobject that is a submobject of a VGroup / Square (number-in-cell, labels inside a frame) and sibling Square+Text in a small VGroup (tile cells) are treated as designed overlap, not bugs.
  • Session deduplication (for per-pair mode only, default for file output): the same semantic pair of entities is written once per render to *_spatial.jsonl; disable with MANIM_VISION_DISABLE_SESSION_DEDUPE=1.
  • Minimum overlap areaMANIM_VISION_MIN_OVERLAP_AREA (default 0.0001 world units²) drops dust-sized intersections from SVG/anti-aliasing.
  • Same-Text kerning — adjacent glyph path overlaps inside one Text / MathTex string are ignored (not layout errors).
  • Entity names in reports are broad where possible, e.g. Text("Binary Search")#… or VGroup#…, not per-glyph VMobjectFromSVGPath_… ids.
  • The terminal logs a short INFO line for each play spatial check: digest-only vs per-pair, counts of suppressed and actionable groups.

Public API and exceptions

Entry points

  • manim_vision.ManimVisionmonitor(scene), shutdown(scene).

Exceptions (re-exported from manim_vision)

Exception Meaning
ManimVisionError Base error (e.g. monitor() given a non-Scene).
ManimVisionGeometryError VMobject could not be turned into valid geometry.
ManimVisionSchemaError Telemetry payload failed JSON Schema validation.
ManimVisionProxyError Reserved for proxy/instrumentation failures.

Lower-level types (used in tests and extensions) live under manim_vision.geometry, manim_vision.proxy, manim_vision.solver, and manim_vision.telemetry — e.g. ManimVisionSceneProxy, PrecisionGeometryEngine, CollisionResult, ConstraintSolver, TelemetryDispatcher.


Design notes and limitations

  • 2D-style analysis in the engine: separation vectors use xy; mobjects are approximated for outline overlap in the scene plane. Not a full 3D physics engine.
  • VMobject-oriented: tracking is built around vectorized mobjects; exotic object types may not register or may log conversion warnings.
  • Touches vs overlap: pairs that only touch (zero area) are filtered out; positive overlap area is what triggers a report.
  • Heavier geometry (e.g. concave shapes) may use centroid / convex-hull fallbacks in the solver; see ConstraintSolver docstrings and implementation for details.
  • The library aims to be non-invasive: it does not replace your self reference; it only replaces the runtime class of the scene object to install hooks.
  • Manim’s copy.deepcopy and helpers (used when building many animations) walk each mobject’s __dict__. Internals that hold a threading.Lock (e.g. the geometry engine) must not be stored on the underlying VMobject. Manim Vision keeps that state on the wrapt proxy and implements __deepcopy__ on ManimVisionMobjectProxy / ManimVisionSceneProxy so creation-style animations (FadeIn, Transform, etc.) do not fail with TypeError: cannot pickle '_thread.lock' object.

Development

From a checkout of the package root (the directory that contains pyproject.toml):

python -m venv .venv
.venv\Scripts\activate          # Windows
# source .venv/bin/activate     # macOS / Linux

pip install -e ".[dev]"
python -m pytest

Run Ruff or your usual formatter if you keep them in the project; tests use pytest with asyncio mode as configured in pyproject.toml.


License

MIT — see the LICENSE file in this repository.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

manim_vision-0.1.6.tar.gz (31.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

manim_vision-0.1.6-py3-none-any.whl (33.1 kB view details)

Uploaded Python 3

File details

Details for the file manim_vision-0.1.6.tar.gz.

File metadata

  • Download URL: manim_vision-0.1.6.tar.gz
  • Upload date:
  • Size: 31.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for manim_vision-0.1.6.tar.gz
Algorithm Hash digest
SHA256 a6b7c62a4292a53d910b1649fb63092f1c14e13dca359c60ae0dd61c853926f9
MD5 8c2e64429f12a6e8824fbf5c7f3d6b4b
BLAKE2b-256 6a2617e7050ef9260151d267b8a0241bb5a8dd358c27231c94babdb98f939f19

See more details on using hashes here.

File details

Details for the file manim_vision-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: manim_vision-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 33.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for manim_vision-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 1f9b2f926dccd8f2865193fef7a85dfe368920506c8631166fa3a22353c47a92
MD5 52364e768a54cd66ef2b50893b51ecde
BLAKE2b-256 39bf6fa4fc9442e7b098b418e2c954bcc4ca775eae1d8217f9774201f11bde34

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page