Files
calesthioandHanzo Dev 7ffb943132 Initial release — OpenMontage: the first open-source agentic video production system
11 production pipelines, 47 tools, 124 agent skills.
Supports cloud APIs (fal.ai, OpenAI, ElevenLabs, Suno, HeyGen, Runway) and
free local providers (diffusers, Piper TTS, WAN 2.1, Hunyuan, CogVideo).

Co-authored-by: Hanzo Dev <[email protected]>
2026-03-29 08:25:17 -07:00

3.4 KiB

ManimGL Frame (Camera) Control

CameraFrame

In ManimGL, camera control is done through self.camera.frame (CameraFrame is a Mobject):

frame = self.camera.frame

# Set euler angles for 3D orientation
frame.set_euler_angles(
    theta=-30 * DEGREES,
    phi=70 * DEGREES,
)

Note: In InteractiveScene, you can also use self.frame as a shortcut.

CameraFrame Methods (from official docs)

The CameraFrame inherits standard Mobject methods plus these specific ones:

  • .to_default_state() - Reset camera
  • .set_euler_angles(theta, phi, gamma) - Set all angles
  • .set_theta(theta) - Horizontal rotation
  • .set_phi(phi) - Vertical rotation
  • .set_gamma(gamma) - Roll
  • .increment_theta(dtheta) - Add to theta
  • .increment_phi(dphi) - Add to phi
  • .increment_gamma(dgamma) - Add to gamma

Also inherits: .shift(), .scale(), .move_to()

# Look down at 45 degrees, rotated 30 degrees
self.frame.reorient(45, -30, 0, ORIGIN, 8)

# Animate the reorientation
self.play(
    self.frame.animate.reorient(60, -45, 0, (1, 0, 0), 10),
    run_time=3
)

Common Camera Operations

Zoom

# Zoom in (smaller height = closer)
self.play(self.frame.animate.set_height(4))

# Zoom out
self.play(self.frame.animate.set_height(12))

Pan

# Move camera center
self.play(self.frame.animate.move_to(RIGHT * 3))

# Shift camera
self.play(self.frame.animate.shift(UP * 2))

Combined Movement

self.play(
    self.frame.animate.reorient(50, -40, 0, (2, 1, 0), 6).set_anim_args(run_time=3)
)

fix_in_frame()

Keep mobjects fixed in screen space during 3D camera movement:

title = Text("My Title")
title.to_edge(UP)
title.fix_in_frame()  # Call on the mobject, not the scene!

self.add(title)

# Title stays fixed while camera moves
self.play(self.frame.animate.reorient(60, -45, 0))

Key difference from ManimCE: In ManimCE you call self.add_fixed_in_frame_mobjects(title). In ManimGL you call title.fix_in_frame().

set_floor_plane()

Set the floor plane orientation for 3D scenes:

self.set_floor_plane("xz")  # y is up, xz is floor
self.set_floor_plane("xy")  # z is up, xy is floor (default)

Frame Animation Syntax

# Chain with set_anim_args for run_time
self.play(
    self.frame.animate.reorient(45, -30, 0, ORIGIN, 8).set_anim_args(run_time=2)
)

# Multiple frame operations
self.play(
    self.frame.animate.shift(RIGHT * 2).set_height(6),
    run_time=1.5
)

Background Rectangle

For scenes with 3D camera movement, add a background:

background = FullScreenRectangle()
background.set_fill(BLACK, 1)
background.fix_in_frame()
self.add(background)

Complete 3D Example

class Camera3DDemo(InteractiveScene):
    def construct(self):
        # Background
        bg = FullScreenRectangle()
        bg.set_fill(GREY_E, 1)
        bg.fix_in_frame()
        self.add(bg)

        # Title fixed in frame
        title = Text("3D Demo")
        title.to_edge(UP)
        title.fix_in_frame()
        self.add(title)

        # 3D content
        cube = Cube(side_length=2)
        cube.set_color(BLUE)
        self.add(cube)

        # Animate camera
        self.play(
            self.frame.animate.reorient(60, -45, 0, ORIGIN, 8),
            run_time=3
        )

        # Rotate around
        self.play(
            self.frame.animate.reorient(60, 45, 0),
            run_time=4
        )