r/manim

▲ 6 r/manim

Check out my animated math visualizer!

screenshot of Reimann sum animation

Hi everybody!

I've been working on a browser-based python tool for making animated scientific and mathematical visualizations. I've used it to make a few different animations that I thought might be interesting. Namely, the Riemann sum, Bloch-sphere, and the Lorenz attractor.

Everything in each of the animations is generated from an editable Python script in the browser.

I'm calling the project Luxeris. It's still very early, but I've reached the point where I'd really like to see what mathematicians actually try to make with it.

https://luxeris.app

I would especially appreciate feedback on what kinds of mathematical visualizations you'd want a tool like this to support.

Thanks!

P.S. sorry in advance if this is a bad place to mention the tool. I just thought it was cool!

reddit.com
u/Brave_Jeweler_4801 — 1 day ago
▲ 0 r/manim

Which AI do you use to create videos? I see spend a lot of tokens!

I'm using Claude Opus 4.8 High and spend a lot of tokens creating a decent results.
How do you manage that? Do you have an Skill for that or use other LLM?

reddit.com
u/ScriptNone — 3 days ago
▲ 28 r/manim

Little Something I'm Working on for my YouTube Channel @Arithmetes

Let me know your thoughts!

u/fuckletoogan — 4 days ago
▲ 52 r/manim+1 crossposts

I made my own creature for my Manim videos, inspired by 3b1b's Pi creatures (open source)

I recently started a YouTube channel and I was inspired by Grant's Pi creatures. So I wanted to make my own, I'm calling it Sprout.

It doesn't carry a strong math theme the way π does, but I think it can still come in handy in my videos as a little on-screen companion.

It has 14 expression modes, gaze tracking, speech and thought bubbles, and a leaf that's always alive (idle sway + ambient motes).

I'm looking for feedback, I'm not a designer myself, so: does anything look off to you, or could be improved?

Also, here's the public GitHub repo for anyone who wants to use it, or to fork it as a starting point for their own character:
https://github.com/HamdiBarkous/Sprout

u/Hamdi_bks — 8 days ago
▲ 69 r/manim+3 crossposts

Vectors, basis, and transformations - manic

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// ============================================================================
//  Essence of Linear Algebra, chapters 1→2→3 in one arc.
//
//  Ch1  A vector is an arrow from the origin; its coordinates are [x, y].
//  Ch2  Those coordinates are SCALARS: v = x·î + y·ĵ — a linear combination of
//       the basis vectors î=(1,0), ĵ=(0,1).
//  Ch3  A matrix is a transformation: it says where î and ĵ LAND, and the whole
//       grid morphs to follow (`gridmap` animates it). Because v = x·î + y·ĵ,
//       it rides along, landing at x·(new î) + y·(new ĵ).
//
//  Example: v = [1, 2] under [[2,1],[1,2]] (î→(2,1), ĵ→(1,2)), so v lands at
//  1·(2,1) + 2·(1,2) = (4,5). Origin (400,470), 55 px/unit.
// ============================================================================
title("Vectors, basis, and transformations");
canvas(1280, 720);
template("black");

text(narr, (640, 696), "A vector is an arrow from the origin.", 24);

// the plane + basis, ready to be transformed in Ch3 (starts at the identity)
gridmap(gm, (400, 470), 55, 2, 1, 1, 2, 5);

// the vector v = [1,2] and its linear-combination scaffold
vector(v, (400, 470), (55, 110), yellow);
vector(jj, (455, 470), (0, 110), red);           // 2·j-hat, stacked on i-hat → reaches v
equation(vlab, (486, 352), `\vec{v}=[1,2]`, 30); color(vlab, yellow);
equation(ilab, (472, 500), `\hat{\imath}`, 26); color(ilab, lime);
equation(jlab, (366, 414), `\hat{\jmath}`, 26); color(jlab, red);
equation(mtx, (980, 165), `\begin{bmatrix}2&1\\1&2\end{bmatrix}`, 44);

// Ch4 — a second transform (90° rotation) composed on top: morph M1 → M2·M1
gridmap(gm2, (400, 470), 55, -1, -2, 2, 1, 5, 2, 1, 1, 2);
equation(comp4, (640, 96), `\begin{bmatrix}0&-1\\1&0\end{bmatrix}\begin{bmatrix}2&1\\1&2\end{bmatrix}=\begin{bmatrix}-1&-2\\2&1\end{bmatrix}`, 34);

