or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

animations.mdcameras.mdcoordinate-systems.mdindex.mdmobjects.mdrendering.mdscenes.mdutilities.md

cameras.mddocs/

0

# Camera System

1

2

Flexible camera system supporting 2D and 3D perspectives, camera movement, zooming, and multi-camera setups for complex visual presentations. Cameras control what portion of the mathematical space is rendered and how it appears on screen, providing the viewing framework for all Manim animations.

3

4

## Capabilities

5

6

### Base Camera

7

8

The fundamental camera class providing core rendering functionality and viewport management for 2D scenes.

9

10

```python { .api }

11

class Camera:

12

"""

13

Base camera class handling viewport management and rendering coordination.

14

15

Controls what region of mathematical space is visible, pixel resolution,

16

and rendering parameters for converting mathematical objects to screen pixels.

17

"""

18

19

def __init__(

20

background_image: str = None,

21

frame_center: np.ndarray = ORIGIN,

22

image_mode: str = "RGBA",

23

n_channels: int = 4,

24

pixel_array_dtype: str = "uint8",

25

cairo_line_width_multiple: float = 0.01,

26

use_z_index: bool = True,

27

background: np.ndarray = None,

28

pixel_height: int = None,

29

pixel_width: int = None,

30

frame_height: float = None,

31

frame_width: float = None,

32

frame_rate: float = None,

33

background_color: str = None,

34

background_opacity: float = None,

35

**kwargs

36

) -> None:

37

"""

38

Parameters:

39

- background_image: Path to background image file

40

- frame_center: Center point of camera viewport in scene coordinates

41

- image_mode: Color mode ("RGBA", "RGB", etc.)

42

- n_channels: Number of color channels

43

- pixel_array_dtype: Data type for pixel array ("uint8", "float64")

44

- cairo_line_width_multiple: Scaling factor for Cairo line rendering

45

- use_z_index: Whether to use z-index for depth sorting

46

- background: Custom background array

47

- pixel_height: Vertical resolution in pixels

48

- pixel_width: Horizontal resolution in pixels

49

- frame_height: Viewport height in Manim units

50

- frame_width: Viewport width in Manim units

51

- frame_rate: Animation frame rate

52

- background_color: Background color

53

- background_opacity: Background opacity

54

"""

55

56

# Core rendering methods

57

def capture_mobjects(

58

mobjects: list[Mobject],

59

**kwargs

60

) -> None:

61

"""

62

Render mobjects to the camera's pixel array.

63

64

Converts mathematical mobjects to screen pixels using appropriate

65

rendering methods for each mobject type.

66

67

Parameters:

68

- mobjects: List of mobjects to render

69

"""

70

71

def get_image(self) -> Image.Image:

72

"""

73

Get rendered image as PIL Image object.

74

75

Returns:

76

- Image.Image: PIL image containing rendered scene

77

"""

78

79

def get_pixel_array(self) -> np.ndarray:

80

"""

81

Get raw pixel array from camera buffer.

82

83

Returns:

84

- np.ndarray: Pixel array with shape (height, width, channels)

85

"""

86

87

def set_pixel_array(

88

pixel_array: np.ndarray,

89

convert_from_floats: bool = False

90

) -> None:

91

"""

92

Set camera's pixel array directly.

93

94

Parameters:

95

- pixel_array: New pixel array

96

- convert_from_floats: Whether to convert from float [0,1] to int [0,255]

97

"""

98

99

def reset(self) -> None:

100

"""Reset camera to initial state with clear background."""

101

102

def init_background(self) -> None:

103

"""Initialize background based on configuration settings."""

104

105

def resize_frame_shape(self, fixed_dimension: int = 0) -> None:

106

"""

107

Resize frame to maintain aspect ratio.

108

109

Parameters:

110

- fixed_dimension: Which dimension to keep fixed (0=width, 1=height)

111

"""

112

113

# Coordinate transformation methods

114

def transform_points_pre_display(

115

mobject: Mobject,

116

points: np.ndarray

117

) -> np.ndarray:

118

"""

119

Transform points before display rendering.

120

121

Apply camera transformations to convert scene coordinates

122

to screen coordinates.

123

124

Parameters:

125

- mobject: Mobject being transformed

126

- points: Points in scene coordinates

127

128

Returns:

129

- np.ndarray: Points in screen coordinates

130

"""

131

132

def points_to_pixel_coords(

133

points: np.ndarray

134

) -> np.ndarray:

135

"""

136

Convert scene points to pixel coordinates.

137

138

Parameters:

139

- points: Points in scene coordinates

140

141

Returns:

142

- np.ndarray: Points in pixel coordinates

143

"""

144

145

def adjust_out_of_range_points(

146

points: np.ndarray

147

) -> np.ndarray:

148

"""

149

Adjust points that fall outside visible range.

150

151

Parameters:

152

- points: Scene coordinate points

153

154

Returns:

155

- np.ndarray: Adjusted points within visible range

156

"""

157

158

# Properties for frame dimensions and positioning

159

@property

160

def frame_height() -> float:

161

"""Height of camera viewport in scene units."""

162

163

@property

164

def frame_width() -> float:

165

"""Width of camera viewport in scene units."""

166

167

@property

168

def frame_center() -> np.ndarray:

169

"""Center point of camera viewport."""

170

171

@property

172

def pixel_height() -> int:

173

"""Vertical resolution in pixels."""

174

175

@property

176

def pixel_width() -> int:

177

"""Horizontal resolution in pixels."""

178

179

@property

180

def background_color() -> str:

181

"""Background color of the camera."""

182

183

@property

184

def background_opacity() -> float:

185

"""Background opacity of the camera."""

186

```

