Camera Control & Viewport Framing
Animora provides a camera convenience wrapper (animora.core.Camera) built on top of Manim's MovingCameraScene. It offers semantic viewport manipulation with automated bounding-box calculation, smooth multi-object framing, target tracking, and reset transitions.
1. Quick Start
To enable dynamic camera movements in your animations, subclass MovingCameraScene and instantiate Camera(self):
from animora.core import MovingCameraScene, Camera
from animora.datastructures import Array
from animora.theme import ModernDark, use_theme
class CameraDemoScene(MovingCameraScene):
def construct(self) -> None:
with use_theme(ModernDark):
arr = Array([10, 20, 30, 40, 50, 60, 70, 80])
self.play(arr.animate_create())
cam = Camera(self)
# 1. Focus onto a specific subarray or element
cam.focus(arr, scale=0.7, run_time=1.5)
# 2. Reset back to the default wide viewport
cam.reset(run_time=1.2)
2. Core Camera Operations
camera.focus(target, scale=1.0, run_time=1.0, rate_func=...)
Smoothly animates the camera frame to center on target (either an Animora Component or a Manim Mobject).
- target: The element to center the viewport on.
- scale: Zoom multiplier. Values $< 1.0$ zoom in closer; values $> 1.0$ zoom out.
# Zoom in tightly on the 4th array element
target_box = arr.get_cell(3)
cam.focus(target_box, scale=0.5, run_time=1.0)
camera.fit(targets, padding=0.5, run_time=1.0, rate_func=...)
Dynamically computes the joint bounding box enclosing a list of objects and fits the viewport around them with clean padding.
camera.follow(target, auto_update=True) & camera.unfollow()
Locks the camera's center position to follow a moving target.
- auto_update=True: Attaches an updater callback that pans the camera in real time as the target moves across the screen.
- Call cam.unfollow() to detach the updater when target tracking is complete.
# Follow a node moving through a graph traversal
cam.follow(active_node)
self.play(active_node.animate.shift([3, 1, 0]))
cam.unfollow()
camera.reset(run_time=1.0, rate_func=...)
Restores the camera frame to origin (0, 0, 0) with the default screen dimensions (14.22 width $\times$ 8.0 height).
3. Error Handling and Degradation
Camera requires access to a camera frame with .move_to() and .set_width(), which is provided natively by MovingCameraScene.
If Camera is initialized with a standard Scene that does not support camera movement, it raises a clear, actionable error:
from animora.core import Scene, Camera
class StaticScene(Scene):
def construct(self) -> None:
cam = Camera(self) # Raises TypeError with helpful migration instructions
Error Message:
TypeError: Camera requires a MovingCameraScene (or a Scene with a movable camera frame). Got: StaticScene.