1. Введение: Зачем вообще кодить видео?

Если вы хоть раз видели ролики на YouTube-канале 3Blue1Brown, вы знаете этот стиль: плавные трансформации фигур, «живые» формулы и графики, которые строятся сами собой. Многие думают, что это результат адского ручного труда моушн-дизайнера. На самом деле — это чистый Python.

Библиотека называется Manim. И давайте сразу определимся: если вам нужно смонтировать влог из отпуска, закрывайте статью, Manim вам не нужен. Но если вы хотите визуализировать структуры данных, алгоритмы или физмат-модели, классические видеоредакторы (After Effects, Premiere) становятся проблемой.

Попытка построить динамический график функции или анимировать сортировку массива мышкой — это часы возни с кейфреймами (keyframe) и ручным выравниванием. Любая правка в логике заставляет переделывать всё с нуля.

Manim предлагает другой подход — Programmatic Animation:

  1. Абсолютная точность: Всё описывается математически. Если нужен сдвиг на вектор (2, 0, 0), он будет идеальным.

  2. Реюзабельность: Видео — это код. Его можно закоммитить в Git, отрефакторить и использовать куски в других проектах.

  3. Массовость: Нужно изменить цвет тысячи объектов? Вы меняете одну переменную в цикле for, а не кликаете по каждому объекту на таймлайне.

По сути, мы меняем монтажный стол на IDE. Для тех, кому проще написать скрипт, чем двигать ползунки, это глоток свежего воздуха.

2. Подготовка почвы: Manim Community vs ManimGL

Прежде чем писать pip install, нужно прояснить момент, на котором спотыкаются 90% новичков. Существует две основные версии библиотеки, и они несовместимы между собой.

  1. ManimGL (manimlib): Оригинальная версия от Гранта Сандерсона (автора 3Blue1Brown). Работает на OpenGL.

    • Плюсы: Очень быстрый рендеринг (GPU), возможность интерактива в реальном времени.

    • Минусы: Написана «под себя», слабая документация, нестабильна, сложно настраивается на Windows.

  2. Manim Community (manim): Форк, поддерживаемый сообществом разработчиков.

    • Плюсы: Стабильные ежемесячные релизы, отличная документация, кроссплатформенность, плагины.

    • Минусы: Рендерится на CPU (Cairo), поэтому медленнее на сложных сценах.

Вердикт: Для работы используем Manim Community. Это стандарт де-факто для всех, кто не является Грантом Сандерсоном. В статье мы работаем именно с ней.

Зависимости (System Dependencies)

Manim — это не просто Python-пакет, это обертка над системными инструментами. Без них магии не будет:

  1. FFmpeg: Критически важен. Python гене��ирует кадры (картинки), а FFmpeg склеивает их в MP4. Он должен быть установлен в системе и прописан в переменных среды (PATH).

  2. LaTeX: Нужен для рендеринга красивых математических формул. Если у вас в системе нет TeX-дистрибутива, Manim будет падать при попытке создать объект MathTex.

Установка

Когда системные зависимости на месте, ставим саму библиотеку. Обратите внимание на имя пакета:

# Ставит Community версию (то, что нам нужно)
pip install manim

# НЕ перепутайте с manimlib (это версия 3b1b)
# pip install manimlib — ЭТО НАМ НЕ НУЖНО

Проверяем, что всё взлетело:

manim --version

Если видите номер версии (например, Manim Community v0.19.1), окружение готово.

3. Анатомия сцены: Hello World

В Manim единица контента — это класс, наследуемый от Scene. Внутри него есть метод construct(), который работает как main() в C-подобных языках. Всё, что написано внутри construct, будет выполнено и отрендерено.

Минимально рабочий скрипт выглядит так (сохраните как scene.py):

from manim import *

class HelloWorld(Scene):
    def construct(self):
        # 1. Создаем Mobject (Mathematical Object)
        box = Square()
        box.set_fill(BLUE, opacity=0.5) # Настройка свойств

        # 2. Добавляем объект на сцену
        self.add(box)

Разбор ключевых компонентов:

  1. from manim import *: Обычно import * — это дурной тон (PEP8 не одобряет), но в контексте Manim это стандарт. Библиотека экспортирует сотни классов (цвета, фигуры, константы), и импортировать их поштучно — мучение.

  2. Mobject (Mathematical Object): Базовый класс для всего, что отображается на экране. Геометрия (Circle, Line), текст (Text, Tex), графики — всё это наследники Mobject.

  3. Координатная система: Центр экрана — это (0, 0, 0).

    • Высота кадра по умолчанию: 8 единиц (от -4 до +4 по Y).

    • Ширина: завист от соотношения сторон (при 16:9 это ~14.22 единицы, от -7.11 до +7.11 по X).

    • Поэтому Square() без аргументов создается ровно в центре.