187

188

### Moving Camera

189

190

Camera that can be moved, zoomed, and rotated during animations for dynamic perspective changes and cinematic effects.

191

192

```python { .api }

193

class MovingCamera(Camera):

194

"""

195

Camera that can move through the scene with animated frame adjustments.

196

197

Allows for dynamic camera movements including panning, zooming, and rotation

198

to create cinematic effects and follow animated objects.

199

"""

200

201

def __init__(

202

frame: Mobject = None,

203

fixed_dimension: int = 0,

204

default_frame_stroke_color: str = WHITE,

205

default_frame_stroke_width: float = 0,

206

**kwargs

207

) -> None:

208

"""

209

Parameters:

210

- frame: Mobject representing camera frame (usually ScreenRectangle)

211

- fixed_dimension: Which dimension to keep fixed during scaling (0=width, 1=height)

212

- default_frame_stroke_color: Default color for frame border

213

- default_frame_stroke_width: Default width for frame border

214

"""

215

216

# Frame manipulation methods

217

@property

218

def frame() -> Mobject:

219

"""Camera frame mobject that defines the viewport."""

220

221

def auto_zoom(

222

*mobjects: Mobject,

223

margin: float = 1,

224

only_mobjects_in_frame: bool = False,

225

animate: bool = False

226

) -> None:

227

"""

228

Automatically adjust camera to fit specified mobjects.

229

230

Parameters:

231

- *mobjects: Mobjects to fit in frame

232

- margin: Additional margin around mobjects

233

- only_mobjects_in_frame: Whether to consider only visible mobjects

234

- animate: Whether to animate the zoom

235

"""

236

237

def save_camera_position(self) -> None:

238

"""Save current camera position and zoom for later restoration."""

239

240

def restore_camera_position(self) -> None:

241

"""Restore previously saved camera position and zoom."""

242

243

# Animation-friendly properties

244

@property

245

def frame_height() -> float:

246

"""Height of camera frame (can be animated)."""

247

248

@frame_height.setter

249

def frame_height(value: float) -> None:

250

"""Set frame height (animatable)."""

251

252

@property

253

def frame_width() -> float:

254

"""Width of camera frame (can be animated)."""

255

256

@frame_width.setter

257

def frame_width(value: float) -> None:

258

"""Set frame width (animatable)."""

259

260

@property

261

def frame_center() -> np.ndarray:

262

"""Center of camera frame (can be animated)."""

263

264

@frame_center.setter

265

def frame_center(value: np.ndarray) -> None:

266

"""Set frame center (animatable)."""

267

268

# Coordinate transformation overrides

269

def points_to_pixel_coords(

270

points: np.ndarray

271

) -> np.ndarray:

272

"""Convert points to pixels accounting for frame movement."""

273

274

def adjust_out_of_range_points(

275

points: np.ndarray

276

) -> np.ndarray:

277

"""Adjust points based on current frame position."""

278

```

279

280

### Three-Dimensional Camera

281

282

Specialized camera for 3D scenes with perspective projection, camera orientation, and 3D lighting effects.

283

284