// the determinant cell (Ch5), the projection (Ch7), and the alt-basis grid (Ch8)
determinant(dt, (400, 470), 55, 2, 1, 1, 2, gold);
project(pr, (400, 470), 55, (1, 2), (3, 1));       // project v=(1,2) onto span(w=(3,1))
squish(sq, (400, 470), 55, 1, 2, 5);               // Ch7 duality: dot with v = squish onto a line
eigen(ev, (400, 470), 55, 2, 1, 1, 2, gold);       // Ch9 eigenvectors of [[2,1],[1,2]] (λ = 3, 1)
diagonalise(dg, (400, 470), 55, 2, 1, 1, 2, gold); // Ch10 eigenbasis = a pure stretch
coords(cf, (700, 450), (-4, 4), (-3, 3), 46, 46, 0); // Ch11 a function graph…
plot(fn, (700, 450), 46, 46, "0.25*x*x*x - x", (-3.6, 3.6)); color(fn, mint);
equation(deq, (700, 130), `\tfrac{d}{dx}\;\leftrightarrow\;\begin{bmatrix}0&1&0\\0&0&2\\0&0&0\end{bmatrix}`, 32);
gridmap(cb, (400, 470), 55, 1, 0.7, 0.4, 1, 5);
vector(vb, (400, 470), (55, 110), yellow);

// --- initial visibility ---
hidden(gm.i); hidden(gm.j);                       // basis revealed in Ch2
hidden(v); hidden(vlab); hidden(jj); hidden(ilab); hidden(jlab); hidden(mtx);
hidden(dt); hidden(dt.unit); hidden(dt.val); hidden(pr);
hidden(sq); hidden(sq.line); hidden(sq.dual);
hidden(ev); hidden(dg); hidden(cf); hidden(fn); hidden(deq);
hidden(gm2); hidden(gm2.bg); hidden(gm2.i); hidden(gm2.j); hidden(comp4);
hidden(cb); hidden(cb.bg); hidden(cb.i); hidden(cb.j); hidden(vb);

// --- Ch1: a vector ---
wait(0.5);
par { show(v); show(vlab); }
wait(1.3);

// --- Ch2: coordinates are a linear combination of the basis ---
say(narr, "Its coordinates are scalars: v = 1·i-hat + 2·j-hat.");
par { show(gm.i); show(gm.j); show(ilab); show(jlab); }
wait(0.7);
show(jj);                                         // i-hat then two j-hats reach v
wait(1.6);

// --- Ch3: the matrix transforms space; v rides along ---
say(narr, "A matrix moves i-hat and j-hat — and the whole grid follows.");
show(mtx);
par { fade(jj); fade(ilab); fade(jlab); fade(vlab); }
par { to(gm, morph, 1, 2.2); grow(v, (620, 195), 2.2); }   // space deforms, v follows
wait(0.6);
say(narr, "v lands at 1·(new i-hat) + 2·(new j-hat) = (4,5).");
wait(1.6);

// --- Ch4: matrix multiplication is composition ---
say(narr, "Ch 4 — apply one transform, then another: that is matrix multiplication.");
show(comp4);                                       // the product, clearly placed up top
par { fade(gm); fade(v); }
show(gm2);                                          // starts at M1 (seamless with Ch3)
to(gm2, morph, 1, 1.8);                             // now rotate 90°: the grid is at M2·M1
wait(1.3);
to(gm2, morph, 0, 1.5);                             // undo the second transform, back to M1
par { fade(gm2); fade(comp4); }
par { show(gm); show(v); }
wait(0.6);

// --- Ch5: the determinant is the area scale factor ---
say(narr, "Ch 5 — the determinant is how much areas scale: 2·2 − 1·1 = 3.");
par { show(dt); show(dt.unit); show(dt.val); }
wait(1.9);
par { fade(dt); fade(dt.unit); fade(dt.val); }    // fade = timeline hide (hidden is base-state only)

// --- Ch6: column space + the inverse undoes the transform ---
say(narr, "Ch 6 — the columns span the whole plane, so the inverse sends space back.");
par { to(gm, morph, 0, 1.8); grow(v, (455, 360), 1.8); }   // reverse the morph = the inverse
wait(1.4);

// --- Ch7: the dot product — projection, and its dual (a squish onto a line) ---
say(narr, "Ch 7 — the dot product of v and w is a projection — w's shadow on v.");
par { fade(gm); fade(gm.bg); fade(v); fade(mtx); }
show(pr);
wait(1.6);
say(narr, "It's also a squish of the whole plane onto a line — the dual vector IS v.");
fade(pr);
par { show(sq); show(sq.line); show(sq.dual); }
to(sq, morph, 1, 1.9);                              // collapse space onto the number line
wait(1.0);
to(sq, morph, 0, 1.2);                              // and back — the dual vector remains
wait(0.8);