Позиционирование

Вместо того чтобы высчитывать координаты вручную (x=3.5, y=-2), в Manim принят относительный подход.

circle = Circle()
square = Square()

# Сдвиг относительно центра или текущей позиции
circle.shift(LEFT * 2)  # Сдвинуть влево на 2 единицы
square.next_to(circle, RIGHT, buff=0.5) # Поставить справа от круга с отступом 0.5

Запуск рендера

Чтобы превратить этот код в видео (или картинку), идем в терминал:

manim -pql scene.py HelloWorld
  • -p (preview): автоматически открыть файл после рендера.

  • -q (quality): флаг качества. l — low (480p, быстро), h — high (1080p), k — 4k.

  • scene.py: имя файла.

  • HelloWorld: имя класса сцены.

Результатом выполнения кода выше будет статичная картинка с синим квадратом. Чтобы он задвигался, нам нужны анимации, о которых в следующем пункте.

4. Основы магии: Анимация и Трансформация

Если self.add() просто шлепает объект на кадр, то метод self.play() запускает генерацию кадров видео. Именно он отвечает за интерполяцию состояний от начала до конца действия.

Базовая логика

В метод play передается экземпляр анимации. Библиотека блокирует выполнение скрипта на время этой анимации (по умолчанию 1 секунда), рендерит нужное количество кадров и переходит к следующей строчке.

    def construct(self):
        square = Square()
        
        # Рисует контуры квадрата (Create — самая частая анимация появления)
        self.play(Create(square)) 
        
        # Пауза на 1 секунду. ВАЖНО: time.sleep() здесь не работает!
        # self.wait() генерирует статические кадры.
        self.wait(1.0)

Трансформации (The Killer Feature)

То, ради чего используют Manim — это Transform. Библиотека берет векторные точки первого объекта и плавно перемещает их в координаты точек второго объекта.

Это позволяет делать морфинг чего угодно во что угодно: буквы в цифру, квадрата в звезду, графика в прямую линию.

        circle = Circle()
        circle.set_fill(PINK, opacity=0.5)

        # Квадрат плавно превращается в Круг
        self.play(Transform(square, circle))

Важный нюанс архитектуры:
Метод Transform(A, B) модифицирует объект A, заставляя его выглядеть как B. Объект B при этом на сцену не добавляется, он служит лишь целевым шаблоном.
Если вам нужно, чтобы в итоге на сцене остался именно объект B (например, чтобы потом работать с его методами), используйте ReplacementTransform(A, B).

Синтаксис .animate

Для простых изменений свойств (сдвинуть, перекрасить, повернуть) не обязательно создавать целевой объект вручную. У каждого Mobject есть свойство .animate.

        # Вместо создания нового квадрата в другом месте:
        # self.play(square.animate.shift(RIGHT * 3).rotate(PI/4))
        
        # Также можно управлять скоростью через run_time
        self.play(
            square.animate.set_color(RED), 
            run_time=2.0
        )

Итоговый пайплайн анимации:

  1. Creation: Появление (Create, FadeIn, Write, DrawBorderThenFill).

  2. Mutation: Изменение (Transform, .animate).

  3. Destruction: Исчезновение (Uncreate, FadeOut, ShrinkToCenter).

Всё это комбинируется последовательно или параллельно (через запятую внутри одного play), давая полный контроль над таймингом видео.

5. Главная фишка: LaTeX и Формулы

Если вы пробовали вставить красивое уравнение в Adobe Premiere или DaVinci Resolve, вы знаете эту боль: нужно идти в онлайн-редактор LaTeX, генерировать PNG с прозрачным фоном, скачивать, вставлять на таймлайн. Если нашли ошибку в формуле — повторяем цикл заново.

Manim был рожден математиком для математики, поэтому поддержка LaTeX здесь нативная.

Как это работает

Вы пишете строку в синтаксисе TeX, Manim под капотом стучится в системный дистрибутив, генерирует SVG-вектор и превращает его в набор кривых Безье. Для нас это значит одно: формула — это не картинка, это геометрия. Её можно гнуть, перекрашивать по частям и трансформировать.

Используем класс MathTex:

        # Обязательно используйте r-строки (raw strings), 
        # иначе Python сойдет с ума от количества бэкслешей
        equation = MathTex(
            r"e^{i\pi} + 1 = 0",
            font_size=96
        )
        self.play(Write(equation))