```python { .api }

285

class ThreeDCamera(Camera):

286

"""

287

Camera for 3D scenes with perspective projection and orientation control.

288

289

Provides full 3D camera functionality including perspective projection,

290

camera positioning in 3D space, and lighting for realistic 3D rendering.

291

"""

292

293

def __init__(

294

focal_distance: float = 20.0,

295

shading_factor: float = 0.2,

296

default_distance: float = 5.0,

297

light_source_start_point: np.ndarray = 9*DOWN + 7*LEFT + 10*OUT,

298

should_apply_shading: bool = True,

299

exponential_projection: bool = False,

300

phi: float = 0,

301

theta: float = -90*DEGREES,

302

gamma: float = 0,

303

zoom: float = 1,

304

**kwargs

305

) -> None:

306

"""

307

Parameters:

308

- focal_distance: Distance from camera to focal plane

309

- shading_factor: Intensity of 3D shading effects

310

- default_distance: Default z-distance for objects

311

- light_source_start_point: Initial position of light source

312

- should_apply_shading: Whether to apply 3D shading

313

- exponential_projection: Whether to use exponential perspective

314

- phi: Camera angle from z-axis (inclination) in radians

315

- theta: Camera angle from x-axis (azimuth) in radians

316

- gamma: Camera roll angle around viewing direction

317

- zoom: Camera zoom factor

318

"""

319

320

# 3D orientation and positioning

321

def set_euler_angles(

322

phi: float = None,

323

theta: float = None,

324

gamma: float = None

325

) -> None:

326

"""

327

Set camera orientation using Euler angles.

328

329

Parameters:

330

- phi: Inclination angle (angle from z-axis)

331

- theta: Azimuth angle (angle from x-axis)

332

- gamma: Roll angle (rotation around viewing direction)

333

"""

334

335

def get_euler_angles(self) -> tuple[float, float, float]:

336

"""

337

Get current camera orientation angles.

338

339

Returns:

340

- tuple: (phi, theta, gamma) angles in radians

341

"""

342

343

def set_focal_distance(self, distance: float) -> None:

344

"""

345

Set camera focal distance for perspective projection.

346

347

Parameters:

348

- distance: Distance from camera to focal plane

349

"""

350

351

def set_zoom(self, zoom_factor: float) -> None:

352

"""

353

Set camera zoom level.

354

355

Parameters:

356

- zoom_factor: Zoom multiplier (1.0 = default, >1.0 = zoom in)

357

"""

358

359

# 3D transformation methods

360

def get_rotation_matrix(self) -> np.ndarray:

361

"""

362

Get 3D rotation matrix for current camera orientation.

363

364

Returns:

365

- np.ndarray: 3x3 rotation matrix

366

"""

367

368

def reset_rotation_matrix(self) -> None:

369

"""Recalculate rotation matrix from current angles."""

370

371

def transform_points_pre_display(

372

mobject: Mobject,

373

points: np.ndarray

374

) -> np.ndarray:

375

"""

376

Apply 3D transformations including rotation and perspective projection.

377

378

Parameters:

379

- mobject: Mobject being transformed

380

- points: 3D points in scene coordinates

381

382

Returns:

383

- np.ndarray: 2D points after 3D projection

384

"""

385

386

def apply_3d_perspective(

387

points: np.ndarray

388

) -> np.ndarray:

389

"""

390

Apply perspective projection to 3D points.

391

392

Parameters:

393

- points: 3D points after rotation

394

395

Returns:

396

- np.ndarray: 2D points after perspective projection

397

"""

398

399

# Lighting and shading

400

def get_unit_normal(

401

points: np.ndarray,

402

face_indices: np.ndarray = None

403

) -> np.ndarray:

404

"""

405

Calculate unit normal vectors for 3D surfaces.

406

407

Parameters:

408

- points: 3D surface points

409

- face_indices: Indices defining surface faces

410

411

Returns:

412

- np.ndarray: Unit normal vectors

413

"""

414

415

def get_shading_factor(

416

points: np.ndarray,

417

unit_normal_vect: np.ndarray

418

) -> float:

419

"""

420

Calculate shading factor based on lighting angle.

421

422

Parameters:

423

- points: 3D surface points

424

- unit_normal_vect: Surface normal vectors

425

426

Returns:

427

- float: Shading factor [0, 1]

428

"""

429

430

# Object management for 3D scenes

431

def add_fixed_orientation_mobjects(

432

*mobjects: Mobject

433

) -> None:

434

"""

435

Add mobjects that maintain fixed orientation relative to camera.

436

437

These mobjects always face the camera regardless of camera rotation,

438

useful for text labels and 2D elements in 3D scenes.

439

440

Parameters:

441

- *mobjects: Mobjects to fix orientation

442

"""

443

444

def add_fixed_in_frame_mobjects(

445

*mobjects: Mobject

446

) -> None:

447

"""

448

Add mobjects that remain fixed in screen space.

449

450

These mobjects maintain fixed screen positions regardless of

451

camera movement, useful for UI elements and legends.

452

453

Parameters:

454

- *mobjects: Mobjects to fix in frame

455

"""

456

457

def remove_fixed_orientation_mobjects(

458

*mobjects: Mobject

459

) -> None:

460

"""Remove mobjects from fixed orientation list."""

461

462

def remove_fixed_in_frame_mobjects(

463

*mobjects: Mobject

464

) -> None:

465

"""Remove mobjects from fixed frame list."""

466

467

# Value trackers for smooth animation

468

def get_value_trackers(self) -> list[ValueTracker]:

469

"""

470

Get value trackers for animating camera parameters.

471

472

Returns:

473

- list[ValueTracker]: Trackers for phi, theta, focal_distance, gamma, zoom

474

"""

475

476

@property

477

def phi_tracker() -> ValueTracker:

478

"""Value tracker for phi (inclination) angle."""

479

480

@property

481

def theta_tracker() -> ValueTracker:

482

"""Value tracker for theta (azimuth) angle."""

483

484

@property

485

def gamma_tracker() -> ValueTracker:

486

"""Value tracker for gamma (roll) angle."""

487

488

@property

489

def focal_distance_tracker() -> ValueTracker:

490

"""Value tracker for focal distance."""

491

492

@property

493

def zoom_tracker() -> ValueTracker:

494

"""Value tracker for zoom level."""

495

```