// --- Ch8: change of basis ---
say(narr, "Ch 8 — change of basis: the same arrow, read on a different grid.");
par { fade(sq); fade(sq.line); fade(sq.dual); }
par { show(cb); show(vb); }
to(cb, morph, 1, 1.8);                                       // the coordinate grid changes; v stays put
wait(1.8);

// --- Ch9: eigenvectors and eigenvalues ---
say(narr, "Ch 9 — some vectors keep to their own line: eigenvectors (λ = 3 and λ = 1).");
par { fade(cb); fade(vb); }
show(ev);
wait(2.0);

// --- Ch10: the eigenbasis is a pure stretch ---
say(narr, "Ch 10 — in the eigenbasis, the transformation is just a diagonal stretch.");
fade(ev);
show(dg);
wait(2.0);

// --- Ch11: abstract vector spaces ---
say(narr, "Ch 11 — even functions are vectors; the derivative is a linear map with a matrix.");
fade(dg);
par { show(cf); show(fn); show(deq); }
wait(2.2);
u/anish2good — 9 days ago
▲ 35 r/manim

Manim v0.21.0 has been released! 🚨🎉

This release brings 60 changes, including a new text-rendering option, substantial performance improvements, and fixes across Cairo, OpenGL, MathTex, Code, scene caching, and more.

Highlights

  • First-class Typst support: The new Typst and MathTypst mobjects render markup and mathematics directly to SVG without requiring a TeX installation. Install support with pip install "manim[typst]".
  • Faster Cairo rendering: Animation-heavy scenes rendered about 2× faster in benchmarks.
  • Parallel encoding: Partial movie files can now be encoded concurrently. This is opt-in through the new max_inflight_encoders setting, so existing behavior remains unchanged by default.
  • Faster, safer cache hashing: NumPy arrays are now hashed from their complete contents, preventing stale cache hits while reducing hashing time by roughly 94–98% in representative benchmarks.
  • Plenty of quality-of-life improvements: Multiline MathTex, configurable BulletedList spacing, optional inner lines for tables, multiple TexTemplate compiler passes, more chainable mobject methods, and much more.

There are two breaking changes worth checking if you use Code color styling or call Camera.convert_pixel_array() directly—see the full release notes for migration details.

A huge thank-you to everyone who contributed, especially our 27 first-time contributors! 💚

Full changelog: https://docs.manim.community/en/stable/changelog/0.21.0-changelog.html
GitHub release: https://github.com/ManimCommunity/manim/releases/tag/v0.21.0

reddit.com
u/behackl — 10 days ago
▲ 24 r/manim+5 crossposts

My entry for SoME5

Experimenting with softbody physics in Manim. The scene with all the individual blocks falling took my laptop 5 hours to render, just as long as the rest of the video😅 Made with Manim and TouchDesigner

youtu.be
u/matigekunst — 10 days ago
▲ 68 r/manim+2 crossposts

I made an animated video introducing quantum mechanics using Manim and Blender for the first time

Any feedback would be appreciated as it's my first video using both Blender and Manim together.

youtu.be
u/Dizzy_Complaint3326 — 13 days ago
▲ 25 r/manim+3 crossposts

quantum-double-slit — one particle, two slits, ONE field, three faces - manic

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// quantum-double-slit — one particle, two slits, ONE field, three faces.
//
// The whole experiment's physics is authored ONCE, as a `field`:
//   |psi|^2(x,y) = sinc^2( single-slit diffraction )  ·  cos^2( two-slit interference )
// the EXACT Fraunhofer double-slit intensity (sinc^2 envelope with its real nulls /
// "missing orders", not a gaussian fudge). That single `field(psi2,…)` then drives all
// three views — a per-pixel heatmap, the detection screen (dots + curve), and a 3-D
// amplitude surface — so they are provably the SAME expression, not three drifting models.
//
// Act I shows the animated REAL wave Re(psi) rolling through the slits (a live wavelength
// slider tightens the fringes — Δy ∝ λ). That real ripple is honestly distinguished from
// what a detector records: the intensity |psi|^2. Equations shown are all exact:
//   ψ = ψ1 + ψ2 ,   I = |ψ1+ψ2|^2 ≠ |ψ1|^2 + |ψ2|^2 ,   Δy = λL/d.
//
//   manic examples/quantum-double-slit.manic
title("One Particle, Two Slits");
canvas("16:9");
template("black");
bloom(0.32, 0.55, 30);

// ===== the physics, authored ONCE (slits at (0, ±0.5), screen sampled at x = 4.5) =====
field(psi2, "sinc(8.0*y/hypot(x+0.15, y))^2 * cos(24.0*(hypot(x, y-0.5) - hypot(x, y+0.5)))^2");