разделения (Substrings)

Самая мощная фича — доступ к отдельным символам формулы. Поскольку Manim видит формулу как массив векторных контуров, вы можете обратиться к конкретному символу по индексу, как в списке Python.

Но высчитывать индекс символа «x» в длинном уравнении неудобно. Лучшая практика — разбивать формулу на части при создании:

        # Передаем части формулы отдельными строками
        eq = MathTex("a^2", "+", "b^2", "=", "c^2")
        
        # Теперь eq — это VGroup (группа векторов) из 5 элементов.
        # Мы можем обращаться к ним по отдельности:
        
        # Перекрасим "a^2" в синий
        eq[0].set_color(BLUE)
        # Перекрасим "b^2" в желтый
        eq[2].set_color(YELLOW)
        
        self.play(Write(eq))
        
        # Анимация акцента: масштабируем "c^2"
        self.play(
            eq[4].animate.scale(1.5).set_color(RED)
        )

TransformMatchingTex

Для создания тех самых видео, где одна формула перетекает в другую с сохранением общих символов (например, сокращение дроби, где одинаковые x перелетают и исчезают), используется TransformMatchingTex.

Это работает почти автоматически: Manim анализирует исходный и целевой TeX-код, находит одинаковые куски и плавно перемещает их на новые места, а всё, что не совпало — фейдит. Это выглядит профессионально, а пишется в две строчки.

6. Практический кейс: Визуализация графика и ValueTracker

Двигать квадратики — это весело, но давайте сделаем что-то полезное для Data Science или физики. Построим график функции (синусоиды) и пустим по нему точку, которая будет бежать в реальном времени и показывать свои текущие координаты.

Здесь нам понадобятся три важные концепции:

  1. Axes: Система координат. Manim умеет сам рисовать оси, расставлять засечки и цифры.

  2. c2p (Coordinates to Point): Метод, который переводит математические координаты (x=2, y=5) в пиксельные координаты на экране.

  3. ValueTracker: Это невидимый объект, который хранит число. Мы анимируем изменение этого числа, а все остальные объекты (точка, текст) «слушают» его и обновляются автоматически.

Задача

Нарисовать синусоиду и заставить точку пробежать по ней от x = -3 до x = 3, отображая значение y над собой.

Код примера (сохраните как graph_scene.py):

from manim import *
import numpy as np

class PlottingStats(Scene):
    def construct(self):
        # 1. Настраиваем оси
        # x_range=[min, max, step]
        axes = Axes(
            x_range=[-4, 4, 1],
            y_range=[-1.5, 1.5, 0.5],
            x_length=8, 
            y_length=5,
            axis_config={"color": GREY},
            tips=False # Убрать стрелочки на концах осей
        ).add_coordinates() 

        # 2. Строим график
        # axes.plot принимает лямбда-функцию
        sin_curve = axes.plot(lambda x: np.sin(x), color=BLUE)
        
        sin_label = MathTex("y = \\sin(x)").next_to(sin_curve, UP + RIGHT)

        # 3. Магия ValueTracker
        # Создаем "хранилище" значения X. Стартуем с -3
        t = ValueTracker(-3)

        # 4. Создаем точку, которая зависит от t
        # always_redraw пересоздает объект каждый кадр
        dot = always_redraw(lambda: Dot(
            # c2p берет (x, y) и возвращает координаты на экране
            point=axes.c2p(t.get_value(), np.sin(t.get_value())),
            color=RED
        ))

        # 5. Динамический текст (показания Y)
        # ИСПРАВЛЕНИЕ: Используем параметр number (или позиционный аргумент), 
        # параметра num в DecimalNumber нет.
        number_label = always_redraw(lambda: DecimalNumber(
            number=np.sin(t.get_value()), 
            num_decimal_places=2,
            color=RED
        ).next_to(dot, UP))

        self.play(Create(axes), Create(sin_curve), Write(sin_label))
        self.add(dot, number_label) 

        # 6. Запуск анимации
        # Мы анимируем ТОЛЬКО ValueTracker.
        # Точка и цифра обновятся сами благодаря always_redraw.
        self.play(
            t.animate.set_value(3), 
            run_time=4,
            rate_func=linear 
        )
        
        self.wait()

Разбор механики

Ключевая строка здесь: dot = always_redraw(lambda: ... ).
Функция always_redraw говорит Manim: "Вызывай эту лямбду перед отрисовкой каждого кадра видео".

  1. Каждый кадр Manim смотрит на текущее значение t (которое плавно меняется от -3 до 3).

  2. Вычисляет новый np.sin(t).

  3. Строит новую точку и обновляет цифру в DecimalNumber.

