# How to Work with Mobjects, VMobjects, and VGroups to Build Scenes in Manim

> Master Manim scene creation using Mobjects, VMobjects, and VGroups. Learn to bundle shapes, group elements, and animate complex scenes efficiently.

- Repository: [Grant Sanderson/manim](https://github.com/3b1b/manim)
- Tags: how-to-guide
- Published: 2026-02-28

---

**To build scenes in Manim, use `VMobject` subclasses for drawable shapes, `VGroup` to bundle them into single transformable units, and `Mobject`'s family tree methods for layout and animation.**

Manim, the mathematical animation engine created by 3Blue1Brown and maintained in the `3b1b/manim` repository, organizes every visual element into a hierarchy of **mobjects** (mathematical objects). Understanding the relationship between the abstract `Mobject` base class, the vectorized `VMobject`, and the container `VGroup` is essential for composing clean, reusable animation code.

## Understanding the Mobject Hierarchy

Manim’s rendering pipeline is built around three core classes defined in [`manimlib/mobject/mobject.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/mobject.py) and [`manimlib/mobject/types/vectorized_mobject.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/types/vectorized_mobject.py).

### Mobject – The Abstract Foundation

`Mobject` is the root class for any drawable entity. It manages the **family tree** through `submobjects` (children) and `parents` (containers) lists, handles **updaters** via `add_updater` and `remove_updater`, and provides geometric transformations through `apply_points_function`.

Key capabilities include:

- **Family management**: Methods like `add`, `remove`, `clear`, `add_to_back`, `replace_submobject`, and `insert_submobject` manipulate the scene graph.
- **Geometry**: `shift`, `scale`, `rotate`, `move_to`, `next_to`, and `align_on_border` modify `self.data['point']` through the unified transformation pipeline.
- **Updaters**: The `always` and `f_always` properties register callables that execute every frame, enabling continuous behaviors. These receive `self.time` from the Scene class.

### VMobject – Vectorized Graphics

`VMobject` (Vectorized Mobject) extends `Mobject` to store per-vertex data required for GPU rendering. Defined in [`manimlib/mobject/types/vectorized_mobject.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/types/vectorized_mobject.py), it serves as the parent for all shape primitives like `Circle`, `Square`, and `Polygon`.

Critical features:

- **Data buffers**: Stores `stroke_rgba`, `stroke_width`, `fill_rgba`, `joint_angle`, `base_normal`, and `fill_border_width` in the `data_dtype` definition. This data is sent to the GPU via `VShaderWrapper`.
- **Styling API**: `set_fill`, `set_stroke`, `set_shading`, and `set_flat_stroke` operate recursively on the family by default.
- **Path handling**: `get_bezier_tuples`, `get_subcurve`, and `DashedVMobject` enable complex curve manipulation.
- **Group factory**: `VMobject.get_group_class` returns `VGroup`, ensuring that the expression `a + b` automatically produces a `VGroup` containing both objects.

### VGroup – The Container Object

`VGroup` (defined around line 1312 in [`manimlib/mobject/types/vectorized_mobject.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/types/vectorized_mobject.py)) inherits from both `Group` and `VMobject`. This dual inheritance allows it to behave like a Python list while retaining full vector graphics capabilities.

Key behaviors:

- **Hybrid inheritance**: Because it is both a `Group` and `VMobject`, a `VGroup` supports indexing (`vg[0]`) like a list and transformations like any other drawable object.
- **Uniform inheritance**: Upon creation, it copies the first child’s uniform dictionary (`self.uniforms.update(self.submobjects[0].uniforms)`) to ensure consistent stroke and fill settings across the group.
- **Layout utilities**: Methods such as `arrange`, `arrange_in_grid`, `space_out_submobjects`, and `sort` (defined on `Mobject`) work transparently on `VGroup` instances.

## Working with Families and Transformations

Effective scene building relies on manipulating the mobject family tree and applying coordinate transformations.

### Managing the Scene Graph

Every mobject maintains parent-child relationships. When you call `self.add(mob)` in your Scene, you are attaching the mobject to the scene's family tree. Changes to a parent automatically propagate to children’s bounding boxes and shader data.

Use `add_to_back` to control render order (z-index), and `replace_submobject` to swap elements during animations without breaking family references.

### Applying Coordinate Functions