parameter(lam, (w - 175, 150), 0.55, 0.30, 0.90, "wavelength", 2);

// ---- Act I: the animated REAL wave Re(psi) — plane wave -> two slits -> superposition ----
shader(wave) {
  let k = 6.2832 / lam;
  let wv = 6.0;
  let px = (u - 0.5) * asp * 5.0 + 1.5;      // world x  (slit plane at x=0)
  let py = (v - 0.5) * 6.0;                   // world y  (transverse)
  let m1 = step(0.0, px);
  let r1 = hypot(px, py - 0.5) + 0.001;
  let r2 = hypot(px, py + 0.5) + 0.001;
  let a1 = cos(k*r1 - wv*t) / sqrt(1.0 + 1.4*r1);
  let a2 = cos(k*r2 - wv*t) / sqrt(1.0 + 1.4*r2);
  let pl = 0.72 * cos(k*px - wv*t);
  let re = (1.0 - m1)*pl + 0.8*m1*(a1 + a2);
  let s = tanh(1.6 * re);
  let r = 0.34 + 0.42*s;
  let g = 0.18 + 0.10*abs(s);
  let b = 0.66 - 0.34*s;
}
z(wave, -10);

// ---- the |psi|^2 heatmap of the SAME field (revealed after the wave settles) ----
shader(field2) {
  let px = (u - 0.5) * asp * 5.0 + 1.5;
  let py = (v - 0.5) * 6.0;
  let d = psi2(px, py);                        // <-- the SAME field
  let r = 0.08 + 1.20*d;
  let g = 0.05 + 0.55*d*d;
  let b = 0.26 + 0.75*d;
}
z(field2, -9); hidden(field2);

// ---- the barrier with two slits (world x=0 -> ~424px; slits at world y=±0.5) ----
rect(wal1, (424, 150), 12, 300); tag(wal1, wall);
rect(wal2, (424, 360), 12, 96);  tag(wal2, wall);
rect(wal3, (424, 570), 12, 300); tag(wal3, wall);
line(scr, (1130, 70), (1130, 650)); stroke(scr, 3); color(scr, gold); untraced(scr);
text(scrl, (1130, 52), "screen"); size(scrl, 20); color(scrl, gold); plate(scrl); hidden(scrl);

// ---- Act II: the detection screen (dots + curve), sampled from the SAME field ----
// dot i survives iff hash(i) < |psi|^2 at its transverse position — honest rejection
// sampling against the field, at the screen line x=4.5.
cloud(hits, 4200, #ffffff, 0.95) {
  let rn = mod(abs(sin(i * 12.9898) * 43758.55), 1);
  let rn2 = mod(abs(sin(i * 78.233) * 12543.7), 1);
  let rn3 = mod(abs(sin(i * 45.164) * 9631.4), 1);
  let ys = mod(i * 0.61803, 1) * 5.0 - 2.5;                 // transverse position
  let inten = psi2(4.5, ys);                                // <-- the SAME field
  let survive = step(rn, inten);
  let ap = smoothstep(0, 0.2, t - (24.5 + 12.0 * rn2));
  let x = 640 + ys * 150;
  let y = 360 + (rn3 - 0.5) * 380;
  let r = 2.0 * survive * ap;
  let hue = 45 + 20 * rn;
}
hidden(hits);
plot(icur, (cx, 620), 150, 150, "psi2(4.5, x)", (-2.5, 2.5));
untraced(icur); stroke(icur, 3); gradient(icur, blue, gold, 270);

// ---- Act III: the SAME field as a 3-D amplitude surface ----
camera3((6.4, -6.6, 4.4), (2.3, 0, 0.3), 44);
surface3(surf, "psi2(x, y)", (0.35, 5.0), (-2.6, 2.6), 96); hidden(surf); color(surf, gold);

// ---- HUD ----
text(head, (cx, 52), "One Particle, Two Slits"); size(head, 36); color(head, white); glow(head, 6); plate(head); display(head); cursor(head);
text(cap, (cx, h - 40), ""); size(cap, 24); color(cap, white); plate(cap);
equation(eqQ, (cx, 128), `\psi \;=\; \psi_1 + \psi_2`, 30); plate(eqQ); hidden(eqQ);
counter(nhit, (w - 175, 250), 0, 0, "detections ", ""); color(nhit, gold); hidden(nhit);

// ================= timeline =================

