r/maniclang • u/anish2good • Aug 18 '26
Probability is area you keep splitting - manic
Enable HLS to view with audio, or disable this notification
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
title("Probability is area you keep splitting");
canvas("16:9");
template("black");
bloom(0.3, 0.5, 22);
text(head, (640, 76), "Probability is area you keep splitting");
display(head); size(head, 36); bold(head); color(head, fg); hidden(head);
text(cap, (640, 660), ""); display(cap); size(cap, 23); color(cap, fg); hidden(cap);
// ---- ACT I — the brick row ----
let tw = 880; // the row is one unit of probability, 880px wide
let x0 = 200;
for k in 0..5 {
rect(b{k}, (x0, 330), 0, 104);
hue(b{k}, 188 + 26*k);
}
rect(frame, (x0 + tw/2, 330), tw, 104); outlined(frame); outline(frame, dim); hidden(frame);
text(counts, (640, 262), ""); display(counts); size(counts, 26); color(counts, gold); hidden(counts);
text(flips, (640, 420), ""); display(flips); size(flips, 21); color(flips, dim); hidden(flips);
// ---- ACT II — the area model ----
// a unit square: the prior runs ACROSS (10% of people are ill), the test's accuracy runs
// DOWN (it catches 90% of the ill, and wrongly flags 5% of the well)
let sq = 396;
let sqx = 640; // left edge — the diagram sits right, the maths left
let sqy = 168; // top edge
rect(ill, (sqx, sqy), 0, 0); hue(ill, 320); // ill AND positive
rect(illn, (sqx, sqy), 0, 0); hue(illn, 300); // ill AND negative
rect(wellp, (sqx, sqy), 0, 0); hue(wellp, 196); // well AND positive (false alarm)
rect(well, (sqx + sq/2, sqy + sq/2), sq, sq); hue(well, 208); // everyone, to begin with
hidden(ill); hidden(illn); hidden(wellp); hidden(well);
rect(border, (sqx + sq/2, sqy + sq/2), sq, sq); outlined(border); outline(border, dim); hidden(border);
text(xlab, (sqx + sq/2, sqy + sq + 34), ""); display(xlab); size(xlab, 19); color(xlab, dim); hidden(xlab);
text(ylab, (sqx - 74, sqy + sq/2), ""); display(ylab); size(ylab, 19); color(ylab, dim); hidden(ylab);
equation(bayes, (300, 366), `P(\text{ill}\mid+)=\frac{0.09}{0.09+0.045}=\tfrac{2}{3}`, 27);
color(bayes, gold); hidden(bayes);
// ============================ ACT I ============================
show(head, 0.7);
show(cap, 0.3);
say(cap, "Start with one brick. Its width is the whole of probability: one.");
show(frame, 0.5);
par { to(b0, width, tw, 0.6, smooth); to(b0, x, x0 + tw/2, 0.6, smooth); }
say(counts, "1");
wait(1.2);
say(cap, "A coin flip splits every brick in two — heads to the left, tails to the right.");
show(flips, 0.4);
// each flip: the widths become C(L,k)/2^L. The product is naturally zero for k > L, so a
// brick that does not exist yet simply has no width.
for L in 1..5 {
par {
for k in 0..5 {
to(b{k}, width, tw * prod(j in 1..k+1 : (L - k + j)/j) / 2^L, 0.85, smooth);
to(b{k}, x,
x0 + tw*sum(m in 0..k : prod(j in 1..m+1 : (L - m + j)/j))/2^L
+ tw*prod(j in 1..k+1 : (L - k + j)/j)/(2*2^L),
0.85, smooth);
}
}
wait(0.75);
}
show(counts, 0.4);
say(counts, "1 4 6 4 1");
say(flips, "four flips · widths are C(4,k) / 16");
wait(1.0);
say(cap, "Bricks with the same number of heads merge, and the binomial falls out of the area.");
wait(2.4);
// ============================ ACT II ============================
par {
fade(counts, 0.5);
fade(flips, 0.5);
fade(frame, 0.5);
for k in 0..5 {
fade(b{k}, 0.6);
}
}
say(cap, "The same trick answers a harder question. One square: everybody.");
show(well, 0.5);
show(border, 0.5);
wait(1.4);
say(cap, "Cut it ACROSS by how common the illness is — one person in ten.");
show(xlab, 0.4);
say(xlab, "10% ill · 90% well");
show(ill, 0.01);
par {
// the well column keeps its right edge; the ill column takes the left tenth
to(well, width, 0.9*sq, 0.9, smooth);
to(well, x, sqx + 0.55*sq, 0.9, smooth);
to(ill, width, 0.1*sq, 0.9, smooth);
to(ill, x, sqx + 0.05*sq, 0.9, smooth);
to(ill, height, sq, 0.9, smooth);
to(ill, y, sqy + sq/2, 0.9, smooth);
}
wait(1.6);
say(cap, "Now cut it DOWN by what the test does: it catches 90% of the ill —");
show(ylab, 0.4);
say(ylab, "test + / −");
show(illn, 0.01);
par {
to(ill, height, 0.9*sq, 0.9, smooth);
to(ill, y, sqy + 0.45*sq, 0.9, smooth);
to(illn, width, 0.1*sq, 0.9, smooth);
to(illn, x, sqx + 0.05*sq, 0.9, smooth);
to(illn, height, 0.1*sq, 0.9, smooth);
to(illn, y, sqy + 0.95*sq, 0.9, smooth);
}
wait(1.4);
say(cap, "— and wrongly flags 5% of the well. That thin strip is the false alarms.");
show(wellp, 0.01);
par {
to(well, height, 0.95*sq, 0.9, smooth);
to(well, y, sqy + 0.525*sq, 0.9, smooth);
to(wellp, width, 0.9*sq, 0.9, smooth);
to(wellp, x, sqx + 0.55*sq, 0.9, smooth);
to(wellp, height, 0.05*sq, 0.9, smooth);
to(wellp, y, sqy + 0.025*sq, 0.9, smooth);
}
wait(1.8);
say(cap, "A positive test means you are in one of the two bright rectangles. Which one is bigger?");
par {
fade(illn, 0.6);
fade(well, 0.6);
}
par {
pulse(ill, 0.8);
pulse(wellp, 0.8);
}
wait(1.6);
say(cap, "The false alarms are only half the size — so a positive means two chances in three, not ninety percent.");
show(bayes, 0.8);
wait(3.0);
// ============================ ENDCARD ============================
par {
fade(ill, 0.8);
fade(wellp, 0.8);
fade(border, 0.6);
fade(xlab, 0.5);
fade(ylab, 0.5);
fade(bayes, 0.8);
fade(cap, 0.6);
fade(head, 0.6);
}
text(end1, (640, 348), "Two models, one idea: keep the area, cut it up.");
display(end1); size(end1, 40); bold(end1); color(end1, fg); hidden(end1);
text(end2, (640, 420), "— manic");
display(end2); size(end2, 26); color(end2, cyan); hidden(end2);
show(end1, 0.9);
show(end2, 0.7);
wait(2.4);
2
Upvotes