프로그래밍 애니메이션 엔진manimgl v1.7.2 · 파이썬 106개 파일 · 라이선스 MIT · 렌더러 wgpu + WGSL 셰이더 · 최신 커밋 2026-08-06 · 작성자 Grant Sanderson · TrendShift Daily #19)
manim(math + animation)은 "설명용 수학 영상을 위한, 정밀한 프로그래밍 애니메이션 엔진"이다. 사용자는 Scene이라는 클래스를 상속받아 construct() 메서드 안에 "무엇을, 어떻게 움직여라"를 파이썬으로 적는다. 그러면 manim이 그 지시를 매 프레임의 좌표·색·투명도로 계산(보간)해 GPU로 그리고, ffmpeg로 mp4 영상까지 뽑아준다.
파워포인트에서 도형을 움직이려면 마우스로 하나하나 끌어 경로를 그린다. 정밀도도, 재현성도 낮다. 원의 반지름을 정확히 √2로, 곡선을 y=x²로 맞추는 건 사실상 불가능하다.
manim은 반대다. "이 좌표계를 행렬 [[1,1],[0,1]]로 변형해", "이 수식을 저 수식으로 매끄럽게 바꿔"라고 코드로 명령한다. 지휘자가 악보(코드)를 넘기면 연주자(엔진)가 정확히 같은 연주를 매번 재현하듯, 같은 코드는 언제나 픽셀 단위로 똑같은 영상을 만든다.
이 저장소가 특별한 이유는 두 개의 manim이 존재하기 때문이다. 지금 보는 3b1b/manim은 Grant Sanderson 본인이 자기 영상 제작을 위해 쓰는 "원조" 버전(패키지명 manimgl)이고, 2020년 커뮤니티가 이를 포크해 만든 안정판이 따로 있다(패키지명 manim). 이 구분은 뒤(2절)에서 자세히 다룬다 — 설치 사고의 90%가 여기서 난다.
manim은 신생 프로젝트가 아니다. 그런데도 TrendShift 상위권에 다시 오른다. 핵심은 유명한 원조 저장소가 2026년 들어 렌더링 엔진을 OpenGL에서 wgpu(WebGPU)로 통째 교체하는 대공사를 진행 중이기 때문이다. 관심 포인트는 세 가지다.
선형대수·미적분·신경망을 시각적으로 설명하는 3Blue1Brown 영상을 한 번쯤 본 사람은 수백만 명이다. "그 영상을 만드는 도구가 오픈소스"라는 사실은 그 자체로 강력한 유입 동기다. 개발자·교사·학생이 "나도 저런 영상을 만들고 싶다"며 계속 몰려든다.
초기 manim은 CPU에서 Cairo로 그림을 그렸고, 이후 ManimGL이라는 이름대로 OpenGL(ModernGL) 기반 GPU 렌더링으로 넘어갔다. 그리고 최신판(1.7.x)은 다시 wgpu로 이주했다. wgpu는 브라우저 표준 WebGPU의 파이썬 구현으로, 하나의 코드가 내부적으로 Vulkan·Metal·DirectX12·OpenGL 중 그 컴퓨터에 맞는 API로 실행된다. 셰이더도 GLSL이 아니라 WGSL(.wgsl)로 다시 쓰였다.
ManimGL(이 저장소)은 "F1 팀의 자체 정비소" — Grant 본인 영상 제작 속도에 맞춰 빠르게 실험하고 갈아엎는다. 최신 기능이 먼저 들어오지만 문서·안정성은 후순위다.
ManimCommunity(커뮤니티 포크)는 "양산차 공장" — 테스트·CI·풍부한 문서로 처음 배우는 사람에게 친절하다. 대부분의 튜토리얼·강좌는 이쪽 기준이다.
이 저장소는 pip install manimgl로 설치한다. pip install manim은 커뮤니티 에디션이라 코드가 호환되지 않는다. 두 버전의 설치법을 섞으면 반드시 깨진다 — 먼저 어느 쪽을 쓸지 정하고, 그쪽 안내만 따라야 한다.
ManimGL의 킬러 기능은 Scene.embed()다. 이걸 넣고 실행하면 렌더링 창이 뜬 채로 IPython 셸이 열려, 화면 속 도형을 그 자리에서 코드로 밀고·돌리고·바꿔 볼 수 있다. 영상 한 편을 통째로 렌더링해 결과를 확인하는 게 아니라, 라이브로 조각하듯 만든다. 이 실시간성이 커뮤니티판과 구별되는 원조판의 매력이다.
manim의 의존성 목록을 뜯어보면 이 프로젝트의 정체가 그대로 드러난다. 수학을 계산하는 층(numpy·scipy·sympy), 그것을 GPU로 그리는 층(wgpu·WGSL), 그리고 텍스트·수식·영상으로 내보내는 미디어 층이 한 몸으로 묶여 있다.
| 도구 | 역할 / 왜 이걸 쓰나 |
|---|---|
| NumPy | 모든 것의 바닥. 도형의 점 하나하나가 numpy 배열의 좌표다. 애니메이션은 결국 이 좌표 배열을 매 프레임 보간하는 일. |
| SciPy | 공간 변환, 보간, 수치 적분 등 고급 수학 연산. |
| SymPy | 기호 수학(symbolic). 수식을 "계산"이 아니라 "식 그대로" 다룰 때. |
| trimesh · pywavefront · isosurfaces | 3D 메시·표면 생성. ThreeDScene의 곡면·다면체를 만든다. |
| wgpu | WebGPU의 파이썬 구현. 실제 GPU 파이프라인·버퍼·셰이더를 다룬다. 내부적으로 Vulkan/Metal/DX12/GL로 번역. |
| WGSL 셰이더 | manimlib/shaders/*.wgsl. fill.wgsl(면 채우기), stroke.wgsl(선), surface.wgsl(3D 면) 등 GPU에서 도는 프로그램. |
| rendercanvas · glfw | 렌더 결과를 띄울 실제 OS 창을 연다. 대화형 미리보기 창이 여기서 나온다. |
| LaTeX (외부) | 수식 렌더링의 뿌리. Tex/TexText가 LaTeX을 호출해 수식을 그린다. 시스템에 별도 설치 필요(선택). |
| manimpango | 일반 텍스트(Text)를 Pango로 렌더링. 폰트·다국어 처리. |
| svgelements · skia-pathops | LaTeX/SVG를 베지어 경로로 변환하고, 경로 불리언 연산(합집합·교집합)을 처리. |
| ffmpeg (외부) | 프레임을 libx264·yuv420p mp4로 인코딩. manim이 Popen 파이프로 프레임을 흘려보낸다. |
| IPython · rich · tqdm | 대화형 셸(embed), 예쁜 로그, 진행 바. |
manimgl my_scene.py MyScene를 치면 벌어지는 일을 그리면 이렇다.
manim의 모든 것은 세 개의 클래스로 환원된다. 이 셋의 관계만 잡으면 나머지는 응용이다.
| 추상 | 정체 | 비유 |
|---|---|---|
| Mobject | 화면에 존재하는 "무엇" (원·수식·좌표계). 점 좌표 배열을 들고 있다. | 무대 위의 배우 |
| Animation | Mobject를 "시간에 따라 어떻게 바꾸는가". interpolate(alpha)가 핵심. | 배우에게 주는 동선 지시 |
| Scene | 배우와 지시를 모아 시간축에서 연출·렌더. construct()가 각본. | 연출자 + 무대 |
Mobject(math object)는 세 가지를 들고 있다. ① self.data: 점마다의 좌표·색을 담은 numpy StructuredArray(이게 통째로 GPU 버퍼로 올라간다). ② self.uniforms: 셰이더에 넘길 개체별 설정(음영 등). ③ self.submobjects: 자식 Mobject들의 리스트. 도형은 트리(가족) 구조다 — 하나의 수식은 여러 글자 Mobject의 부모이고, 각 글자는 다시 획들의 부모다.
class Mobject:
def __init__(self, ...):
self.submobjects = [] # 자식들 (가족 트리)
self.data = StructuredArray(...) # 점: point/color 등 -> GPU 버퍼
self.uniforms = Uniforms(...) # 개체별 셰이더 설정
def get_family(self): # 나 + 모든 자손을 평탄화
return [self, *sub_families...]
대부분의 도형은 VMobject(Vectorized Mobject)를 상속한다. 곡선을 베지어 곡선의 연쇄로 표현하는 벡터 도형이다. 그래서 아무리 확대해도 계단현상이 없다.
manim의 렌더러(renderer/)에서 가장 배울 게 많은 지점은 임의의 곡선으로 둘러싸인 면을 GPU 스텐실 버퍼의 감김수(winding number)로 채우는 기법이다(fill.wgsl). CPU에서 다각형을 삼각형으로 쪼개는(triangulation) 대신, 각 베지어가 만드는 삼각형들을 GPU에 그리되 "픽셀을 몇 번 감쌌는가"를 스텐실에 세어 내부/외부를 판정한다.
애니메이션의 심장은 단 하나, interpolate(alpha)다. alpha는 0(시작)에서 1(끝)로 가는 진행도다. 엔진은 매 프레임 경과 시간을 alpha로 바꾸고, 여기에 rate_func(기본 smooth)를 씌워 "처음엔 천천히, 중간엔 빠르게, 끝엔 다시 천천히"의 자연스러운 가감속을 만든다.
alpha (선형 시간) ─► rate_func ─► 실제 진행도
play(Transform(A, B), run_time=3, rate_func=smooth)
# 매 프레임: A.data 를 B.data 쪽으로 rate_func(alpha) 만큼 보간
self.play(circle.animate.shift(RIGHT)) 같은 마법 같은 문법을 자주 본다. .animate는 "이 메서드를 지금 실행하지 말고, 실행 전/후 상태를 기록해 그 사이를 애니메이션으로 만들라"는 뜻이다. 최종 상태를 코드로 적으면 중간 과정을 엔진이 알아서 보간한다.
구조를 관통하는 원칙은 "무엇(mobject) / 어떻게(animation) / 언제(scene)"의 3분할이다. 새 도형을 배우려면 mobject/를, 새 효과를 배우려면 animation/을, 출력·연출을 배우려면 scene/을 열면 된다.
manim을 뜯어보면 겉보기(수학 영상)와 달리, GPU 그래픽스·씬 그래프·수치 보간·미디어 파이프라인이라는 서로 다른 분야를 실전 코드로 한 번에 배울 수 있다. 배울 거리를 층별로 정리하면 이렇다.
renderer/와 shaders/는 현대 GPU 프로그래밍의 압축판이다. 정점 버퍼, 유니폼, 파이프라인 상태(깊이·스텐실·블렌드), 그리고 WGSL 셰이더까지. 특히 스텐실 감김수로 벡터 면을 채우는 기법은 실무 벡터 렌더러(폰트·SVG 엔진)에서도 쓰는 고급 주제다.
manimlib/shaders/fill.wgsl의 색 계산부를 살짝 고쳐(예: 위치에 따라 색을 섞기) 렌더 결과가 어떻게 변하는지 관찰하면, "셰이더가 픽셀 색을 정한다"는 개념이 손에 잡힌다.Mobject.submobjects와 get_family()는 게임 엔진·UI 프레임워크의 씬 그래프와 똑같은 개념이다. 부모를 옮기면 자식이 따라오고, 변환이 트리를 타고 전파된다. 재귀적 트리 순회를 실제 쓰임새로 익히기 좋다.
utils/rate_functions.py와 utils/bezier.py는 애니메이션의 수학이다. 선형 시간을 자연스러운 움직임으로 바꾸는 rate function, 곡선을 표현하는 베지어 보간 — 프론트엔드 CSS 애니메이션부터 게임까지 어디서나 재등장하는 개념이다.
LaTeX을 호출해 SVG를 얻고, ffmpeg에 프레임을 파이프로 흘려보내는 scene_file_writer.py는 "파이썬으로 외부 프로세스를 지휘하는 법"의 좋은 예다. subprocess.Popen으로 스트리밍 인코딩을 붙이는 실전 패턴을 볼 수 있다.
manim은 무거운 학습 프레임워크가 아니라 렌더링 엔진이라, 최신 GPU가 없어도 돈다. 다만 파이썬 밖의 외부 도구 두세 개를 시스템에 깔아야 하고, 초보자 설치 실패의 대부분이 이 단계에서 난다.
| 항목 | 요구 / 권장 |
|---|---|
| Python | 3.7 이상. 설치는 pip install manimgl 또는 소스에서 pip install -e . |
| GPU / 그래픽 API | wgpu가 Vulkan·Metal·DirectX12·OpenGL 중 하나를 사용. 근래 나온 PC/맥이면 대부분 충족. Apple Silicon(ARM) 맥은 Cairo 설치 권장. |
| FFmpeg (필수) | 영상(mp4) 출력에 필수. 없으면 프레임을 파일로 못 묶는다. |
| LaTeX (선택) | 수식(Tex)을 쓸 때만. MacTeX(약 6GB)는 무겁고, 가벼운 BasicTeX로 필요한 패키지만 추가 가능. |
| Pango (Linux) | 리눅스에서 텍스트 렌더링용 개발 헤더 필요(manimpango). |
| 출력 규격 | 기본 1920x1080 / 30fps / libx264 / yuv420p. 옵션으로 저해상도(빠른 미리보기)·4K(3840x2160)까지. |
-w 파일로 저장 · -o 저장 후 열기 · -s 마지막 프레임만(빠른 확인) · -so 마지막 프레임을 이미지로 저장·표시 · -n <번호> n번째 애니메이션부터 건너뛰기 · -f 전체화면. 개발 중엔 -s로 결과 구도만 빠르게 잡고, 완성되면 -w로 뽑는 흐름이 정석이다.manimgl example_scenes.py OpeningManimExample를 실행해 창이 뜨는지 확인한다. 그다음 -w를 붙여 mp4가 실제로 나오는지 본다. 목표: 설치·ffmpeg·GPU가 모두 정상인지 검증. (여기서 막히면 대부분 ffmpeg 미설치 또는 manim/manimgl 혼동.)
Scene을 상속해 construct() 안에서 Circle()을 만들고 self.play(ShowCreation(circle)) → self.play(circle.animate.shift(RIGHT*2))를 실행한다. 배우는 것: Mobject 생성 → add/play → .animate 문법의 기본 리듬.
NumberPlane(좌표평면)을 깔고 apply_matrix([[1,1],[0,1]])로 선형변환 애니메이션을 만든다(3Blue1Brown 선형대수 영상의 핵심 장면). 배우는 것: 좌표계 Mobject, 행렬 변환, Transform.
Animation을 상속해 interpolate_mobject(alpha)를 직접 구현하거나, 자신만의 rate_func(예: 튕기는 bounce)를 짜서 play(..., rate_func=my_bounce)로 적용한다. 배우는 것: 애니메이션의 alpha·이징 수학을 소비자가 아니라 생산자로서 다루기.
ThreeDScene에서 곡면을 띄우고 카메라를 회전시킨 뒤, self.embed()로 IPython에 들어가 화면 속 객체를 실시간으로 조작해 본다. 여유가 되면 shaders/fill.wgsl을 복제·수정해 나만의 채우기 효과를 만든다. 배우는 것: 대화형 워크플로우 + WGSL 셰이더의 실제 편집.
| 주차 | 주제 | 무엇을·왜 |
|---|---|---|
| 1주 | NumPy·벡터/행렬 | manim의 모든 도형은 좌표 배열이다. 벡터 연산·행렬 변환·브로드캐스팅을 손에 익힌다. |
| 2주 | manim 3대 추상 | Mobject / Animation / Scene의 관계. 예제 씬을 뜯어 읽으며 흐름을 체득. |
| 3주 | 좌표계·변환·그래프 | Axes·NumberPlane·ComplexPlane, 선형/비선형 변환, 함수 그래프 애니메이션. |
| 4주 | 베지어·이징 수학 | utils/bezier.py·rate_functions.py를 읽고 커스텀 rate_func 작성. |
| 5주 | GPU 렌더링 기초 | 래스터화·정점/프래그먼트 셰이더·깊이/스텐실 개념. renderer/·fill.wgsl 정독. |
| 6주 | 텍스트·수식·3D·대화형 | LaTeX→SVG 파이프라인, Pango 텍스트, ThreeDScene, embed() 워크플로우. |
처음부터 wgpu 렌더러를 파려 하면 지친다. 1~3주는 사용자로서 예쁜 영상을 만들며 재미를 붙이고, 4주부터 독자로 전환해 manimlib/ 소스를 읽는 것이 지속 가능하다. 실제로 3Blue1Brown의 3b1b/videos 저장소에 모든 영상의 소스가 공개돼 있어, "이 장면은 어떻게 짰나"를 역으로 배울 수 있다.
manimgl, 이 저장소)는 3b1b 원조·빠른 실험판, 후자(manim)는 커뮤니티 안정·문서판. 코드 비호환. 튜토리얼 다수는 커뮤니티판 기준.construct()를 오버라이드해 add/play/wait로 연출을 적는다.get_family()는 자신과 모든 자손을 평탄화해 반환한다(변환 전파의 단위).smooth).mobj.animate.shift(RIGHT)..wgsl). 과거의 OpenGL/GLSL을 대체.fill.wgsl).