496

497

### Specialized Camera Types

498

499

Advanced camera classes for specific use cases and complex rendering scenarios.

500

501

```python { .api }

502

class MultiCamera(Camera):

503

"""

504

Camera supporting multiple simultaneous viewpoints.

505

506

Enables split-screen effects, picture-in-picture, and other

507

multi-viewport visualizations.

508

"""

509

510

def __init__(

511

*cameras: Camera,

512

**kwargs

513

) -> None:

514

"""

515

Parameters:

516

- *cameras: Sub-cameras for different viewports

517

"""

518

519

def capture_mobjects(

520

mobjects: list[Mobject],

521

**kwargs

522

) -> None:

523

"""Render scene using all sub-cameras simultaneously."""

524

525

def set_split_positions(

526

positions: list[tuple[float, float, float, float]]

527

) -> None:

528

"""

529

Set viewport positions for each sub-camera.

530

531

Parameters:

532

- positions: List of (x, y, width, height) for each viewport

533

"""

534

535

class MappingCamera(Camera):

536

"""

537

Camera with coordinate space transformations and mappings.

538

539

Allows for non-linear coordinate transformations and custom

540

mathematical space mappings.

541

"""

542

543

def __init__(

544

mapping_func: Callable[[np.ndarray], np.ndarray] = None,

545

min_anchor_points: int = 50,

546

max_anchor_points: int = 100,

547

**kwargs

548

) -> None:

549

"""

550

Parameters:

551

- mapping_func: Function to transform coordinates

552

- min_anchor_points: Minimum points for mapping interpolation

553

- max_anchor_points: Maximum points for mapping interpolation

554

"""

555

556

def points_to_pixel_coords(

557

points: np.ndarray

558

) -> np.ndarray:

559

"""Apply coordinate mapping before pixel conversion."""

560

561

class SplitScreenCamera(MultiCamera):

562

"""

563

Camera for split-screen presentations with automatic layout.

564

565

Convenient wrapper for common split-screen configurations

566

with automatic viewport management.

567

"""

568

569

def __init__(

570

left_camera: Camera,

571

right_camera: Camera,

572

split_ratio: float = 0.5,

573

**kwargs

574

) -> None:

575

"""

576

Parameters:

577

- left_camera: Camera for left viewport

578

- right_camera: Camera for right viewport

579

- split_ratio: Horizontal split position (0.5 = center)

580

"""

581

```

582

583

## Usage Examples

584

585

### Basic Camera Movement

586

587

```python

588

from manim import *

589

590

class CameraMovementExample(MovingCameraScene):

591

def construct(self):

592

# Create objects

593

square = Square(color=BLUE)

594

circle = Circle(color=RED).shift(RIGHT * 4)

595

596

self.add(square, circle)

597

598

# Move camera to focus on square

599

self.play(

600

self.camera.frame.animate.move_to(square).scale(0.5)

601

)

602

self.wait(1)

603

604

# Move camera to circle

605

self.play(

606

self.camera.frame.animate.move_to(circle)

607

)

608

self.wait(1)

609

610

# Zoom out to show both

611

self.play(

612

self.camera.frame.animate.move_to(ORIGIN).scale(2)

613

)

614

```