All geometric transformations route through `apply_points_function` in [`mobject.py`](https://github.com/3b1b/manim/blob/main/mobject.py). This ensures that whether you call `shift`, `scale`, or `rotate`, the underlying point data in `self.data['point']` is updated consistently, and bounding boxes are recalculated for the entire family.

## Practical Scene Building Patterns

The following patterns demonstrate how to compose scenes using the hierarchy effectively.

### Pattern 1: Simple Composition with VGroup

Group related primitives to treat them as a single transformable unit.

```python
from manimlib import *

class SimpleGroup(Scene):
    def construct(self):
        # Create primitive VMobjects

        circle = Circle(radius=2, color=RED).set_fill(opacity=0.3)
        square = Square(side_length=2, color=BLUE).set_fill(opacity=0.5)

        # Group them – VGroup behaves like a single VMobject

        logo = VGroup(circle, square).arrange(RIGHT, buff=0.5)

        # Position the group

        logo.to_edge(UP)

        # Add to scene with an animation

        self.play(FadeIn(logo, shift=DOWN))

        # Demonstrate collective transformation

        self.play(logo.animate.scale(1.5).rotate(PI / 4))
        self.wait()

```

**Key points**:
- `VGroup` automatically inherits `animate`, enabling chained transformations on the whole group.
- `arrange(RIGHT)` uses the layout utilities defined in `Mobject`.

### Pattern 2: Nested Groups and Per-Subobject Styling

Access individual children to apply distinct styles while maintaining group coherence.

```python
class NestedGroups(Scene):
    def construct(self):
        # Base shapes

        outer = Circle(radius=3, color=YELLOW).set_fill(opacity=0.2)
        inner = Circle(radius=1, color=GREEN).set_fill(opacity=0.8)

        # Group the two circles

        ring = VGroup(outer, inner)
        ring.center()                     # Center both circles together

        # Add a third element that stays independent

        dot = Dot(radius=0.1, color=WHITE).next_to(ring, DOWN, buff=0.3)

        # Combine into a top‑level group

        whole = VGroup(ring, dot)

        # Style subobjects individually

        outer.set_stroke(width=8, color=ORANGE)   # only outer circle gets thick stroke

        inner.set_fill(opacity=0.4)               # dim inner fill

        self.add(whole)
        self.play(whole.animate.rotate(2 * PI), run_time=4)
        self.wait()

```

**Key points**:
- Sub-objects are accessible via indexing (`ring[0]` is `outer`).
- Styling calls recurse through the family by default, but you can limit recursion with `recurse=False`.

### Pattern 3: Live Updaters on VMobjects

Use `always` and `f_always` to create frame-wise animations without explicit `self.play` calls.

```python
class LiveWave(Scene):
    def construct(self):
        wave = VMobject()
        wave.set_points_as_corners([LEFT, RIGHT])   # start as a simple line

        wave.set_stroke(color=PURPLE, width=8)

        # Make the wave oscillate forever

        wave.always.apply_function(
            lambda pts: pts + np.column_stack((
                np.zeros(len(pts)),
                0.5 * np.sin(pts[:, 0] + self.time),
                np.zeros(len(pts))
            ))
        )

        self.add(wave)
        self.wait(5)   # watch the live animation

```

**Key points**:
- `wave.always.apply_function` registers a frame-wise updater that mutates points.
- `self.time` is supplied by the `Scene` base class in [`manimlib/scene/scene.py`](https://github.com/3b1b/manim/blob/main/manimlib/scene/scene.py).

## Key Source Files for Deep Dives

To understand the internals behind these patterns, study the following files in the `3b1b/manim` repository:

| File | Purpose |
|------|---------|
| [`manimlib/mobject/mobject.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/mobject.py) | Core implementation of the family tree, point handling, updaters, and generic transformations. |
| [`manimlib/mobject/types/vectorized_mobject.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/types/vectorized_mobject.py) | Defines `VMobject`, its data buffers, styling API, and the `VGroup` container. |
| [`manimlib/scene/scene.py`](https://github.com/3b1b/manim/blob/main/manimlib/scene/scene.py) | Provides the `Scene` class that owns the camera, orchestrates `self.add`, `self.play`, and passes the `self.time` variable to updaters. |
| [`manimlib/mobject/types/__init__.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/types/__init__.py) | Re-exports the most-used shape classes (`Circle`, `Square`, `Polygon`) which all inherit from `VMobject`. |
| [`manimlib/mobject/svg/svg_mobject.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/svg/svg_mobject.py) | Shows how SVG paths are converted into a `VMobject` hierarchy, useful when you need custom vector graphics. |

## Summary

- **`Mobject`** is the abstract base that handles family trees, coordinate transforms, and updaters in [`manimlib/mobject/mobject.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/mobject.py).
- **`VMobject`** adds GPU-ready vertex buffers and styling controls for vector graphics, serving as the parent for all shapes.
- **`VGroup`** acts as a dual-purpose container: it supports list-like indexing while retaining full `VMobject` transform capabilities, making it ideal for bundling complex assets.
- Use **`always`** and **`f_always`** updaters for continuous animations driven by `self.time`.
- Reference **[`manimlib/mobject/types/vectorized_mobject.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/types/vectorized_mobject.py)** and **[`manimlib/mobject/mobject.py`](https://github.com/3b1b/manim/blob/main/manimlib/mobject/mobject.py)** when extending or debugging the hierarchy.

## Frequently Asked Questions

### What is the difference between Mobject and VMobject?

`Mobject` is the abstract foundation that manages the scene graph, transformations, and updaters but contains no rendering data. `VMobject` (Vectorized Mobject) inherits from `Mobject` and adds GPU-specific buffers for stroke, fill, and vertex data, making it the appropriate base for any visible shape like circles or polygons.

### When should I use VGroup instead of Group?

You should use `VGroup` when you need a container that behaves as a single drawable object. Because `VGroup` inherits from both `Group` and `VMobject`, it supports vector styling and transformations while allowing list-like access to its children. Use `Group` only when you need a pure organizational container without the rendering overhead of `VMobject`.

### How do I access individual submobjects in a VGroup?

You can access children via standard indexing: `my_vgroup[0]` returns the first submobject. You can also iterate over the group with `for mob in my_vgroup:`. To style individual members without affecting siblings, call methods directly on the indexed submobject, as styling operations recurse through the family by default.

### Can I apply different styles to submobjects within a VGroup?

Yes. While `VGroup` copies the first child's uniform dictionary upon creation to ensure visual consistency, you can override styles on individual submobjects afterward. Access the child via indexing and apply methods like `set_stroke` or `set_fill`. To prevent a style call from propagating to children, pass `recurse=False` to the styling method.