// ---- Act I: the wave meets the wall
type(head, 1.1);
show(scrl, 0.4);
draw(scr, 0.7);
say(cap, "a quantum wave rolls toward a wall with two openings", 0.6);
show(eqQ, 0.6);
wait(2.4);
say(cap, "beyond the slits: TWO waves - from ONE particle - overlapping", 0.5);
wait(2.6);
cue(tick);
say(cap, "shorter wavelength, tighter fringes - the spacing goes as lambda", 0.5);
to(lam, value, 0.36, 2.0, smooth);
wait(1.0);
to(lam, value, 0.6, 1.6, smooth);
wait(0.8);

// ---- the honest reframe: real wave vs. what is measured
cue(tick);
say(cap, "but this rippling is the REAL part of the wave - a detector never sees it", 0.6);
wait(2.0);
rewrite(eqQ, `I \;=\; |\psi|^{2}`, 0.9);
say(cap, "what it records is the INTENSITY - one field, |psi| squared", 0.6);
par { show(field2, 1.3); fade(wave, 1.3); }
wait(1.4);

// ---- Act II: one particle at a time, drawn from that field
cue(whoosh);
say(cap, "now face the screen - send the particles through ONE AT A TIME", 0.5);
par { fade(field2, 0.9); fade(wall, 0.8); fade(scr, 0.7); fade(scrl, 0.7); fade(lam, 0.7); }
par { show(hits, 0.4); show(nhit, 0.3); }
cue(tick);
rewrite(eqQ, `I \;=\; |\psi_1+\psi_2|^{2} \;\neq\; |\psi_1|^{2}+|\psi_2|^{2}`, 0.9);
par {
  to(nhit, value, 1600, 15, linear);
  seq {
    say(cap, "each electron lands at a single point - apparently at random...", 0.5);
    wait(5.0);
    say(cap, "...yet none EVER land in the dark bands - not even the diffraction nulls", 0.5);
    wait(4.5);
    say(cap, "the stripes assemble - one self-interfering particle at a time", 0.5);
    wait(3.5);
  }
}
draw(icur, 1.6);
cue(chime);
say(cap, "every dot is drawn from that ONE field - it traces |psi| squared exactly", 0.6);
wait(2.2);

// ---- Act III: the same field, as a landscape
cue(whoosh);
par { fade(hits, 0.9); fade(icur, 0.7); fade(nhit, 0.6); }
par { show(surf, 1.2); }
say(cap, "the same field a third time - now as terrain: peaks bright, valleys silent", 0.6);
par { to(nhit, value, 1600, 0.1, linear); orbit3(-26, 26, 8.6, 6, smooth); }
say(cap, "along the nodal rays the two waves cancel forever - flat valleys of never", 0.6);
cue(tick);
rewrite(eqQ, `\boxed{\;\Delta y \;=\; \dfrac{\lambda L}{d}\;}`, 1.0);
par { orbit3(20, 18, 8.0, 5, smooth); breathe(eqQ, 3, 0.05, 0, 5); }
say(cap, "one particle, two paths, one field - the same physics in every view", 0.7);
wait(2.6);
u/anish2good — 11 days ago
▲ 5 r/manim

Is anyone using manim for non Math vidoes

I know manim is built for math but, I have a feeling it can be useful for many other types of animations and visuals. Curious if there's anyone out there making videos not related to math? If so, what kinds of videos are you making?

reddit.com
u/working_unicorn — 13 days ago
▲ 26 r/manim+1 crossposts

When integrals become random

Hey everyone,

I’m a researcher in computational mathematics, and I recently started playing around with Manim out of interest to communicate some of the aspects of my work to a larger audience. It remains to be seen how successful that will be ;)

I uploaded a video explaining the basics of stochastic integration.
What started as a "quick experiment" quickly got out of control a bit... Though I'm content with the results, there's clearly some points that I'd like to improve. Not just manim things, but also narration, and the entire process of video making.

I’d be happy for you to check out the video and provide feedback on the delivery!

Cheers!

youtube.com
u/Sagye — 11 days ago
▲ 0 r/manim

Could vibe coding make Manim a major tool for visual generation?

I've been using Manim and Claude to fill in the gaps I have in my videos. For instance, if I've got X seconds of dialogue with no visual, I give my dialogue to Claude and ask it to generate some Manim that I then fine-tune.

Sometimes I'll add layers on top of the visual in my video editor when it is too specific, but I find this system to work really well and it's incredibly fast.

It really makes me believe that code-based illustration generators have huge potential with AI, sure image generation models exist, but most of the time you can tell, it's the whole "AI slop" thing, while visuals generated by Manim are clean and "human".

What do you guys think? Is vibe-coding good for Manim? Could Manim evolve one day to be more used outside of math-related videos and more "all public" videos?

u/DataVisionStudio — 11 days ago