615

616

### 3D Camera Control

617

618

```python

619

class ThreeDCameraExample(ThreeDScene):

620

def construct(self):

621

# Set initial camera orientation

622

self.set_camera_orientation(phi=75*DEGREES, theta=45*DEGREES)

623

624

# Create 3D objects

625

axes = ThreeDAxes()

626

cube = Cube(side_length=2, fill_opacity=0.7)

627

sphere = Sphere(radius=1.2).shift(UP * 2)

628

629

self.add(axes, cube, sphere)

630

631

# Animate camera rotation

632

self.play(

633

self.camera.phi_tracker.animate.set_value(30*DEGREES),

634

self.camera.theta_tracker.animate.set_value(60*DEGREES),

635

run_time=3

636

)

637

638

# Move camera position

639

self.play(

640

self.camera.frame_center.animate.shift(RIGHT * 2),

641

self.camera.zoom_tracker.animate.set_value(1.5),

642

run_time=2

643

)

644

645

# Add fixed orientation text

646

text = Text("3D Scene", font_size=48)

647

self.add_fixed_in_frame_mobjects(text)

648

text.to_corner(UL)

649

```

650

651

### Auto-Zoom Functionality

652

653

```python

654

class AutoZoomExample(MovingCameraScene):

655

def construct(self):

656

# Create scattered objects

657

dots = VGroup(*[

658

Dot(np.random.uniform(-6, 6, 3))

659

for _ in range(10)

660

])

661

662

self.add(dots)

663

664

# Auto-zoom to fit all dots

665

self.camera.auto_zoom(*dots, margin=1, animate=True)

666

self.wait(2)

667

668

# Focus on subset

669

subset = dots[:3]

670

self.camera.auto_zoom(*subset, margin=0.5, animate=True)

671

self.wait(2)

672

```

673

674

### Multi-Camera Setup

675

676

```python

677

class MultiCameraExample(Scene):

678

def setup(self):

679

# Create split-screen camera

680

left_camera = Camera()

681

right_camera = Camera()

682

683

self.camera = SplitScreenCamera(

684

left_camera,

685

right_camera,

686

split_ratio=0.6

687

)

688

689

def construct(self):

690

# Content will appear in both viewports

691

circle = Circle(color=BLUE)

692

square = Square(color=RED)

693

694

self.add(circle, square)

695

```

696

697

### Advanced 3D Camera Animation

698

699

```python

700

class Advanced3DCameraExample(ThreeDScene):

701

def construct(self):

702

# Create complex 3D scene

703

axes = ThreeDAxes()

704

surface = Surface(

705

lambda u, v: [u, v, u**2 + v**2],

706

u_range=[-2, 2],

707

v_range=[-2, 2],

708

resolution=16,

709

fill_opacity=0.8

710

)

711

712

self.add(axes, surface)

713

714

# Set initial position

715

self.set_camera_orientation(phi=60*DEGREES, theta=30*DEGREES)

716

717

# Create orbital camera movement

718

def orbit_camera():

719

self.begin_ambient_camera_rotation(rate=0.1)

720

721

# Add light tracking

722

self.camera.light_source.move_to([5, 5, 5])

723

724

# Animate camera parameters simultaneously

725

self.play(

726

self.camera.phi_tracker.animate.set_value(90*DEGREES),

727

self.camera.zoom_tracker.animate.set_value(0.8),

728

run_time=4

729

)

730

731

# Start orbital motion

732

orbit_camera()

733

self.wait(6)

734

self.stop_ambient_camera_rotation()

735

```

736

737

### Camera Coordinate Transformations

738

739

```python

740

class CoordinateTransformExample(Scene):

741

def construct(self):

742

# Show how camera transforms coordinates

743

axes = Axes()

744

point_in_scene = np.array([2, 1, 0])

745

746

# Convert to pixel coordinates

747

pixel_coords = self.camera.points_to_pixel_coords(

748

np.array([point_in_scene])

749

)[0]

750

751

# Create visual indicators

752

scene_dot = Dot(point_in_scene, color=RED)

753

pixel_text = Text(

754

f"Pixel: ({pixel_coords[0]:.0f}, {pixel_coords[1]:.0f})",

755

font_size=24

756

).next_to(scene_dot, UP)

757

758

coord_text = Text(

759

f"Scene: ({point_in_scene[0]}, {point_in_scene[1]})",

760

font_size=24

761

).next_to(scene_dot, DOWN)

762

763

self.add(axes, scene_dot, pixel_text, coord_text)

764

```