Без этой техники вам пришлось бы вручную рассчитывать тысячи координат. С ValueTracker вы управляете одной переменной, а вся сцена реагирует на её изменение.

7. Тонкости рендеринга и CLI

Код написан, но результат пока существует только в вашей голове. Чтобы превратить его в пиксели, нужно освоить командную строку (CLI). Manim имеет богатую систему флагов, которые определяют раз��ешение, фреймрейт и формат.

Базовая команда выглядит так:
manim [флаги] [имя_файла.py] [ИмяКлассаСцены]

Управление качеством (-q)

Самая частая ошибка новичка — пытаться рендерить сразу в высоком качестве. Manim работает на CPU (по большей части), и рендер 60 fps в 4K может занять минуты даже для простой сцены.

Используйте флаг -q (quality) с одной из букв:

  • -ql (Low): 480p, 15 fps. Используйте для разработки. Рендерится мгновенно, позволяет быстро оценить анимацию.

  • -qm (Medium): 720p, 30 fps. Хороший компромисс для черновиков.

  • -qh (High): 1080p, 60 fps. Стандарт для YouTube. Ставьте только когда код полностью отлажен.

  • -qk (4K): 2160p, 60 fps. Для перфекционистов.

Полезные флаги

  1. -p (Preview): После рендера сразу открывает видео в плеере по умолчанию. Без этого флага вам придется каждый раз лезть в папку media/videos/....

  2. -t (Transparent): Рендерит видео с альфа-каналом (прозрачным фоном). Критически важно, если вы делаете анимацию для наложения поверх живого видео в Premiere или DaVinci. Формат файла будет .mov (ProRes).

  3. --format gif: Сохраняет результат не в MP4, а в GIF. Удобно для статей на Хабр или GitHub Readme.

Конфигурация (manim.cfg)

Чтобы не писать каждый раз manim -pqh --disable_caching ..., можно создать в папке с проектом файл manim.cfg. Библиотека подхватит настройки автоматически.

Пример конфига:

[CLI]
frame_rate = 60
pixel_height = 1080
pixel_width = 1920
background_color = BLACK
background_opacity = 1
scene_names = DefaultScene

Почему так долго?

Если рендер зависает на э��апе Latex error или просто долго думает перед началом:

  1. LaTeX: Каждая формула компилируется через системный TeX. Это медленная операция, но Manim кэширует результаты. Второй запуск будет быстрее.

  2. Кэш: Manim сохраняет промежуточные анимации. Если вы поменяли цвет одного круга в конце сцены, он не будет пересчитывать начало. Но иногда кэш ломается. Если видите странные глитчи — удалите папку media/ и пересоберите проект.

Итоговая рекомендация:
Пишите код с флагом -pql.
Финальный билд делайте с -pqh.
Для интеграции с монтажом используйте -t.

8. Заключение и «Куда копать дальше»

Manim — это не «убийца» After Effects. Пытаться монтировать в нем блог или клип — изощренная форма мазохизма. Но как только задача касается точной геометрии, математических абстракций или алгоритмов, Manim перестает быть просто библиотекой и становится супероружием.

Вам больше не нужно выравнивать пиксели мышкой. Вы описываете логику поведения, а рендеринг — это просто побочный эффект выполнения кода. Это дает вам:

  1. Контроль версий: Ваше видео лежит в Git. Вы можете сделать ветку, поэкспериментировать с цветами и откатиться назад.

  2. Масштабируемость: Написать скрипт для сортировки 10 элементов так же сложно, как для 1000.

  3. Переиспользование: Создав однажды красивую визуализацию нейросети, вы будете использовать этот класс во всех будущих презентациях.

Что мы не затронули (но стоит изучить)

В рамках одной статьи невозможно охватить всё. Вот ключевые темы для самостоятельного изучения:

  • 3D Scenes (ThreeDScene): Вращение камеры, оси Z, поверхности. Выглядит эффектно, но требует хорошего пространственного мышления.

  • Graph Theory: В Manim встроен мощный движок для отрисовки графов и деревьев (Dijkstra, BFS/DFS визуализируются на раз-два).

  • Звук: Методы self.add_sound() для синхронизации аудиодорожки с анимацией.

Анонсы новых статей, полезные материалы, а так же если в процессе у вас возникнут сложности, обсудить их или задать вопрос по этой статье можно в моём Telegram-сообществе. Смело заходите, если что-то пойдет не так, — постараемся разобраться вместе.

Полезные ссылки

  1. Документация Manim Community: Она отлично структурирована и полна примеров.

Комментарии (0)