Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Calculus & functions

Each block is the whole file — copy it into x.manic and run manic x.manic (live) or --record out (video).

calculus-demo

The flagship: two big ideas on one curve. A tangent slides along a bell curve with a live slope readout (flat at the peak), then the area sweeps open while the integral climbs to its true value — on properly numbered, scaled axes.

title("Calculus, visualized — the derivative and the integral");
canvas("16:9");

// screen anchor for the plot: math (0,0) maps here. Placing it at cx-450 with
// sx=150 centres the domain 0..6 under the canvas centre.
let ox = cx - 450;
let oy = cy + 120;
let sx = 150;          // screen px per unit of x
let sy = 170;          // screen px per unit of y

// ---------------- header ----------------
text(hdr, (cx, 54), "Two big ideas, one curve");
size(hdr, 32); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

text(flabel, (cx, 94), "f(x) = a smooth bell-shaped curve");
size(flabel, 18); color(flabel, dim); display(flabel); hidden(flabel);

// ---------------- the curve ----------------
axes(ax, (ox, oy), 930, 205, 1);
color(ax, dim); untraced(ax);

// axis labels, at the arrow tips
text(xlab, (ox + 958, oy + 6), "x");
size(xlab, 24); color(xlab, dim); display(xlab); hidden(xlab);

text(ylab, (ox, oy - 232), "f(x)");
size(ylab, 24); color(ylab, dim); display(ylab); hidden(ylab);

// numbered scale — each label sits at the plot's real coordinate:
// x = k  ->  (ox + k*sx, oy)      y = v  ->  (ox, oy - v*sy)
line(tx1, (ox + 1*sx, oy - 7), (ox + 1*sx, oy + 7)); color(tx1, dim); tag(tx1, scale); hidden(tx1);
line(tx2, (ox + 2*sx, oy - 7), (ox + 2*sx, oy + 7)); color(tx2, dim); tag(tx2, scale); hidden(tx2);
line(tx3, (ox + 3*sx, oy - 7), (ox + 3*sx, oy + 7)); color(tx3, dim); tag(tx3, scale); hidden(tx3);
line(tx4, (ox + 4*sx, oy - 7), (ox + 4*sx, oy + 7)); color(tx4, dim); tag(tx4, scale); hidden(tx4);
line(tx5, (ox + 5*sx, oy - 7), (ox + 5*sx, oy + 7)); color(tx5, dim); tag(tx5, scale); hidden(tx5);
line(tx6, (ox + 6*sx, oy - 7), (ox + 6*sx, oy + 7)); color(tx6, dim); tag(tx6, scale); hidden(tx6);

text(nx1, (ox + 1*sx, oy + 28), "1"); size(nx1, 16); color(nx1, dim); tag(nx1, scale); hidden(nx1);
text(nx2, (ox + 2*sx, oy + 28), "2"); size(nx2, 16); color(nx2, dim); tag(nx2, scale); hidden(nx2);
text(nx3, (ox + 3*sx, oy + 28), "3"); size(nx3, 16); color(nx3, dim); tag(nx3, scale); hidden(nx3);
text(nx4, (ox + 4*sx, oy + 28), "4"); size(nx4, 16); color(nx4, dim); tag(nx4, scale); hidden(nx4);
text(nx5, (ox + 5*sx, oy + 28), "5"); size(nx5, 16); color(nx5, dim); tag(nx5, scale); hidden(nx5);
text(nx6, (ox + 6*sx, oy + 28), "6"); size(nx6, 16); color(nx6, dim); tag(nx6, scale); hidden(nx6);

line(tyh, (ox - 7, oy - 0.5*sy), (ox + 7, oy - 0.5*sy)); color(tyh, dim); tag(tyh, scale); hidden(tyh);
line(ty1, (ox - 7, oy - 1*sy),   (ox + 7, oy - 1*sy));   color(ty1, dim); tag(ty1, scale); hidden(ty1);
text(nyh, (ox - 36, oy - 0.5*sy), "0.5"); size(nyh, 16); color(nyh, dim); tag(nyh, scale); hidden(nyh);
text(ny1, (ox - 24, oy - 1*sy),   "1");   size(ny1, 16); color(ny1, dim); tag(ny1, scale); hidden(ny1);

plot(f, (ox, oy), sx, sy, "exp(-0.5*(x-3)*(x-3))", (0, 6));
color(f, cyan); stroke(f, 4); untraced(f);

// ---------------- captions (swap per act) ----------------
text(capd, (cx, h - 46), "THE DERIVATIVE   —   the slope at every point");
size(capd, 22); color(capd, gold); bold(capd); display(capd); hidden(capd);

text(capi, (cx, h - 46), "THE INTEGRAL   —   the area underneath");
size(capi, 22); color(capi, lime); bold(capi); display(capi); hidden(capi);

text(endcap, (cx, h - 46), "two views of one curve");
size(endcap, 22); color(endcap, cyan); bold(endcap); display(endcap); hidden(endcap);

// ---------------- derivative pieces ----------------
tangent(tan, f, 0.4, 220);
color(tan, gold); hidden(tan);

slope(sl, f, 0.4);
color(sl, gold); hidden(sl);

// ---------------- integral pieces ----------------
area(reg, f, 0, 0);
color(reg, lime);

text(ivlabel, (cx + 330, cy - 150), "area so far");
size(ivlabel, 16); color(ivlabel, dim); display(ivlabel); hidden(ivlabel);

integral(iv, f, 0, 0, (cx + 330, cy - 110));
size(iv, 30); color(iv, lime); hidden(iv);

// ================= timeline =================
show(hdr, 0.6);
show(flabel, 0.4);
draw(ax, 0.8);
par {
  show(xlab, 0.4);
  show(ylab, 0.4);
  show(scale, 0.4);
}
draw(f, 1.6);
wait(0.4);

// --- Act 1: the derivative ---
show(capd, 0.5);
show(tan, 0.5);
show(sl, 0.4);
wait(0.3);
par {                                 // climb to the peak — slope goes to zero
  to(tan, x, 3, 2.2);
  to(sl, x, 3, 2.2);
}
pulse(sl, 0.5);
wait(0.3);
par {                                 // over the top — slope turns negative
  to(tan, x, 5.6, 2.6);
  to(sl, x, 5.6, 2.6);
}
wait(0.4);

// --- Act 2: the integral ---
par {
  fade(capd, 0.4);
  fade(tan, 0.4);
  fade(sl, 0.4);
}
show(capi, 0.5);
show(ivlabel, 0.3);
show(iv, 0.3);
par {                                 // sweep the area open, number climbs
  to(reg, x, 6, 4);
  to(iv, x, 6, 4);
}
wait(0.4);
flash(iv, lime);
pulse(iv, 0.5);
wait(0.4);

// --- close ---
fade(capi, 0.4);
show(endcap, 0.6);

calculus-one

Calculus I end to end in one continuous scene: limits (a curve with a hole), the derivative (secants collapsing onto the tangent), curve shape, and the integral + Fundamental Theorem — chapter wipes between.

title("Calculus I, End to End");
canvas("16:9");
template("black");

// ================= HUD (sticky: survives every camera move) =================
text(head, (cx, 60), "Calculus I, End to End"); display(head); cursor(head); sticky(head);
text(h1, (cx, 148), "1. Limits - getting close without arriving"); size(h1, 28); color(h1, cyan); hidden(h1); sticky(h1);
text(h2, (cx, 148), "2. The derivative - a slope caught in the act"); size(h2, 28); color(h2, magenta); hidden(h2); sticky(h2);
text(h3, (cx, 148), "3. What f' knows about the shape of f"); size(h3, 28); color(h3, lime); hidden(h3); sticky(h3);
text(h4, (cx, 148), "4. The integral - area, one strip at a time"); size(h4, 28); color(h4, gold); hidden(h4); sticky(h4);
text(h5, (cx, 148), "5. The Fundamental Theorem - the bridge"); size(h5, 28); hidden(h5); sticky(h5);
text(cap, (cx, h - 42), ""); size(cap, 26); sticky(cap);

caption(menu, "limits - slopes - shapes - areas - the bridge", (cx, cy), 34, gold); hidden(menu);

// chapter wipes, tinted to the incoming chapter
line(w2, (-40, 140), (-40, h - 90)); stroke(w2, 4); color(w2, magenta); glow(w2, 14);
line(w3, (-40, 140), (-40, h - 90)); stroke(w3, 4); color(w3, lime); glow(w3, 14);
line(w4, (-40, 140), (-40, h - 90)); stroke(w4, 4); color(w4, gold); glow(w4, 14);
line(w5, (-40, 140), (-40, h - 90)); stroke(w5, 4); glow(w5, 14);

// ================= ch 1 cast: LIMITS =================
// example A: f(x) = (x^3 - x)/(x - 1) = x(x+1) away from the hole at x = 1
// example B: a limit at infinity - the sigmoid hugging its asymptote
let gx1 = cx + 34;
let gy = 560;
arrow(x1a, (cx - 380, gy), (cx + 390, gy)); untraced(x1a); stroke(x1a, 3); tag(x1a, c1);
arrow(y1a, (gx1, gy), (gx1, 235)); untraced(y1a); stroke(y1a, 3); tag(y1a, c1);
plot(p1, (gx1, gy), 170, 60, "x^2+x", (-2.2, 1.8));
untraced(p1); stroke(p1, 4); gradient(p1, blue, cyan, gold, 270); tag(p1, c1);
dot(rider, (gx1, gy), 7); color(rider, gold); glow(rider, 8); hidden(rider); tag(rider, c1);
limit(lm, p1, 1, gold); hidden(lm); tag(lm, c1);
plot(p1b, (gx1, gy), 170, 60, "4/(1+exp(-2.2*x))", (-2.2, 1.8));
untraced(p1b); stroke(p1b, 4); color(p1b, teal); tag(p1b, c1);
limit(lmb, p1b, inf, cyan); hidden(lmb); tag(lmb, c1);
equation(eq1, (cx, 230), `\lim_{x\to 1}\frac{x^3-x}{x-1}`, 40); hidden(eq1); sticky(eq1);

// ================= ch 2 cast: THE DERIVATIVE =================
// example A: f(x) = x^2/2, secants through (1, 0.5) collapse onto the tangent
// example B: sine's recorded slope is cosine
let gx2 = cx - 170;
arrow(x2a, (cx - 312, gy), (cx + 322, gy)); untraced(x2a); stroke(x2a, 3); tag(x2a, c2);
arrow(y2a, (gx2, gy), (gx2, 240)); untraced(y2a); stroke(y2a, 3); tag(y2a, c2);
plot(p2, (gx2, gy), 170, 80, "0.5*x^2", (-0.6, 2.6));
untraced(p2); stroke(p2, 4); gradient(p2, blue, magenta, 270); tag(p2, c2);
dot(anch, (gx2 + 170, gy - 40), 7); color(anch, gold); glow(anch, 8); hidden(anch); tag(anch, c2);
for k in 0..3 {
  let hh = 1.5 - 0.6*k;
  let mm = 1 + hh/2;
  let ya = 0.5 - 0.9*mm;
  let yb = 0.5 + 1.4*mm;
  line(sec{k}, (gx2 + 17, gy - ya*80), (gx2 + 408, gy - yb*80));
  stroke(sec{k}, 3); color(sec{k}, teal); opacity(sec{k}, 0.45 + 0.2*k); hidden(sec{k}); tag(sec{k}, c2);
  dot(sd{k}, (gx2 + (1 + hh)*170, gy - ((1 + hh)^2/2)*80), 6);
  color(sd{k}, teal); hidden(sd{k}); tag(sd{k}, c2);
}
tangent(tg2, p2, 1, 280); hidden(tg2); tag(tg2, c2);
slope(sl2, p2, 1); hidden(sl2); tag(sl2, c2);
deriv(dv2, p2, magenta); untraced(dv2); tag(dv2, c2);
line(bl2, (gx2 - 90, 445), (gx2 + 445, 445)); dashed(bl2); stroke(bl2, 2); color(bl2, dim); hidden(bl2); tag(bl2, c2);
plot(p2s, (gx2, 445), 170, 80, "1.1*sin(1.8*x)", (-0.5, 2.6));
untraced(p2s); stroke(p2s, 4); color(p2s, cyan); tag(p2s, c2);
deriv(dvs, p2s, magenta); untraced(dvs); dashed(dvs, 12, 9); tag(dvs, c2);
equation(eq2, (cx, 230), `f'(1) \;=\; \lim_{h\to 0}\frac{f(1+h)-f(1)}{h}`, 38); hidden(eq2); sticky(eq2);

// ================= ch 3 cast: SHAPE =================
// f(x) = x^3/3 - x : turning points at x = -1, 1; concavity flips at 0
// (one horizontal axis only - no vertical line slicing through the curve)
let gy3 = 420;
arrow(x3a, (cx - 436, gy3), (cx + 446, gy3)); untraced(x3a); stroke(x3a, 3); tag(x3a, c3);
plot(p3, (cx, gy3), 180, 150, "x^3/3-x", (-2.2, 2.2));
untraced(p3); stroke(p3, 4); gradient(p3, blue, lime, gold, 270); tag(p3, c3);
tangent(tg3, p3, -2.1, 300); hidden(tg3); tag(tg3, c3);
slope(sl3, p3, -2.1); hidden(sl3); tag(sl3, c3);
extrema(ex3, p3, gold); hidden(ex3); tag(ex3, c3);
inflections(if3, p3, magenta); hidden(if3); tag(if3, c3);
equation(eq3, (cx, 230), `f'(x)=x^2-1`, 38); hidden(eq3); sticky(eq3);

// ================= ch 4 + 5 cast: INTEGRAL and the FTC =================
// example A: f(x) = 0.3 x (4 - x), area 0..4 is exactly 3.2
// example B: a sine arch whose signed area cancels to zero
let gx4 = cx - 340;
arrow(x4a, (gx4 - 40, gy), (gx4 + 730, gy)); untraced(x4a); stroke(x4a, 3); tag(x4a, c4);
arrow(y4a, (gx4, gy), (gx4, 240)); untraced(y4a); stroke(y4a, 3); tag(y4a, c4);
plot(p4, (gx4, gy), 170, 80, "0.3*x*(4-x)", (0, 4));
untraced(p4); stroke(p4, 4); gradient(p4, blue, gold, 270); tag(p4, c4);
for i in 0..8 {
  let xm = (i + 0.5)*0.5;
  let hgt = 0.3*xm*(4 - xm);
  rect(rs{i}, (gx4 + xm*170, gy - hgt*80/2 + 24), 0.5*170 - 3, hgt*80);
  color(rs{i}, gold); opacity(rs{i}, 0.55); tag(rs{i}, rstrips);
}
hidden(rstrips);
area(ar4, p4, 0, 0); color(ar4, gold); opacity(ar4, 0.3);
integral(int4, p4, 0, 0, (gx4 + 640, 300)); hidden(int4);
plot(p4b, (gx4, gy), 170, 80, "1.2*sin(1.5708*x)", (0, 4));
untraced(p4b); stroke(p4b, 4); color(p4b, teal);
area(arb, p4b, 0, 0); color(arb, teal); opacity(arb, 0.3);
integral(intb, p4b, 0, 0, (gx4 + 640, 350)); hidden(intb);
equation(eq4, (cx, 230), `A \;\approx\; \sum_i \textcolor{gold}{f(x_i)}\,\Delta x`, 38); hidden(eq4); sticky(eq4);

// FTC: the accumulation A(x) drawn as its own curve, then ITS derivative
accum(acF, p4, 0, gold); untraced(acF);
deriv(dfF, acF, magenta); untraced(dfF); dashed(dfF, 12, 9);
text(alab, (gx4 + 700, 296), "A(x) - area so far"); size(alab, 24); color(alab, gold); hidden(alab);
text(flab, (cx, 430), "f(x)"); size(flab, 24); color(flab, cyan); hidden(flab);
equation(eqF, (cx, 230), `A(x) \;=\; \int_0^x f(t)\,dt`, 40); hidden(eqF); sticky(eqF); z(eqF, 10);

// finale
circle(confbox, (cx, 230), 80); hidden(confbox);
particles(conf, confbox, 22, 4, 9, "ring"); color(conf, gold); hidden(conf);
caption(r1, "zoom in: the derivative is the slope of a moment", (cx, 400), 28, magenta); hidden(r1);
caption(r2, "add up: the integral is the area of a journey", (cx, 455), 28, gold); hidden(r2);
caption(r3, "the Fundamental Theorem: each undoes the other", (cx, 510), 28); hidden(r3);

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

// ---- cold open
type(head, 1.2);
wordpop(menu, 0.07);
wait(1.0);
fade(menu, 0.5);

// ---- ch 1: LIMITS ------------------------------------------------------
mark("limits");
cue(whoosh);
show(h1, 0.5);
par { draw(x1a, 0.6); draw(y1a, 0.6); }
show(rider, 0.2);
par { draw(p1, 1.4); travel(rider, p1, 1.4, smooth); }
fade(rider, 0.3);
show(eq1, 0.6);
say(cap, "At x = 1 this formula divides zero by zero - the curve has a HOLE", 0.5);
show(lm, 0.6);
cue(tick);
rewrite(eq1, `\lim_{x\to 1}\frac{x^3-x}{x-1} \;=\; \lim_{x\to 1}\,x(x+1)`, 0.9);
par { cam((gx1 + 170, 470), 1.2, smooth); zoom(1.8, 1.2, smooth); }
say(cap, "The limit asks: where were you HEADING? Watch the dot commit", 0.5);
to(lm, x, 1, 2.6, smooth);
cue(tick);
rewrite(eq1, `\lim_{x\to 1}\frac{x^3-x}{x-1} \;=\; 2`, 0.9);
flash(lm, cyan);
wait(0.8);
par { cam((cx, cy), 1.0, smooth); zoom(1, 1.0, smooth); }

// second example: chasing x to infinity
say(cap, "Limits also ask where the ROAD ends: chase x toward infinity", 0.5);
par { fade(p1, 0.5); fade(lm, 0.5); }
draw(p1b, 1.2);
show(lmb, 0.5);
to(lmb, x, 1.8, 2.0, smooth);
cue(tick);
rewrite(eq1, `\lim_{x\to\infty}\frac{4}{1+e^{-2.2x}} \;=\; 4`, 0.9);
wait(0.7);
par { shift(w2, (w + 80, 0), 0.7, linear); fade(c1, 0.6); disintegrate(eq1, 0.8); fade(h1, 0.5); }

// ---- ch 2: THE DERIVATIVE ----------------------------------------------
mark("derivative");
cue(whoosh);
show(h2, 0.5);
par { draw(x2a, 0.6); draw(y2a, 0.6); }
draw(p2, 1.2);
show(anch, 0.4);
show(eq2, 0.6);
say(cap, "Pin one point. A SECANT through a neighbour measures average slope", 0.5);
par { cam((gx2 + 200, 470), 1.0, smooth); zoom(1.35, 1.0, smooth); }
par { show(sec0, 0.4); show(sd0, 0.4); }
cue(tick);
rewrite(eq2, `\frac{\Delta y}{\Delta x} \;=\; 1+\tfrac{h}{2} \;=\; 1.75`, 0.8);
par { fade(sec0, 0.4); fade(sd0, 0.4); show(sec1, 0.4); show(sd1, 0.4); }
cue(tick);
rewrite(eq2, `\frac{\Delta y}{\Delta x} \;=\; 1+\tfrac{h}{2} \;=\; 1.45`, 0.8);
par { fade(sec1, 0.4); fade(sd1, 0.4); show(sec2, 0.4); show(sd2, 0.4); }
cue(tick);
rewrite(eq2, `\frac{\Delta y}{\Delta x} \;=\; 1+\tfrac{h}{2} \;=\; 1.15`, 0.8);
say(cap, "Slide the neighbour home: the secants collapse onto ONE line", 0.5);
par { fade(sec2, 0.5); fade(sd2, 0.5); show(tg2, 0.5); show(sl2, 0.5); }
flash(tg2, gold);
cue(pop);
cue(tick);
rewrite(eq2, `f'(1) \;=\; 1`, 0.9);
wait(0.6);
par { cam((cx, cy), 1.0, smooth); zoom(1, 1.0, smooth); }

// now do it EVERYWHERE: the tangent glides, recording f' as a new curve
say(cap, "Do it at every point - and record the answer as a NEW curve", 0.5);
par { to(tg2, x, -0.4, 0.7, smooth); to(sl2, x, -0.4, 0.7, smooth); }
par { to(tg2, x, 2.3, 2.6, smooth); to(sl2, x, 2.3, 2.6, smooth); draw(dv2, 2.6); }
cue(tick);
rewrite(eq2, `f'(x) \;=\; x`, 0.9);
wait(0.6);

// second example: every curve carries its shadow
say(cap, "It works for EVERY curve: sine's recorded slope is cosine", 0.5);
par { fade(p2, 0.5); fade(dv2, 0.5); fade(tg2, 0.5); fade(sl2, 0.5); fade(anch, 0.4); }
par { show(bl2, 0.4); draw(p2s, 1.2); }
draw(dvs, 1.6);
cue(tick);
rewrite(eq2, `\big(\sin x\big)' \;=\; \cos x`, 0.9);
wait(0.7);
par { shift(w3, (w + 80, 0), 0.7, linear); fade(c2, 0.6); disintegrate(eq2, 0.8); fade(h2, 0.5); }

// ---- ch 3: SHAPE -------------------------------------------------------
mark("shape");
cue(whoosh);
show(h3, 0.5);
draw(x3a, 0.7);
draw(p3, 1.4);
show(eq3, 0.6);
say(cap, "The derivative is a story about SHAPE. Ride the tangent and listen", 0.5);
par { show(tg3, 0.5); show(sl3, 0.5); }
par { to(tg3, x, -1, 1.6, smooth); to(sl3, x, -1, 1.6, smooth); }
cue(pop);
show(ex3, 0.4); pulse(ex3, 0.8);
say(cap, "Slope zero: the curve turns. A peak - then a valley", 0.5);
par { to(tg3, x, 0, 1.2, smooth); to(sl3, x, 0, 1.2, smooth); }
show(if3, 0.4); flash(if3, magenta);
say(cap, "Here the BEND flips: concave down becomes concave up - an inflection", 0.5);
par { to(tg3, x, 1, 1.2, smooth); to(sl3, x, 1, 1.2, smooth); }
pulse(ex3, 0.8);
par { to(tg3, x, 2.1, 1.2, smooth); to(sl3, x, 2.1, 1.2, smooth); }
cue(tick);
rewrite(eq3, `f'=0:\ \text{turning}\qquad f''=0:\ \text{bending flips}`, 0.9);
wait(1.0);
par { shift(w4, (w + 80, 0), 0.7, linear); fade(c3, 0.6); disintegrate(eq3, 0.8); fade(h3, 0.5); }

// ---- ch 4: THE INTEGRAL ------------------------------------------------
mark("integral");
cue(whoosh);
show(h4, 0.5);
par { draw(x4a, 0.6); draw(y4a, 0.6); }
draw(p4, 1.3);
show(eq4, 0.6);
say(cap, "The other question: how much accumulates? Slice it into strips", 0.5);
stagger(0.08) { for i in 0..8 { par { show(rs{i}, 0.3); shift(rs{i}, (0, -24), 0.4, out); } } }
wait(0.8);
say(cap, "Thinner and thinner strips: the sum becomes the exact area", 0.5);
show(int4, 0.3);
par { fade(rstrips, 1.1); to(ar4, x, 4, 2.2, smooth); to(int4, x, 4, 2.2, smooth); }
flash(int4, gold);
cue(tick);
rewrite(eq4, `A \;=\; \int_0^4 f\,dx \;=\; 3.2`, 0.9);
wait(0.8);

// second example: signed area - the hill cancels the valley
say(cap, "One warning: below the axis, area counts NEGATIVE", 0.5);
par { fade(p4, 0.5); fade(ar4, 0.5); fade(int4, 0.5); }
draw(p4b, 1.2);
show(intb, 0.3);
par { to(arb, x, 4, 2.0, smooth); to(intb, x, 4, 2.0, smooth); }
flash(intb, teal);
cue(tick);
rewrite(eq4, `\int_0^4 \sin\!\Big(\frac{\pi x}{2}\Big)dx \;=\; 0`, 0.9);
say(cap, "The hill above cancels the valley below - signed area", 0.5);
wait(0.6);
par { fade(p4b, 0.5); fade(arb, 0.5); fade(intb, 0.4); show(p4, 0.5); }
par { shift(w5, (w + 80, 0), 0.7, linear); disintegrate(eq4, 0.8); fade(h4, 0.5); }

// ---- ch 5: THE FUNDAMENTAL THEOREM --------------------------------------
mark("ftc");
cue(whoosh);
show(h5, 0.5);
say(cap, "Rewind. This time, GRAPH the running total as you sweep", 0.5);
show(ar4, 0.4);
to(ar4, x, 0, 0.7, smooth);
show(eqF, 0.7);
par { to(ar4, x, 4, 2.8, smooth); draw(acF, 2.8); }
show(alab, 0.5); show(flab, 0.5);
say(cap, "Now take the DERIVATIVE of that gold curve - the slope of the total", 0.5);
cue(tick);
rewrite(eqF, `\frac{d}{dx}A(x) \;=\; \;?`, 0.8);
draw(dfF, 2.2);
flash(p4, magenta);
cue(chime);
say(cap, "It lands EXACTLY on f. Accumulating, then differentiating, is a round trip", 0.5);
cue(tick);
rewrite(eqF, `\boxed{\;\frac{d}{dx}\int_0^x f(t)\,dt \;=\; f(x)\;}`, 1.0);
wait(1.2);

// ---- finale
par { fade(c4, 0.7); fade(ar4, 0.7); fade(acF, 0.7); fade(dfF, 0.7); fade(alab, 0.5); fade(flab, 0.5); fade(h5, 0.5); }
seq { show(conf, 0.1); burst(conf, 1.4); }
par {
  breathe(eqF, 3, 0.05, 0, 7);
  seq { stagger(0.4) { wordpop(r1, 0.05); wordpop(r2, 0.05); wordpop(r3, 0.05); } }
}
say(cap, "Calculus I: zoom in, add up - and the bridge between", 0.6);
wait(2.5);

integrals

Three views of the integral on one bump: coarse Riemann strips rise into place with the sample dots f(x*) riding the curve, refine to 32, then the true area sweeps open — glowing act-wipes between.

title("Ways to Integrate");
canvas(1000, 1000);
template("black");

// ---------- layout constants ----------
let gx = cx - 340;   // graph origin (math x = 0)
let gy = h - 160;    // graph baseline (math y = 0)
let sx = 170;        // px per x-unit
let sy = 100;        // px per y-unit

// ---------- HUD: headings & captions (sticky = survive camera moves) ----------
text(head, (cx, 60), "Ways to Integrate"); display(head); cursor(head); sticky(head);
text(t1, (cx, 122), "1. Riemann - slice the domain"); size(t1, 30); color(t1, cyan); hidden(t1); sticky(t1);
text(t2, (cx, 122), "2. Lebesgue - slice the range"); size(t2, 30); color(t2, gold); hidden(t2); sticky(t2);
text(t3, (cx, 122), "3. Henstock-Kurzweil - slice with a gauge"); size(t3, 30); color(t3, magenta); hidden(t3); sticky(t3);

caption(in1, "Riemann - vertical strips of equal width", (cx, cy - 70), 32, cyan); hidden(in1);
caption(in2, "Lebesgue - horizontal layers weighed by measure", (cx, cy), 32, gold); hidden(in2);
caption(in3, "Henstock-Kurzweil - strip widths set by a gauge", (cx, cy + 70), 32, magenta); hidden(in3);

text(cap, (cx, h - 42), ""); size(cap, 26); sticky(cap);

// ---------- act wipes: glowing verticals that sweep the frame between acts ----------
line(wipe1, (-40, 140), (-40, h - 90)); stroke(wipe1, 4); color(wipe1, gold); glow(wipe1, 14);
line(wipe2, (-40, 140), (-40, h - 90)); stroke(wipe2, 4); color(wipe2, magenta); glow(wipe2, 14);
line(wipe3, (-40, 140), (-40, h - 90)); stroke(wipe3, 4); glow(wipe3, 14);

// ---------- axes ----------
arrow(xax, (gx - 30, gy), (gx + 4*sx + 50, gy)); untraced(xax); stroke(xax, 3);
arrow(yax, (gx, gy + 30), (gx, 175)); untraced(yax); stroke(yax, 3);
text(xl0, (gx, gy + 26), "0"); size(xl0, 22); color(xl0, dim); hidden(xl0);
text(xl4, (gx + 4*sx, gy + 26), "4"); size(xl4, 22); color(xl4, dim); hidden(xl4);

// ---------- the smooth bump (acts 1 & 2) ----------
plot(fplot, (gx, gy), sx, sy, "3*exp(-((x-2)^2))", (0, 4));
untraced(fplot); stroke(fplot, 4); gradient(fplot, blue, cyan, gold, 270);
dot(rider, (gx, gy), 7); color(rider, gold); glow(rider, 8); hidden(rider);

// Riemann: 8 coarse strips (declared 26px low, they RISE into place)
// + the SAMPLE DOTS f(x_i*) riding the curve top - the star of the definition
for i in 0..8 {
  let xm = (i + 0.5)*0.5;
  let hgt = 3*exp(-((xm - 2)^2));
  rect(rc{i}, (gx + xm*sx, gy - hgt*sy/2 + 26), 0.5*sx - 3, hgt*sy);
  color(rc{i}, cyan); opacity(rc{i}, 0.55); tag(rc{i}, coarse);
  dot(sm{i}, (gx + xm*sx, gy - hgt*sy), 5);
  color(sm{i}, cyan); glow(sm{i}, 6); tag(sm{i}, samples);
}
hidden(coarse); hidden(samples);

// Riemann: 32 fine strips
for i in 0..32 {
  let xm = (i + 0.5)*0.125;
  let hgt = 3*exp(-((xm - 2)^2));
  rect(rf{i}, (gx + xm*sx, gy - hgt*sy/2), 0.125*sx - 2, hgt*sy);
  color(rf{i}, cyan); opacity(rf{i}, 0.7); tag(rf{i}, fine);
}
hidden(fine);

// the limit: swept exact area + live integral readout
area(ar, fplot, 0, 0); color(ar, cyan); opacity(ar, 0.35);
integral(intg, fplot, 0, 0, (gx + 4*sx - 40, 265)); hidden(intg);

// the pivot strip: one vertical slice that ROTATES into a horizontal one
rect(pv, (gx + 2*sx, gy - 1.5*sy), 42, 3*sy); color(pv, cyan); opacity(pv, 0.7); hidden(pv);

// Lebesgue: 10 horizontal layers (declared offset sideways, they SLIDE in alternating)
for j in 0..10 {
  let ym = (j + 0.5)*0.3;
  let hf = sqrt(ln(3/ym));
  let jm = j - 2*floor(j/2);
  let xoff = 180*jm - 90;
  rect(ls{j}, (gx + 2*sx - xoff, gy - ym*sy), 2*hf*sx, 0.3*sy - 2);
  color(ls{j}, gold); opacity(ls{j}, 0.55); tag(ls{j}, layers);
}
hidden(layers);
// the level scanner: a dashed line that sweeps UP through the layers
line(lev, (gx, gy - 0.15*sy), (gx + 4*sx, gy - 0.15*sy));
dashed(lev); color(lev, gold); stroke(lev, 2); hidden(lev);

// ---------- the spiky function (act 3) ----------
plot(gplot, (gx, gy), sx, sy, "1.1+1.7*exp(-40*((x-3)^2))", (0, 4));
untraced(gplot); stroke(gplot, 4); gradient(gplot, teal, magenta, 270);
dot(rider2, (gx, gy), 7); color(rider2, magenta); glow(rider2, 8); hidden(rider2);

// the gauge ITSELF, drawn as a real function: delta(x) dips where f spikes
plot(dplot, (gx, gy), sx, 60, "0.55-0.45*exp(-20*((x-3)^2))", (0, 4));
untraced(dplot); dashed(dplot); stroke(dplot, 2); color(dplot, magenta); opacity(dplot, 0.7);
text(dlab, (gx + 4*sx + 34, gy - 33), `$\delta(x)$`); size(dlab, 24); color(dlab, magenta); hidden(dlab);

// uniform cells first (they rise in) - two of them will FAIL at the spike
for i in 0..8 {
  let xm = (i + 0.5)*0.5;
  let hgt = 1.1 + 1.7*exp(-40*((xm - 3)^2));
  rect(hku{i}, (gx + xm*sx, gy - hgt*sy/2 + 26), 0.5*sx - 3, hgt*sy);
  color(hku{i}, teal); opacity(hku{i}, 0.5); tag(hku{i}, hk);
}
hidden(hk);

// gauge-fine cells + their TAG POINTS t_i pinned on the curve
for i in 0..10 {
  let xm = 2.5 + (i + 0.5)*0.1;
  let hgt = 1.1 + 1.7*exp(-40*((xm - 3)^2));
  rect(nk{i}, (gx + xm*sx, gy - hgt*sy/2), 0.1*sx - 2, hgt*sy);
  color(nk{i}, magenta); opacity(nk{i}, 0.75); tag(nk{i}, gauge); tag(nk{i}, hk);
  dot(tg{i}, (gx + xm*sx, gy - hgt*sy), 3);
  color(tg{i}, magenta); glow(tg{i}, 5); tag(tg{i}, tgd);
}
hidden(gauge); hidden(tgd);
bracelabel(bnar, (gx + 2.5*sx, gy + 16), (gx + 3.5*sx, gy + 16), `gauge $\delta(x)$ shrinks here`, 14);
color(bnar, magenta); hidden(bnar);

// ---------- equations (each one LIVES: it rewrites, then turns to dust) ----------
equation(eqR, (cx, 190), `S_{8} \;=\; \sum_{i=1}^{8} f(x_i^{*})\,\textcolor{cyan}{\Delta x}`, 40); hidden(eqR); sticky(eqR);
equation(eqL, (cx, 190), `\text{layer}_j \;=\; \textcolor{gold}{\mu\{\,f > t_j\,\}}\cdot\Delta t`, 40); hidden(eqL); sticky(eqL);
equation(eqH, (cx, 190), `\sum_i f(\textcolor{magenta}{t_i})\,\Delta x_i`, 38); hidden(eqH); sticky(eqH);
equation(eqS, (cx, 250), `\textcolor{cyan}{\text{Riemann}} \;\subsetneq\; \textcolor{gold}{\text{Lebesgue}} \;\subsetneq\; \textcolor{magenta}{\text{Henstock-Kurzweil}}`, 44); hidden(eqS); sticky(eqS); z(eqS, 10);

// ---------- finale confetti + triptych reprise of the three motifs ----------
circle(confbox, (cx, 290), 90); hidden(confbox);
particles(conf, confbox, 24, 4, 11, "ring"); color(conf, gold); hidden(conf);

let mxr = cx - 380;
let mxh = cx + 380;
let myb = 490;
// mini Riemann: a tiny staircase of vertical strips
for i in 0..6 {
  let xm = (i + 0.5)/3;
  let hgt = 76*exp(-2*((xm - 1)^2));
  rect(mr{i}, (mxr - 110 + xm*110, myb - hgt/2), 34, hgt);
  color(mr{i}, cyan); opacity(mr{i}, 0.6); tag(mr{i}, minir);
}
// mini Lebesgue: a tiny layer cake
for j in 0..5 {
  let wd = 200 - 34*j;
  rect(ml{j}, (cx, myb - 9 - j*17), wd, 14);
  color(ml{j}, gold); opacity(ml{j}, 0.6); tag(ml{j}, minil);
}
// mini Henstock-Kurzweil: coarse cells, then a burst of fine ones at the spike
for i in 0..3 {
  rect(mw{i}, (mxh - 90 + i*42, myb - 19), 40, 38);
  color(mw{i}, teal); opacity(mw{i}, 0.6); tag(mw{i}, minih);
}
for k in 0..5 {
  let hgt = 38 + 52*exp(-0.7*((k - 2)^2));
  rect(mn{k}, (mxh + 10 + (k + 0.5)*11, myb - hgt/2), 9, hgt);
  color(mn{k}, magenta); opacity(mn{k}, 0.75); tag(mn{k}, minih);
}
rect(mt, (mxh + 88, myb - 19), 40, 38); color(mt, teal); opacity(mt, 0.6); tag(mt, minih);
hidden(minir); hidden(minil); hidden(minih);

caption(ms1, "slice the domain", (mxr, 560), 26, cyan); hidden(ms1);
caption(ms2, "slice the range", (cx, 560), 26, gold); hidden(ms2);
caption(ms3, "slice by a gauge", (mxh, 560), 26, magenta); hidden(ms3);

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

// ---- cold open: title types on, the three names POP word by word
type(head, 1.2);
stagger(0.5) { wordpop(in1, 0.05); wordpop(in2, 0.05); wordpop(in3, 0.05); }
wait(1.2);
par { fade(in1, 0.4); fade(in2, 0.4); fade(in3, 0.4); }

// ---- act 1: RIEMANN ----------------------------------------------------
cue(whoosh);
show(t1, 0.5);
par { draw(xax, 0.6); draw(yax, 0.6); show(xl0, 0.6); show(xl4, 0.6); }
show(rider, 0.2);
par { draw(fplot, 1.5); travel(rider, fplot, 1.5, smooth); }
fade(rider, 0.3);
say(cap, "Slice the domain into equal strips; each SAMPLE DOT sets its strip's height", 0.5);
stagger(0.08) { for i in 0..8 { par { show(rc{i}, 0.3); shift(rc{i}, (0, -26), 0.4, out); show(sm{i}, 0.3); } } }
show(eqR, 0.6);
wait(1.2);

// push IN while the strips refine, equation rewrites underneath
say(cap, "Refine: quadruple the strips - the staircase hugs the curve", 0.5);
par { cam((cx, gy - 1.2*sy), 1.1, smooth); zoom(1.45, 1.1, smooth); }
par { fade(coarse, 0.5); fade(samples, 0.5); stagger(0.02) { for i in 0..32 { show(rf{i}, 0.22); } } }
cue(tick);
rewrite(eqR, `S_{32} \;=\; \sum_{i=1}^{32} f(x_i^{*})\,\textcolor{cyan}{\Delta x}`, 0.8);
wait(0.9);
par { cam((cx, cy), 1.0, smooth); zoom(1, 1.0, smooth); }

// the limit: strips dissolve into the EXACT swept area, the number climbs
cue(tick);
rewrite(eqR, `\int_0^{4} f\,dx \;=\; \lim_{n\to\infty} S_n`, 0.9);
say(cap, "In the limit, the sum becomes the exact area", 0.5);
show(intg, 0.3);
par { fade(fine, 1.2); to(ar, x, 4, 2.2, smooth); to(intg, x, 4, 2.2, smooth); }
flash(intg, gold);
wait(1.0);
par { shift(wipe1, (w + 80, 0), 0.7, linear); fade(ar, 0.5); fade(intg, 0.5); disintegrate(eqR, 0.8); fade(t1, 0.5); }

// ---- act 2: LEBESGUE ---------------------------------------------------
cue(whoosh);
show(t2, 0.5);
say(cap, "Turn the slicing sideways: cut the range, not the domain", 0.5);
show(pv, 0.3);
par { rotate(pv, 90, 0.9, smooth); recolor(pv, gold, 0.9); }
fade(pv, 0.4);
show(eqL, 0.6);
show(lev, 0.3);
par {
  stagger(0.1) { for j in 0..10 { par { show(ls{j}, 0.35); shift(ls{j}, (180*(j - 2*floor(j/2)) - 90, 0), 0.5, out); } } }
  shift(lev, (0, -2.7*sy), 1.9, smooth);
  zoom(1.06, 2.2, smooth);
}
// the stack breathes: a travelling wave rolls up through the layers
par { for j in 0..10 { oscillate(ls{j}, y, 2.4, 3, j/10, 3.2); } pulse(ls4, 0.9); }
say(cap, "A layer at height t sits over the set where f > t; its width is that set's measure", 0.5);
cue(tick);
rewrite(eqL, `\int f\,d\mu \;=\; \int_0^{\infty}\textcolor{gold}{\mu\{\,f > t\,\}}\,dt`, 0.9);
wait(1.2);
fade(lev, 0.4);
par { shift(wipe2, (w + 80, 0), 0.7, linear); fade(layers, 0.5); disintegrate(eqL, 0.8); fade(t2, 0.5); fade(fplot, 0.5); zoom(1, 0.8, smooth); }

// ---- act 3: HENSTOCK-KURZWEIL ------------------------------------------
cue(whoosh);
show(t3, 0.5);
show(rider2, 0.2);
par { draw(gplot, 1.4); travel(rider2, gplot, 1.4, smooth); }
fade(rider2, 0.3);
say(cap, "New function, old recipe: equal strips again...", 0.5);
stagger(0.07) { for i in 0..8 { par { show(hku{i}, 0.3); shift(hku{i}, (0, -26), 0.4, out); } } }
show(eqH, 0.6);
wait(0.5);

// push in on the spike: the uniform cells FAIL, flash red, shake, shatter
par { cam((gx + 3*sx, gy - 1.3*sy), 1.1, smooth); zoom(1.6, 1.1, smooth); }
say(cap, "The spike slips between samples - equal widths are too coarse here", 0.5);
par { recolor(hku5, red, 0.3); recolor(hku6, red, 0.3); shake(hku5, 0.8); shake(hku6, 0.8); }
cue(pop);
par { disintegrate(hku5, 0.8); disintegrate(hku6, 0.8); }

// the gauge appears AS A FUNCTION: it dips exactly where f is dangerous
say(cap, `The gauge $\delta(x)$ is itself a function - watch it dip where f spikes`, 0.5);
par { draw(dplot, 1.0); show(dlab, 0.6); }
say(cap, `Tiny slices where f is wild - and every slice carries its tag point $t_i$`, 0.5);
stagger(0.05) { for i in 0..10 { par { show(nk{i}, 0.22); show(tg{i}, 0.22); } } }
show(bnar, 0.5);
wait(0.8);
par { cam((cx, cy), 1.0, smooth); zoom(1, 1.0, smooth); }
cue(tick);
rewrite(eqH, `\Delta x_i < \textcolor{magenta}{\delta(t_i)} \;\Longrightarrow\; \Big|\sum_i f(t_i)\,\Delta x_i - A\Big| < \varepsilon`, 0.9);
flow(gplot, 1.5, forward, once);
wait(1.2);

// ---- finale: wipe to black, hierarchy + confetti + triptych reprise ------
par {
  shift(wipe3, (w + 80, 0), 0.7, linear);
  fade(hk, 0.5); fade(tgd, 0.5); fade(gplot, 0.5); fade(dplot, 0.5); fade(dlab, 0.5);
  fade(xax, 0.5); fade(yax, 0.5); fade(xl0, 0.5); fade(xl4, 0.5);
  disintegrate(eqH, 0.8); fade(bnar, 0.5); fade(t3, 0.5);
}
cue(chime);
show(eqS, 0.8);
par {
  breathe(eqS, 3, 0.05, 0, 7);
  seq { show(conf, 0.1); burst(conf, 1.4); }
  seq {
    stagger(0.35) {
      stagger(0.05) { for i in 0..6 { show(mr{i}, 0.25); } }
      stagger(0.06) { for j in 0..5 { show(ml{j}, 0.25); } }
      seq { stagger(0.04) { for i in 0..3 { show(mw{i}, 0.2); } } stagger(0.04) { for k in 0..5 { show(mn{k}, 0.2); } } show(mt, 0.2); }
    }
    stagger(0.3) { wordpop(ms1, 0.06); wordpop(ms2, 0.06); wordpop(ms3, 0.06); }
  }
}
say(cap, "One area - three philosophies of slicing", 0.6);
wait(2.5);

disc-integration

A flat 2D region spins up into a 3D solid of revolution: one living equation rewrites from the profile r=√z to the volume ∫πr² dz, a single strip lifts into a disc, and a live volume readout climbs.

title("Disc Integration");
canvas(1000, 1000);
template("black");

// ================= HUD (2D always draws above the 3D world) =================
text(head, (cx, 60), "Disc Integration"); display(head); cursor(head);
text(t1, (cx, 122), "1. A region under a curve"); size(t1, 30); color(t1, gold); hidden(t1);
text(t2, (cx, 122), "2. Spin it - every strip sweeps a disc"); size(t2, 30); color(t2, cyan); hidden(t2);
text(t3, (cx, 122), "3. Stack the discs - integrate"); size(t3, 30); color(t3, magenta); hidden(t3);
text(cap, (cx, h - 42), ""); size(cap, 26);

// one living equation: it rewrites its way from the curve to the volume
equation(eqM, (cx, 190), `y=\sqrt{x}\quad(0\le x\le 4)`, 40); hidden(eqM);

// live volume readout
counter(vol, (w - 185, 300), 0, 2, "V = ", ""); hidden(vol);

// ================= act 1 cast: the flat 2D region =================
let gx = cx - 300;
let gy = 520;
let s2 = 140;

arrow(xax2, (gx - 30, gy), (gx + 4*s2 + 50, gy)); untraced(xax2); stroke(xax2, 3); tag(xax2, d2);
arrow(yax2, (gx, gy + 30), (gx, gy - 2.4*s2)); untraced(yax2); stroke(yax2, 3); tag(yax2, d2);
text(x0b, (gx, gy + 26), "0"); size(x0b, 22); color(x0b, dim); hidden(x0b); tag(x0b, d2);
text(x4b, (gx + 4*s2, gy + 26), "4"); size(x4b, 22); color(x4b, dim); hidden(x4b); tag(x4b, d2);

plot(rplot, (gx, gy), s2, s2, "sqrt(x)", (0, 4));
untraced(rplot); stroke(rplot, 4); gradient(rplot, blue, cyan, gold, 270); tag(rplot, d2);
dot(rider, (gx, gy), 7); color(rider, gold); glow(rider, 8); hidden(rider); tag(rider, d2);
area(ar2, rplot, 0, 0); color(ar2, cyan); opacity(ar2, 0.3); tag(ar2, d2);

// the one strip we will follow into 3D (x = 2.25 - remember it)
rect(strip, (gx + 2.25*s2, gy - sqrt(2.25)*s2/2), 66, sqrt(2.25)*s2);
color(strip, cyan); opacity(strip, 0.75); hidden(strip); tag(strip, d2);

// ================= act 2-3 cast: the 3D world (right-handed, Z-up) ==========
camera3((8.2, -9.5, 5.0), (0, 0, 1.9), 42);
axes3(ax3, (0, 0, 0), 4.6, 1); hidden(ax3);

// the spin axis, called out explicitly
line3(spinax, (0, 0, -0.3), (0, 0, 4.6)); thick(spinax, 0.015); color(spinax, dim); hidden(spinax);
text(zlab, (cx, cy), "spin axis"); size(zlab, 22); color(zlab, dim); hidden(zlab);
pin3(zlab, (0, 0, 4.55), (0, -16));

// the profile curve, stood upright: r = sqrt(z)
curve3(prof, "sqrt(t)", "0", "t", (0, 4)); untraced(prof); thick(prof, 0.04); color(prof, gold);

// ghost of the swept surface: bright wireframe revolve
revolve3(ghost, (0, 0, 0), "sqrt(t)", (0, 4), 64);
finish3(ghost, "wire=1"); color(ghost, teal); opacity(ghost, 0.4); untraced(ghost);

// 8 coarse discs (thin cylinders = many-sided prisms), declared low so they RISE
for i in 0..8 {
  let zc = (i + 0.5)*0.5;
  prism3(dc{i}, (0, 0, zc - 0.45), 48, sqrt(zc), 0.48);
  color(dc{i}, cyan); opacity(dc{i}, 0.85); tag(dc{i}, coarse3);
}
hidden(coarse3);

// 20 fine discs
for i in 0..20 {
  let zc = (i + 0.5)*0.2;
  prism3(df{i}, (0, 0, zc - 0.3), 48, sqrt(zc), 0.19);
  color(df{i}, cyan); opacity(df{i}, 0.9); tag(df{i}, fine3);
}
hidden(fine3);

// radius callout for the pulled-out disc (z = 2.25, r = 1.5, pulled to x + 3)
arrow3(rarr, (3.0, 0, 2.62), (4.5, 0, 2.62)); thick(rarr, 0.03); color(rarr, gold); untraced(rarr);
text(rlab, (cx, cy), `$r = \sqrt{z}$`); size(rlab, 26); color(rlab, gold); hidden(rlab);
pin3(rlab, (3.75, 0, 2.62), (0, -30));

// the exact solid, and the vase it will morph into ("any profile, same recipe")
revolve3(solid, (0, 0, 0), "sqrt(t)", (0, 4), 64);
finish3(solid, "shading=smooth depth=0.2 shadow=0.2"); color(solid, cyan); hidden(solid);
revolve3(vase, (0, 0, 0), "1.1+0.55*sin(1.7*t-0.9)", (0, 4), 64); hidden(vase);
morph3(solid, vase);

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

// ---- cold open
type(head, 1.1);

// ---- act 1: the flat region
cue(whoosh);
show(t1, 0.5);
par { draw(xax2, 0.6); draw(yax2, 0.6); show(x0b, 0.6); show(x4b, 0.6); }
show(rider, 0.2);
par { draw(rplot, 1.4); travel(rider, rplot, 1.4, smooth); }
fade(rider, 0.3);
show(eqM, 0.6);
say(cap, "Take the region under the curve...", 0.5);
to(ar2, x, 4, 1.6, smooth);
say(cap, "...and keep your eye on this one strip", 0.5);
show(strip, 0.4);
pulse(strip, 0.9);
wait(0.8);

// ---- the pivot: leave flatland
say(cap, "Now stand the region upright - and SPIN it around the axis", 0.5);
cue(whoosh);
fade(d2, 0.8);
show(t2, 0.5); fade(t1, 0.3);
par { show(ax3, 0.8); show(spinax, 0.8); show(zlab, 0.8); }
draw(prof, 1.2);
flash(spinax, magenta);

// THE MONEY SHOT: the profile curve physically sweeps 360 degrees
// around the axis while the wireframe surface traces on beneath it
par {
  turn3(prof, (0, 0, 2), z, 360, 2.6, smooth);
  draw(ghost, 2.6);
  orbit3(-20, 18, 12.0, 2.6, smooth);
}
cue(tick);
rewrite(eqM, `dV \;=\; \pi\,\textcolor{cyan}{r^2}\,dz`, 0.9);
say(cap, "Every strip of area sweeps a thin DISC of volume", 0.5);

// ---- act 3: the disc stack rises
show(t3, 0.5); fade(t2, 0.3);
stagger(0.09) { for i in 0..8 { par { show(dc{i}, 0.3); shift3(dc{i}, (0, 0, 0.45), 0.4, out); } } }
wait(0.4);

// pull ONE disc out of the stack - the same strip from act 1
say(cap, "That same strip from before - now a cylinder: radius sqrt(z), thickness dz", 0.5);
cue(pop);
shift3(dc4, (3.0, 0, 0), 0.9, smooth);
par { draw(rarr, 0.5); show(rlab, 0.5); }
wait(1.2);
par { fade(rarr, 0.4); fade(rlab, 0.4); shift3(dc4, (-3.0, 0, 0), 0.9, smooth); }
cue(tick);
rewrite(eqM, `V \;\approx\; \sum_i \pi\,r(z_i)^2\,\Delta z`, 0.9);
wait(0.8);

// refine: thinner discs, camera drifts around the stack
say(cap, "Slice thinner - the stack hugs the surface", 0.5);
par {
  fade(coarse3, 0.6);
  stagger(0.04) { for i in 0..20 { show(df{i}, 0.22); } }
  orbit3(35, 24, 11.0, 2.2, smooth);
}
cue(tick);
rewrite(eqM, `V \;=\; \pi\!\int_0^{4}(\sqrt{z}\,)^2\,dz \;=\; \pi\!\int_0^{4} z\,dz`, 0.9);
wait(0.8);

// the limit: discs dissolve into the exact smooth solid, the number climbs
say(cap, "In the limit: the exact solid of revolution", 0.5);
show(vol, 0.3);
par { fade(fine3, 1.2); fade(ghost, 1.2); show(solid, 1.4); to(vol, value, 25.13, 2.2); }
flash(vol, gold);
cue(tick);
rewrite(eqM, `V \;=\; \pi\cdot\tfrac{16}{2} \;=\; 8\pi \;\approx\; 25.13`, 0.9);
par { orbit3(90, 20, 10.5, 2.6, smooth); }
wait(0.6);

// ---- flourish: ANY profile, same recipe - the solid becomes a vase
say(cap, "Any profile, same recipe - just change r(z)", 0.5);
cue(whoosh);
par {
  to(solid, morph, 1, 2.6, smooth);
  fade(vol, 0.8);
  rewrite(eqM, `V \;=\; \pi\int_a^b r(z)^2\,dz`, 1.2);
  orbit3(160, 16, 10.5, 2.6, smooth);
}
cue(chime);
par {
  breathe(eqM, 3, 0.05, 0, 6);
  orbit3(200, 14, 11.0, 6, smooth);
}
say(cap, "Area swept in a circle - volume, one disc at a time", 0.6);
wait(2.0);

reactive-integral

The reactive-math gold example: integration by parts stays one continuous equation, then a plot verifies that the antiderivative’s slope is the integrand and +C is a family of vertical translations. Uses rewrite, not hand-positioned formula pieces.

// ============================================================================
// reactive-integral.manic — one calculation, one continuous visual world
// ----------------------------------------------------------------------------
// Integration by parts uses one structured equation. `rewrite` keeps unchanged
// RaTeX parts alive while only the mathematical difference moves or enters.
// The graph then verifies the result: the slope of F is the height of f, and
// +C becomes a visible family of vertical translations.
// ============================================================================

title("A Reactive Integral");
canvas("16:9");
template("plain");
watermark(manicMark, (1135, 30), "Made With Manic");

// Shared colour roles follow the same mathematical objects through every act.
// x / u is magenta; cos, sin and their antiderivative relation are cyan.
text(kicker, (285, 38), "ONE INTEGRAL · ONE CONTINUOUS STORY");
size(kicker, 18); color(kicker, dim); bold(kicker); hidden(kicker);

text(headline, (430, 72), "Watch only the mathematics that changes");
size(headline, 28); color(headline, fg); bold(headline); hidden(headline);

// ---------------------------------------------------------------------------
// ONE PERSISTENT EQUATION
// ---------------------------------------------------------------------------

equation(
  work,
  (cx, 145),
  `\int \textcolor{magenta}{x}\,\textcolor{cyan}{\cos(x)}\,dx`,
  46
);
hidden(work);

// The by-parts roles remain visible while the expression changes above them.
equation(uChoice, (330, 225), `u=x`, 28); color(uChoice, magenta); hidden(uChoice);
equation(dvChoice, (525, 225), `dv=\cos(x)\,dx`, 28); color(dvChoice, cyan); hidden(dvChoice);
equation(duChoice, (760, 225), `du=dx`, 28); color(duChoice, magenta); hidden(duChoice);
equation(vChoice, (950, 225), `v=\sin(x)`, 28); color(vChoice, cyan); hidden(vChoice);

text(method, (cx, 278), "INTEGRATION BY PARTS");
size(method, 16); color(method, dim); bold(method); hidden(method);

// ---------------------------------------------------------------------------
// ONE GRAPH, ASKED THREE CONNECTED QUESTIONS
// ---------------------------------------------------------------------------

let ox = cx;
let oy = 515;
let sx = 108;
let sy = 28;

axes(ax, (ox, oy), 550, 165, 1);
color(ax, dim); opacity(ax, 0.50); untraced(ax);

// Integrand and one representative antiderivative (C=0).
plot(f, (ox, oy), sx, sy, "x*cos(x)", (-5, 5));
color(f, cyan); stroke(f, 5); glow(f, 0.8); untraced(f);

plot(bigF, (ox, oy), sx, sy, "x*sin(x)+cos(x)", (-5, 5));
color(bigF, lime); stroke(bigF, 5); dashed(bigF, 18, 11);
glow(bigF, 0.8); untraced(bigF);

// Numerical derivative of F: drawing it lands directly on f.
deriv(dF, bigF);
color(dF, gold); stroke(dF, 3); glow(dF, 0.5); untraced(dF);

// A moving tangent makes “F' = f” a local statement at every x.
tangent(tan, bigF, -3.8, 180); color(tan, gold); hidden(tan);
slope(slopeValue, bigF, -3.8, (18, -24)); color(slopeValue, gold); hidden(slopeValue);

equation(fLabel, (250, 338), `f(x)=x\cos(x)`, 28); color(fLabel, cyan); hidden(fLabel);
equation(FLabel, (1010, 338), `F(x)=x\sin(x)+\cos(x)`, 28); color(FLabel, lime); hidden(FLabel);
equation(proofLabel, (cx, 280), `F'(x)=f(x)=x\cos(x)`, 34); color(proofLabel, gold); hidden(proofLabel);

// +C does not change the derivative: it translates the same curve vertically.
plot(Fup, (ox, oy), sx, sy, "x*sin(x)+cos(x)+1.5", (-5, 5));
plot(Fdown, (ox, oy), sx, sy, "x*sin(x)+cos(x)-1.5", (-5, 5));
color(Fup, magenta); color(Fdown, magenta);
stroke(Fup, 3); stroke(Fdown, 3); opacity(Fup, 0.55); opacity(Fdown, 0.55);
dashed(Fup, 14, 9); dashed(Fdown, 14, 9);
untraced(Fup); untraced(Fdown);

equation(familyLabel, (cx, 280), `F(x)+C\quad\text{changes height, not slope}`, 32);
color(familyLabel, magenta); hidden(familyLabel);

text(caption, (cx, 690), "");
size(caption, 19); color(caption, dim); bold(caption);

// Axes and curves are `untraced`, so their draw progress starts at zero without
// also zeroing opacity. That lets `draw(...)` reveal their geometry later.

// ---------------------------------------------------------------------------
// TIMELINE
// ---------------------------------------------------------------------------

show(kicker, 0.45);
show(headline, 0.55);
say(caption, "Start with the question. Keep the stage — change only its state.");
show(work, 0.65);
wait(1.60);

// Choose u and dv by reusing the same semantic colours.
show(method, 0.35);
say(caption, "Choose the two roles. Colour preserves their identity.");
par { show(uChoice, 0.50); show(dvChoice, 0.65); }
wait(1.20);
par { show(duChoice, 0.50); show(vChoice, 0.50); }
wait(1.50);

// Build x sin(x) - integral sin(x) dx. Reusable glyphs travel to their new
// jobs while the obsolete cosine is the only original factor that leaves.
say(caption, "Apply integration by parts: persistent pieces move; new pieces arrive.");
rewrite(
  work,
  `\textcolor{magenta}{x}\textcolor{cyan}{\sin(x)}-\int\textcolor{cyan}{\sin(x)}\,dx`,
  1.05,
  smooth
);
wait(2.00);

// Only the remaining integral changes. x sin(x) stays untouched.
say(caption, "Resolve the remaining integral. The stable product never blinks.");
rewrite(
  work,
  `\textcolor{magenta}{x}\textcolor{cyan}{\sin(x)}+\textcolor{cyan}{\cos(x)}+\textcolor{gold}{C}`,
  1.00,
  smooth
);
wait(2.00);

// Move attention from symbolic manipulation into the same idea as geometry.
say(caption, "Now verify the answer visually — without leaving the scene.");
par {
  fade(method, 0.40);
  fade(uChoice, 0.40); fade(dvChoice, 0.40);
  fade(duChoice, 0.40); fade(vChoice, 0.40);
  draw(ax, 0.85);
}
draw(f, 1.80);
show(fLabel, 0.45);
wait(1.00);

draw(bigF, 1.80);
show(FLabel, 0.45);
wait(1.00);

// The tangent and its numeric slope glide continuously across F.
say(caption, "At every x, the slope of the green curve equals the blue height.");
par { show(tan, 0.45); show(slopeValue, 0.45); }
par {
  to(tan, x, 3.8, 4.80, smooth);
  to(slopeValue, x, 3.8, 4.80, smooth);
}
wait(0.60);

// The derivative trace lands directly over the original integrand.
show(proofLabel, 0.50);
draw(dF, 2.20);
flash(f, cyan);
wait(1.40);

// Finish with the geometric meaning of the integration constant.
say(caption, "+C creates a family of answers — same shape, same slope.");
par {
  fade(tan, 0.45); fade(slopeValue, 0.45); fade(dF, 0.45);
  fade(proofLabel, 0.45); fade(fLabel, 0.45); fade(FLabel, 0.45);
  show(familyLabel, 0.55);
  pulse(work, 0.70);
}
par { draw(Fup, 1.50); draw(Fdown, 1.50); }
wait(2.80);

rewrite-integration

A full manual-integration walkthrough, animated: one equation object is rewrite-morphed through all 21 steps — every substitution, partial-fraction split and back-substitution, each captioned with its rule — down to the closed form. Display-quality LaTeX throughout.

title("Rewrite Integration Steps");
canvas("16:9");
template("mono");

text(head, (cx, 58), "Integrating by rewriting the denominator");
display(head);
bold(head);
size(head, 32);
hidden(head);

text(sub, (cx, 94), "Manual integration — partial fractions by substitution");
size(sub, 20);
color(sub, dim);
hidden(sub);

rect(panelBox, (cx, cy + 14), w - 150, 380);
outline(panelBox, dim);
opacity(panelBox, 0.35);
hidden(panelBox);

text(stepTitle, (cx, 150), "");
display(stepTitle);
bold(stepTitle);
size(stepTitle, 26);
color(stepTitle, cyan);

text(ruleTag, (cx, 182), "");
size(ruleTag, 18);
color(ruleTag, dim);

text(watermark, (w - 96, h - 12), "Made with Manic");
size(watermark, 15);
color(watermark, dim);
hidden(watermark);

equation(work, (cx, cy + 20), `\int \frac{1}{(x - 1)(x + 2)}\,dx`, 34);
hidden(work);

equation(finalLine, (cx, h - 64), `\boxed{\,\frac{\log{\left(x - 1 \right)}}{3} - \frac{\log{\left(x + 2 \right)}}{3} + C\,}`, 34);
color(finalLine, lime);
hidden(finalLine);

show(head, 0.45);
show(sub, 0.45);
show(panelBox, 0.45);
show(watermark, 0.45);
show(work, 0.5);
wait(0.4);

par {
say(stepTitle, "1. u-Substitution", 0.25);
say(ruleTag, "Rule: URule", 0.25);
rewrite(work, `Let\ u = x - 1,\quad \frac{du}{dx} = 1`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "2. u-Substitution", 0.25);
say(ruleTag, "Rule: URule", 0.25);
rewrite(work, `Let\ u = u + \frac{3}{2},\quad \frac{du}{d_u} = 1`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "3. Rewrite", 0.25);
say(ruleTag, "Rule: RewriteRule", 0.25);
rewrite(work, `\int \frac{1}{3 u + \left(u - \frac{3}{2}\right)^{2} - \frac{9}{2}} \,d_u = \int - \frac{2}{3 \left(2 u + 3\right)} + \frac{2}{3 \left(2 u - 3\right)} \,d_u`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "4. Sum rule", 0.25);
say(ruleTag, "Rule: AddRule", 0.25);
rewrite(work, `\int (f+g)\,d_u = \int f\,d_u + \int g\,d_u`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "5. Constant factor", 0.25);
say(ruleTag, "Rule: ConstantTimesRule", 0.25);
rewrite(work, `\int - \frac{2}{3 \left(2 u + 3\right)} \,d_u = - \frac{2}{3} \int \frac{1}{2 u + 3} \,d_u`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "6. u-Substitution", 0.25);
say(ruleTag, "Rule: URule", 0.25);
rewrite(work, `Let\ u = 2 u + 3,\quad \frac{du}{d_u} = 2`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "7. Constant factor", 0.25);
say(ruleTag, "Rule: ConstantTimesRule", 0.25);
rewrite(work, `\int \frac{1}{2 u} \,d_u = \frac{1}{2} \int \frac{1}{u} \,d_u`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "8. Reciprocal", 0.25);
say(ruleTag, "Rule: ReciprocalRule", 0.25);
rewrite(work, `\int \frac{1}{u} \,d_u = \ln|u| + C = \log{\left(u \right)}`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "9. Simplify", 0.25);
say(ruleTag, "Rule: ConstantTimesRule", 0.25);
rewrite(work, `= \frac{\log{\left(u \right)}}{2} + C`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "10. Back substitute", 0.25);
say(ruleTag, "Rule: URule", 0.25);
rewrite(work, `= \frac{\log{\left(2 u + 3 \right)}}{2} + C`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "11. Simplify", 0.25);
say(ruleTag, "Rule: ConstantTimesRule", 0.25);
rewrite(work, `= - \frac{\log{\left(2 u + 3 \right)}}{3} + C`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "12. Constant factor", 0.25);
say(ruleTag, "Rule: ConstantTimesRule", 0.25);
rewrite(work, `\int \frac{2}{3 \left(2 u - 3\right)} \,d_u = \frac{2}{3} \int \frac{1}{2 u - 3} \,d_u`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "13. u-Substitution", 0.25);
say(ruleTag, "Rule: URule", 0.25);
rewrite(work, `Let\ u = 2 u - 3,\quad \frac{du}{d_u} = 2`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "14. Constant factor", 0.25);
say(ruleTag, "Rule: ConstantTimesRule", 0.25);
rewrite(work, `\int \frac{1}{2 u} \,d_u = \frac{1}{2} \int \frac{1}{u} \,d_u`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "15. Reciprocal", 0.25);
say(ruleTag, "Rule: ReciprocalRule", 0.25);
rewrite(work, `\int \frac{1}{u} \,d_u = \ln|u| + C = \log{\left(u \right)}`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "16. Simplify", 0.25);
say(ruleTag, "Rule: ConstantTimesRule", 0.25);
rewrite(work, `= \frac{\log{\left(u \right)}}{2} + C`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "17. Back substitute", 0.25);
say(ruleTag, "Rule: URule", 0.25);
rewrite(work, `= \frac{\log{\left(2 u - 3 \right)}}{2} + C`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "18. Simplify", 0.25);
say(ruleTag, "Rule: ConstantTimesRule", 0.25);
rewrite(work, `= \frac{\log{\left(2 u - 3 \right)}}{3} + C`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "19. Combine", 0.25);
say(ruleTag, "Rule: AddRule", 0.25);
rewrite(work, `= \frac{\log{\left(2 u - 3 \right)}}{3} - \frac{\log{\left(2 u + 3 \right)}}{3} + C`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "20. Back substitute", 0.25);
say(ruleTag, "Rule: URule", 0.25);
rewrite(work, `= \frac{\log{\left(2 u \right)}}{3} - \frac{\log{\left(2 u + 6 \right)}}{3} + C`, 0.7, smooth);
}
wait(0.3);

par {
say(stepTitle, "21. Back substitute", 0.25);
say(ruleTag, "Rule: URule", 0.25);
rewrite(work, `= \frac{\log{\left(2 x - 2 \right)}}{3} - \frac{\log{\left(2 x + 4 \right)}}{3} + C`, 0.7, smooth);
}
wait(0.3);

show(finalLine, 0.8);
pulse(finalLine, 0.8);
wait(1.0);

reactive-world

The foundation for creator-reactive stories: five named step blocks keep one curve, equation, tangent, live slope, derivative plot and caption synchronized. Each step is also exported as a marker for seeking and future multi-format publishing.

// ============================================================================
// reactive-world.manic — one world, named state transitions
// ----------------------------------------------------------------------------
// Each `step` changes several existing representations together. The equation,
// tangent, live slope, derivative curve, caption and camera share one continuous
// stage; anything a step does not mention simply persists.
// ============================================================================

title("Reactive World — The Derivative Lives on the Curve");
canvas("9:16");
template("terminal");
watermark(manicMark, (865, 165), "Made With Manic");

creator(me, "@anish2good name=Calculus_World tagline=One_idea_many_views yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=social cta=See_the_change safe=reels");
socials(me);

text(kicker, (540, 130), "ONE WORLD · FIVE NAMED STEPS");
size(kicker, 23); color(kicker, dim); bold(kicker); hidden(kicker);

text(headline, (540, 215), "The derivative lives on the curve");
size(headline, 39); color(headline, fg); bold(headline); hidden(headline);

rect(stage, (540, 855), 930, 1050);
color(stage, panel); outline(stage, dim); opacity(stage, 0.72);

equation(work, (540, 390), `f(x)=0.35x^2`, 51);
color(work, cyan); hidden(work);

let ox = 540;
let oy = 1050;
let sx = 115;
let sy = 62;

axes(ax, (ox, oy), 410, 420, 1);
color(ax, dim); opacity(ax, 0.55); untraced(ax);

plot(f, (ox, oy), sx, sy, "0.35*x*x", (-3.5, 3.5));
color(f, cyan); stroke(f, 6); glow(f, 0.8); untraced(f);

deriv(df, f);
color(df, magenta); stroke(df, 5); dashed(df, 18, 11); untraced(df);

tangent(tan, f, -2.8, 235);
color(tan, gold); stroke(tan, 4); hidden(tan);

slope(rate, f, -2.8, (24, -30));
color(rate, gold); hidden(rate);

dot(vertex, (ox, oy), 10);
color(vertex, lime); glow(vertex, 1.8); hidden(vertex);

equation(curveLabel, (790, 650), `f(x)`, 31);
color(curveLabel, cyan); hidden(curveLabel);

equation(derivLabel, (790, 1320), `f'(x)`, 31);
color(derivLabel, magenta); hidden(derivLabel);

text(caption, (540, 1450), "Start with one curve and one moving question: how steep is it?");
size(caption, 26); color(caption, dim); wrap(caption, 820); hidden(caption);

// ---------------------------------------------------------------------------
// NAMED REACTIVE STEPS
// ---------------------------------------------------------------------------

step("question") {
  show(kicker, 0.40);
  show(headline, 0.50);
  show(work, 0.55);
  draw(ax, 0.85);
  draw(f, 1.40);
  show(curveLabel, 0.45);
  show(caption, 0.45);
}
wait(0.75);

step("measure-slope") {
  rewrite(work, `f'(x)=0.70x`, 0.90, smooth);
  show(tan, 0.45);
  show(rate, 0.45);
  to(tan, x, 2.8, 3.20, smooth);
  to(rate, x, 2.8, 3.20, smooth);
  say(caption, "Move the point: the tangent and its slope update together.", 0.40);
}
wait(0.60);

step("find-the-flat-point") {
  rewrite(work, `f'(0)=\textcolor{lime}{0}`, 0.85, smooth);
  to(tan, x, 0, 1.80, smooth);
  to(rate, x, 0, 1.80, smooth);
  show(vertex, 0.40);
  say(caption, "At the vertex the tangent becomes flat, so the derivative is zero.", 0.40);
}
wait(0.65);

step("see-the-derivative") {
  rewrite(work, `f'(x)=\textcolor{magenta}{0.70x}`, 0.90, smooth);
  fade(tan, 0.40);
  fade(rate, 0.40);
  draw(df, 1.70);
  show(derivLabel, 0.45);
  say(caption, "Collect every local slope and a second curve appears: the derivative.", 0.40);
}
wait(0.70);

step("takeaway") {
  rewrite(work, `\text{slope of }f=\textcolor{magenta}{f'}`, 0.95, smooth);
  pulse(f, 0.70);
  pulse(df, 0.70);
  say(caption, "One idea, synchronized across symbols, geometry and motion.", 0.40);
}
wait(1.80);

sine_wave

axes + plot, a curve traced on, then vectors.

// The Sine Wave — a first taste of the manic math kit.
//   manic examples/sine_wave.manic
//   manic examples/sine_wave.manic --still 2.6 --scale 1.5 --crt

title("The Sine Wave");
canvas(1280, 720);

// --- cast: the world at t = 0 ---

// a coordinate frame centred on the stage
axes(ax, (640, 380), 520, 240);
text(xlab, (1180, 410), "x");  color(xlab, dim);  size(xlab, 22);
text(ylab, (665, 152), "y");   color(ylab, dim);  size(ylab, 22);

// the curve: visible but not yet drawn, so we can trace it on
plot(wave, (640, 380), 78, 120, sin, 6.6);
untraced(wave);

// a vector to point at, revealed later
vector(v1, (640, 380), (122, 108));
hidden(v1);

// headline + caption
text(head, (640, 118), "y = sin(x)");
display(head);  color(head, cyan);  size(head, 40);  hidden(head);
text(cap, (640, 662), "");  color(cap, dim);  size(cap, 22);

// --- script: beats, top to bottom ---

show(head, 0.5);
say(cap, "a coordinate frame on the void");
draw(wave, 1.7);
say(cap, "y = sin(x), traced on");
wait(0.6);

section("Vectors");
say(cap, "a vector from the origin");
par {
  show(v1, 0.4);
  pulse(v1);
}
wait(1.2);

creator-trigonometry-one-angle

One reactive angle drives three synchronized unit circles, degree/radian readouts, projection measurements, graph markers and progressive sine/cosine/tangent traces. Tangent is split into truthful branches, so its marker disappears at π/2 instead of drawing a false line through the asymptote.

// One live angle drives three unit-circle constructions, graph traces,
// markers, projections, and numerical readouts. Tangent is deliberately split
// into branches so the animation never lies across an asymptote.

title("One Angle Creates Three Functions");
canvas("9:16");
template("black");

creator(me,"@anish2good name=Manic_Geometry tagline=Relationships_made_visible yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=compact cta=Animate_the_relationship safe=clean");
socials(me);
watermark(mark,(w*0.18,h*0.065),"Made With Manic");
endcard(me,"title=Make_Math_Move cta=8gwifi.org/manic");

let u=(w+h-abs(w-h))/1080;

text(kicker,(cx,h*0.095),"MANIC · LIVE TRIGONOMETRY");
text(head,(cx,h*0.145),"One angle. Three different measurements.");
equation(identity,(cx,h*0.205),
  `\textcolor{cyan}{y=\sin\alpha}\qquad
   \textcolor{magenta}{y=\cos\alpha}\qquad
   \textcolor{lime}{y=\tan\alpha}`,22*u);
counter(degrees,(w*0.33,h*0.255),20,0,"α = ","°");
counter(radians,(w*0.69,h*0.255),0.35,2,"α = "," rad");
text(caption,(cx,h*0.835),"Rotate one radius. Watch three graphs respond.");

size(kicker,19*u); bold(kicker); color(kicker,cyan);
size(head,29*u); bold(head); wrap(head,w*0.84);
size(degrees,20*u); bold(degrees); color(degrees,gold);
size(radians,20*u); bold(radians); color(radians,gold);
size(caption,20*u); bold(caption); color(caption,dim); wrap(caption,w*0.80);

// One authored angle is the only changing input in the entire construction.
// Two rotations are available: the first teaches, the second becomes a
// continuous performance pass. Circle formulas are naturally periodic; graph
// markers and public readouts wrap back into [0,2pi).
parameter(alpha,(cx,h*0.885),0.35,0.02,12.54,"ANGLE α",2);
color(alpha,cyan);
bind(alpha,degrees,value,"(p-6.283185*floor(p/6.283185))*180/pi");
bind(alpha,radians,value,"p-6.283185*floor(p/6.283185)");

// Shared portrait geometry.
let circleX=w*0.265;
let graphX=w*0.535;
let radius=w*0.092;
let graphSX=w*0.050;
let graphSY=radius;
let graphRight=graphX+graphSX*6.283;
let row1=h*0.385;
let row2=h*0.565;
let row3=h*0.745;

// ---------------------------------------------------------------------------
// SIN — the rotating point's height.
// ---------------------------------------------------------------------------
circle(sinCircle,(circleX,row1),radius);
outlined(sinCircle); outline(sinCircle,fg);
line(sinCX,(circleX-radius*1.22,row1),(circleX+radius*1.22,row1));
line(sinCY,(circleX,row1-radius*1.22),(circleX,row1+radius*1.22));
point(sinO,(circleX,row1));
point(sinP,(circleX+radius*cos(0.35),row1-radius*sin(0.35)));
point(sinHeight,(circleX,row1-radius*sin(0.35)));
segment(sinRay,sinO,sinP);
segment(sinGuide,sinP,sinHeight);
anglemark(sinAngle,sinHeight,sinO,sinP);

bind(alpha,sinP,x,"286.2+99.4*cos(p)");
bind(alpha,sinP,y,"739.2-99.4*sin(p)");
bind(alpha,sinHeight,y,"739.2-99.4*sin(p)");

line(sinGX,(graphX,row1),(graphRight,row1));
line(sinGY,(graphX,row1-graphSY*1.28),(graphX,row1+graphSY*1.28));
plot(sinCurve,(graphX,row1),graphSX,graphSY,"sin(x)",(0,6.283));
point(sinDot,(graphX+graphSX*0.35,row1-graphSY*sin(0.35)));
point(sinFoot,(graphX+graphSX*0.35,row1));
segment(sinDrop,sinDot,sinFoot);
bind(alpha,sinCurve,trace,"p/6.283185");
bind(alpha,sinDot,x,"577.8+54*(p-6.283185*floor(p/6.283185))");
bind(alpha,sinDot,y,"739.2-99.4*sin(p)");
bind(alpha,sinFoot,x,"577.8+54*(p-6.283185*floor(p/6.283185))");
text(sinLabel,(graphX+graphSX*2.2,row1-radius*1.45),"y = sin(α) · height");

color(sinCircle,fg); color(sinCX,dim); color(sinCY,dim);
color(sinRay,cyan); color(sinGuide,cyan); color(sinAngle,cyan);
color(sinP,cyan); color(sinHeight,cyan); color(sinO,fg);
color(sinGX,dim); color(sinGY,dim); color(sinCurve,cyan);
color(sinDot,fg); color(sinFoot,fg); color(sinDrop,cyan); color(sinLabel,cyan);
dashed(sinGuide,8,6); dashed(sinDrop,8,6);
stroke(sinCircle,3); stroke(sinRay,4); stroke(sinGuide,3); stroke(sinCurve,5);
size(sinLabel,18*u); bold(sinLabel);

// ---------------------------------------------------------------------------
// COS — the rotating point's horizontal reach.
// ---------------------------------------------------------------------------
circle(cosCircle,(circleX,row2),radius);
outlined(cosCircle); outline(cosCircle,fg);
line(cosCX,(circleX-radius*1.22,row2),(circleX+radius*1.22,row2));
line(cosCY,(circleX,row2-radius*1.22),(circleX,row2+radius*1.22));
point(cosO,(circleX,row2));
point(cosP,(circleX+radius*cos(0.35),row2-radius*sin(0.35)));
point(cosReach,(circleX+radius*cos(0.35),row2));
segment(cosRay,cosO,cosP);
segment(cosGuide,cosP,cosReach);

bind(alpha,cosP,x,"286.2+99.4*cos(p)");
bind(alpha,cosP,y,"1084.8-99.4*sin(p)");
bind(alpha,cosReach,x,"286.2+99.4*cos(p)");

line(cosGX,(graphX,row2),(graphRight,row2));
line(cosGY,(graphX,row2-graphSY*1.28),(graphX,row2+graphSY*1.28));
plot(cosCurve,(graphX,row2),graphSX,graphSY,"cos(x)",(0,6.283));
point(cosDot,(graphX+graphSX*0.35,row2-graphSY*cos(0.35)));
point(cosFoot,(graphX+graphSX*0.35,row2));
segment(cosDrop,cosDot,cosFoot);
bind(alpha,cosCurve,trace,"p/6.283185");
bind(alpha,cosDot,x,"577.8+54*(p-6.283185*floor(p/6.283185))");
bind(alpha,cosDot,y,"1084.8-99.4*cos(p)");
bind(alpha,cosFoot,x,"577.8+54*(p-6.283185*floor(p/6.283185))");
text(cosLabel,(graphX+graphSX*2.2,row2-radius*1.45),"y = cos(α) · reach");

color(cosCircle,fg); color(cosCX,dim); color(cosCY,dim);
color(cosRay,magenta); color(cosGuide,magenta);
color(cosP,magenta); color(cosReach,magenta); color(cosO,fg);
color(cosGX,dim); color(cosGY,dim); color(cosCurve,magenta);
color(cosDot,fg); color(cosFoot,fg); color(cosDrop,magenta); color(cosLabel,magenta);
dashed(cosGuide,8,6); dashed(cosDrop,8,6);
stroke(cosCircle,3); stroke(cosRay,4); stroke(cosGuide,3); stroke(cosCurve,5);
size(cosLabel,18*u); bold(cosLabel);

// ---------------------------------------------------------------------------
// TAN — where the radius meets the tangent x=1. Its graph uses three separate
// branches; no path is ever drawn through pi/2 or 3pi/2.
// ---------------------------------------------------------------------------
circle(tanCircle,(circleX,row3),radius);
outlined(tanCircle); outline(tanCircle,fg);
line(tanCX,(circleX-radius*1.22,row3),(circleX+radius*1.38,row3));
line(tanCY,(circleX,row3-radius*1.22),(circleX,row3+radius*1.22));
line(tangentWall,(circleX+radius,row3-radius*1.28),(circleX+radius,row3+radius*1.28));
point(tanO,(circleX,row3));
point(tanP,(circleX+radius*cos(0.35),row3-radius*sin(0.35)));
point(tanHit,(circleX+radius,row3-radius*tan(0.35)));
point(tanBase,(circleX+radius,row3));
segment(tanRay,tanO,tanHit);
segment(tanLength,tanBase,tanHit);

bind(alpha,tanP,x,"286.2+99.4*cos(p)");
bind(alpha,tanP,y,"1430.4-99.4*sin(p)");
bind(alpha,tanHit,y,"1430.4-99.4*min(1.28,max(-1.28,tan(p)))");
bind(alpha,tanHit,opacity,"min(1,abs(cos(p))*7)");
bind(alpha,tanRay,opacity,"min(1,abs(cos(p))*7)");
bind(alpha,tanLength,opacity,"min(1,abs(cos(p))*7)");

line(tanGX,(graphX,row3),(graphRight,row3));
line(tanGY,(graphX,row3-graphSY*1.28),(graphX,row3+graphSY*1.28));
// Stop each sampled branch exactly at the visible y-range. The mathematical
// branch continues toward infinity; the empty gaps remain truthful.
plot(tanA,(graphX,row3),graphSX,graphSY,"tan(x)",(0.02,0.907));
plot(tanB,(graphX,row3),graphSX,graphSY,"tan(x)",(2.235,4.049));
plot(tanC,(graphX,row3),graphSX,graphSY,"tan(x)",(5.377,6.26));
point(tanDot,(graphX+graphSX*0.35,row3-graphSY*tan(0.35)));
point(tanFoot,(graphX+graphSX*0.35,row3));
segment(tanDrop,tanDot,tanFoot);
bind(alpha,tanA,trace,"min(1,p/0.907)");
bind(alpha,tanB,trace,"min(1,max(0,(p-2.235)/1.814))");
bind(alpha,tanC,trace,"min(1,max(0,(p-5.377)/0.883))");
bind(alpha,tanDot,x,"577.8+54*(p-6.283185*floor(p/6.283185))");
bind(alpha,tanDot,y,"1430.4-99.4*min(1.28,max(-1.28,tan(p)))");
bind(alpha,tanDot,opacity,"min(1,abs(cos(p))*7)");
bind(alpha,tanFoot,x,"577.8+54*(p-6.283185*floor(p/6.283185))");
bind(alpha,tanDrop,opacity,"min(1,abs(cos(p))*7)");
text(tanLabel,(graphX+graphSX*2.2,row3-radius*1.45),"y = tan(α) · tangent length");

color(tanCircle,fg); color(tanCX,dim); color(tanCY,dim); color(tangentWall,lime);
color(tanRay,lime); color(tanLength,lime); color(tanP,lime);
color(tanHit,fg); color(tanBase,fg); color(tanO,fg);
color(tanGX,dim); color(tanGY,dim);
color(tanA,lime); color(tanB,lime); color(tanC,lime);
color(tanDot,fg); color(tanFoot,fg); color(tanDrop,lime); color(tanLabel,lime);
dashed(tanDrop,8,6);
stroke(tanCircle,3); stroke(tanRay,4); stroke(tanLength,5);
stroke(tanA,5); stroke(tanB,5); stroke(tanC,5);
size(tanLabel,18*u); bold(tanLabel);

tag(sinCircle,trigWorld); tag(sinCX,trigWorld); tag(sinCY,trigWorld);
tag(sinO,trigWorld); tag(sinP,trigWorld); tag(sinHeight,trigWorld);
tag(sinRay,trigWorld); tag(sinGuide,trigWorld); tag(sinAngle,trigWorld);
tag(sinGX,trigWorld); tag(sinGY,trigWorld); tag(sinCurve,trigWorld);
tag(sinDot,trigWorld); tag(sinFoot,trigWorld); tag(sinDrop,trigWorld); tag(sinLabel,trigWorld);
tag(cosCircle,trigWorld); tag(cosCX,trigWorld); tag(cosCY,trigWorld);
tag(cosO,trigWorld); tag(cosP,trigWorld); tag(cosReach,trigWorld);
tag(cosRay,trigWorld); tag(cosGuide,trigWorld);
tag(cosGX,trigWorld); tag(cosGY,trigWorld); tag(cosCurve,trigWorld);
tag(cosDot,trigWorld); tag(cosFoot,trigWorld); tag(cosDrop,trigWorld); tag(cosLabel,trigWorld);
tag(tanCircle,trigWorld); tag(tanCX,trigWorld); tag(tanCY,trigWorld); tag(tangentWall,trigWorld);
tag(tanO,trigWorld); tag(tanP,trigWorld); tag(tanHit,trigWorld); tag(tanBase,trigWorld);
tag(tanRay,trigWorld); tag(tanLength,trigWorld);
tag(tanGX,trigWorld); tag(tanGY,trigWorld); tag(tanA,trigWorld); tag(tanB,trigWorld); tag(tanC,trigWorld);
tag(tanDot,trigWorld); tag(tanFoot,trigWorld); tag(tanDrop,trigWorld); tag(tanLabel,trigWorld);

hidden(kicker); hidden(head); hidden(identity); hidden(degrees); hidden(radians);
hidden(caption); hidden(alpha); hidden(trigWorld);
untraced(sinCurve); untraced(cosCurve); untraced(tanA); untraced(tanB); untraced(tanC);

step("one angle enters three worlds") {
  par {
    show(kicker,0.30); show(head,0.45); show(identity,0.45);
    show(degrees,0.30); show(radians,0.30); show(caption,0.40);
    show(alpha,0.35);
  }
  stagger(0.04) {
    show(trigWorld,0.30);
  }
}
wait(0.60);

step("height becomes sine") {
  par {
    to(alpha,value,1.05,2.20,smooth);
    say(head,"Sine records the rotating point's height.",0.45,smooth);
    say(caption,"The cyan projection and cyan graph are the same number.",0.45,smooth);
    pulse(sinGuide,0.70); pulse(sinCurve,0.70);
  }
}
wait(0.55);

step("reach becomes cosine") {
  par {
    to(alpha,value,2.35,2.30,smooth);
    say(head,"Cosine records its horizontal reach.",0.45,smooth);
    say(caption,"Past 90°, the point moves left—so cosine becomes negative.",0.48,smooth);
    pulse(cosGuide,0.70); pulse(cosCurve,0.70);
  }
}
wait(0.55);

step("tangent breaks at the asymptote") {
  par {
    to(alpha,value,1.56,1.70,smooth);
    say(head,"Tangent races toward infinity.",0.40,smooth);
    say(caption,"At π/2 the radius is parallel to the tangent line. There is no intersection.",0.50,smooth);
    pulse(tangentWall,0.70);
  }
  cue(whoosh);
  par {
    to(alpha,value,1.82,1.10,smooth);
    say(head,"It does not cross. A new branch begins.",0.40,smooth);
    say(caption,"Manic leaves the discontinuity empty instead of drawing a false connection.",0.50,smooth);
  }
}
wait(0.65);

step("one rotation reveals every sign") {
  par {
    to(alpha,value,3.75,3.10,smooth);
    say(head,"One angle controls every sign and every value.",0.45,smooth);
    say(caption,"At 215°: sine and cosine are negative, while tangent is positive.",0.50,smooth);
  }
}
wait(0.70);

step("complete the cycle") {
  par {
    to(alpha,value,6.25,4.00,smooth);
    say(head,"Three graphs. One rotating radius.",0.45,smooth);
    say(caption,"The unit circle is not a mnemonic—it is the machine generating all three functions.",0.52,smooth);
  }
}

step("keep the mathematics running") {
  par {
    // No hold between cycles: the angle keeps moving while the camera turns
    // three stacked diagrams into one continuous cinematic inspection.
    to(alpha,value,12.53,7.60,linear);
    fade(alpha,0.30);
    say(head,"Now let the mathematics keep running.",0.45,smooth);
    say(caption,"The camera can move because every relationship remains alive.",0.48,smooth);
    seq {
      par {
        cam((cx,row1),1.00,smooth);
        zoom(1.28,1.00,smooth);
      }
      wait(1.00);
      cam((cx,row2),1.00,smooth);
      wait(1.00);
      par {
        // Aim slightly above the tangent row so its graph, explanation, and
        // creator identity share the frame instead of leaving a dead lower half.
        cam((cx,h*0.50),1.00,smooth);
        zoom(1.24,1.00,smooth);
      }
      wait(1.40);
      par {
        cam((cx,cy),1.20,smooth);
        zoom(1.00,1.20,smooth);
      }
    }
  }
}

step("creator call to action") {
  par {
    fade(kicker,0.30); fade(head,0.30); fade(identity,0.30);
    fade(degrees,0.30); fade(radians,0.30); fade(caption,0.30);
    fade(alpha,0.30); fade(trigWorld,0.45); fade(me.footer,0.30);
    show(me.endcard,0.60);
  }
}
wait(2.00);

function_graph

Plot an expression straight from a formula string.

// Function Graphs — plot ANY formula, not just a named curve. manic's answer to
// Manim's FunctionGraph(lambda t: ...): pass a formula string in x (alias t) and
// plot() samples it. This reproduces Manim's ExampleFunctionGraph — two
// Fourier-style packets and a domain-clipped, lifted copy of the second.
//
//   manic examples/function_graph.manic
//   manic examples/function_graph.manic --record out --fps 60

title("Function Graphs");
canvas(1280, 720);

text(head, (640, 92), "plot any formula — y = f(x)");
display(head);  color(head, cyan);  size(head, 26);  hidden(head);
text(cap, (640, 656), "");  color(cap, dim);  size(cap, 22);

// a faint frame to read the curves against (unit = 70 px)
plane(pl, (640, 384), 620, 300, 70);
hidden(pl.grid);  untraced(pl.x);  untraced(pl.y);

// a cosine packet: cos t + 1/2 cos 7t + 1/7 cos 14t, over x in [-7, 7]
plot(cosf, (640, 384), 70, 70, "cos(x) + 0.5*cos(7*x) + (1/7)*cos(14*x)", 7);
color(cosf, magenta);  untraced(cosf);

// the sine version of the same packet
plot(sinf, (640, 384), 70, 70, "sin(x) + 0.5*sin(7*x) + (1/7)*sin(14*x)", 7);
color(sinf, cyan);  untraced(sinf);

// same formula, clipped to x in [-4, 4] and lifted one unit (centre y - 70)
plot(sinf2, (640, 314), 70, 70, "sin(x) + 0.5*sin(7*x) + (1/7)*sin(14*x)", 4);
color(sinf2, lime);  untraced(sinf2);

// --- reveal ---
show(head, 0.5);
section("The plane");
say(cap, "a grid to read against — arrows on the axes");
show(pl.grid, 0.6);
par { draw(pl.x, 0.5);  draw(pl.y, 0.5); }
wait(0.3);

section("A cosine packet");
say(cap, "y = cos t + 1/2 cos 7t + 1/7 cos 14t");
draw(cosf, 1.3);
wait(0.6);

section("A sine packet");
say(cap, "same shape, sin for cos");
draw(sinf, 1.3);
wait(0.6);

section("Clip the domain");
say(cap, "same formula, but only x in [-4, 4], lifted one unit");
draw(sinf2, 1.1);
par { pulse(cosf);  pulse(sinf);  pulse(sinf2); }
wait(1.4);

area_under_curve

Riemann rectangles sweeping to the integral.

// Area Under a Curve — a Riemann sum sweeping n = 5, 10, 20, 40 to show the
// rectangles converging to the exact integral of x^2 on [0, 2.5] = 125/24.
//
// This is the FIRST example to use manic's loop layer: `let` variables,
// arithmetic in arguments, a `for` range loop, and id interpolation (`s5{i}`).
// The four bar-sets differ only in n / prefix / colour — a future `def` macro
// would collapse them to one call; loops already do the per-bar work.
//
//   manic examples/area_under_curve.manic
//   manic examples/area_under_curve.manic --record out --fps 60

title("Area Under a Curve");
canvas(1280, 720);

// --- parameters (edit freely) ---
let ox = 360;   let oy = 590;     // origin, in screen px
let ux = 200;   let uy = 52;      // px per unit on each axis
let a = 0;      let b = 2.5;      // integrate x^2 over [a, b]

text(head, (640, 96), "a Riemann sum becomes an integral");
display(head);  color(head, cyan);  size(head, 26);  hidden(head);
text(cap, (640, 656), "");  color(cap, dim);  size(cap, 24);

// axes
arrow(xax, (ox - 40, oy), (920, oy));   color(xax, dim);  untraced(xax);
arrow(yax, (ox, oy + 20), (ox, 250));   color(yax, dim);  untraced(yax);
text(t1, (ox + 1*ux, oy + 24), "1");     color(t1, dim);  size(t1, 18);
text(t2, (ox + 2*ux, oy + 24), "2");     color(t2, dim);  size(t2, 18);
text(tb, (ox + b*ux, oy + 24), "2.5");   color(tb, dim);  size(tb, 18);

// the curve y = x^2 over [0, 2.5]
plot(curve, (ox, oy), ux, uy, "x*x", (a, b));  color(curve, cyan);  z(curve, 3);  untraced(curve);
text(clab, (ox + b*ux + 30, oy - b*b*uy), "y = x^2");  color(clab, cyan);  size(clab, 22);  hidden(clab);

// --- midpoint rectangles, one loop per count ---
let n = 5;   let dx = (b - a) / n;
for i in 0..n {
  let mid = a + (i + 0.5) * dx;   let h = mid * mid;
  rect(s5{i}, (ox + mid*ux, oy - h*uy/2), dx*ux, h*uy);
  filled(s5{i});  color(s5{i}, magenta);  opacity(s5{i}, 0.4);  tag(s5{i}, r5);
}
let n = 10;  let dx = (b - a) / n;
for i in 0..n {
  let mid = a + (i + 0.5) * dx;   let h = mid * mid;
  rect(s10{i}, (ox + mid*ux, oy - h*uy/2), dx*ux, h*uy);
  filled(s10{i});  color(s10{i}, magenta);  opacity(s10{i}, 0.4);  tag(s10{i}, r10);
}
let n = 20;  let dx = (b - a) / n;
for i in 0..n {
  let mid = a + (i + 0.5) * dx;   let h = mid * mid;
  rect(s20{i}, (ox + mid*ux, oy - h*uy/2), dx*ux, h*uy);
  filled(s20{i});  color(s20{i}, magenta);  opacity(s20{i}, 0.4);  tag(s20{i}, r20);
}
let n = 40;  let dx = (b - a) / n;
for i in 0..n {
  let mid = a + (i + 0.5) * dx;   let h = mid * mid;
  rect(s40{i}, (ox + mid*ux, oy - h*uy/2), dx*ux, h*uy);
  filled(s40{i});  color(s40{i}, magenta);  opacity(s40{i}, 0.4);  tag(s40{i}, r40);
}
hidden(r5);  hidden(r10);  hidden(r20);  hidden(r40);

// --- script ---
show(head, 0.5);
say(cap, "the shaded area under y = x^2 from 0 to 2.5");
par { draw(xax, 0.5);  draw(yax, 0.5); }
draw(curve, 0.9);
show(clab, 0.3);
wait(0.4);

section("Rectangles");
say(cap, "n = 5 rectangles  ->  area ~ 5.16");
show(r5, 0.6);
wait(0.7);
fade(r5, 0.3);

say(cap, "n = 10  ->  area ~ 5.20");
show(r10, 0.5);
wait(0.6);
fade(r10, 0.3);

say(cap, "n = 20  ->  area ~ 5.20");
show(r20, 0.5);
wait(0.6);
fade(r20, 0.3);

say(cap, "n = 40  ->  area ~ 5.21 (hugging the curve)");
show(r40, 0.5);
wait(0.8);

section("The integral");
say(cap, "as n grows without bound, the sum IS the integral");
fade(r40, 0.4);
text(ans, (640, 300), "exact area = 125/24 = 5.208");  display(ans);  color(ans, lime);  size(ans, 30);  hidden(ans);
show(ans, 0.5);
pulse(ans);
wait(1.6);

riemann_rainbow

Coloured Riemann rectangles revealed one by one.

// Riemann Rainbow — the area under y = sin(x) on [0, pi], sliced into rectangles
// that each get their own neon hue and rise into place one by one, left to right.
//
// A showcase for the loop layer: one `for` builds all the bars (each `hue`d by
// its index), and a `stagger` block sweeps them in. Exact area = 2.
//
//   manic examples/riemann_rainbow.manic
//   manic examples/riemann_rainbow.manic --record out --fps 60

title("Riemann Rainbow");
canvas(1280, 720);

// --- parameters ---
let ox = 190;   let oy = 560;      // origin (screen px)
let ux = 300;   let uy = 340;      // px per unit
let a = 0;      let b = pi;         // y = sin(x) over [0, pi]
let n = 28;     let dx = (b - a) / n;

text(head, (640, 96), "area under y = sin(x), one slice at a time");
display(head);  color(head, cyan);  size(head, 26);  hidden(head);
text(cap, (640, 640), "");  color(cap, dim);  size(cap, 24);

// axes
arrow(xax, (ox - 40, oy), (1180, oy));   color(xax, dim);  untraced(xax);
arrow(yax, (ox, oy + 20), (ox, 180));    color(yax, dim);  untraced(yax);
text(l0, (ox, oy + 26), "0");            color(l0, dim);  size(l0, 18);
text(lp, (ox + b*ux, oy + 26), "pi");    color(lp, dim);  size(lp, 18);

// the curve
plot(curve, (ox, oy), ux, uy, "sin(x)", (a, b));  color(curve, fg);  z(curve, 5);  untraced(curve);

// --- one rainbow bar per slice (midpoint heights) ---
for i in 0..n {
  let mid = a + (i + 0.5) * dx;
  let h = sin(mid);
  rect(bar{i}, (ox + mid*ux, oy - h*uy/2), dx*ux, h*uy);
  filled(bar{i});
  hue(bar{i}, 360 * i / n);      // each slice its own colour
  opacity(bar{i}, 0.9);
  tag(bar{i}, bars);
}
hidden(bars);

// --- script ---
show(head, 0.5);
say(cap, "y = sin(x) from 0 to pi");
par { draw(xax, 0.5);  draw(yax, 0.5); }
draw(curve, 1.0);
wait(0.3);

section("Slice by slice");
say(cap, "28 rectangles rise in, left to right");
stagger(0.05) {
  for i in 0..n { show(bar{i}, 0.35); }
}
wait(0.6);

section("The area");
say(cap, "together they fill the area under the curve = 2");
par { pulse(curve); }
wait(1.6);

riemann_readout

Running sums shown as a live computed number.

// Riemann + Live Total — the midpoint area under y = x^2 on [0, 2.5] is
// COMPUTED in-language with a `sum(...)` reduction, and a `counter` readout
// tweens from 0 up to that total while the bars fill in. The number you see
// counting is the reduction's value.
//
// Showcases reductions + animated numeric readouts (`counter` + `to(_, value)`).
//
//   manic examples/riemann_readout.manic
//   manic examples/riemann_readout.manic --record out --fps 60

title("Riemann + Live Total");
canvas(1280, 720);

let ox = 300;   let oy = 560;
let ux = 190;   let uy = 52;
let a = 0;      let b = 2.5;   let n = 40;   let dx = (b - a) / n;

// the midpoint Riemann sum, computed at build time
let area = sum(i in 0..n : (a + (i + 0.5)*dx)^2 * dx);

text(head, (640, 90), "area under y = x^2, summed as the bars fill");
display(head);  color(head, cyan);  size(head, 26);  hidden(head);

counter(total, (950, 210), 0, 3, "area = ", "");
display(total);  color(total, lime);  size(total, 36);  hidden(total);
text(exact, (950, 260), "exact 125/24 = 5.208");  color(exact, dim);  size(exact, 20);  hidden(exact);

// axes
arrow(xax, (ox - 40, oy), (900, oy));   color(xax, dim);  untraced(xax);
arrow(yax, (ox, oy + 20), (ox, 210));   color(yax, dim);  untraced(yax);
text(t1, (ox + 1*ux, oy + 24), "1");    color(t1, dim);  size(t1, 18);
text(t2, (ox + 2*ux, oy + 24), "2");    color(t2, dim);  size(t2, 18);

// curve
plot(curve, (ox, oy), ux, uy, "x*x", (a, b));  color(curve, cyan);  z(curve, 4);  untraced(curve);

// midpoint rectangles
for i in 0..n {
  let mid = a + (i + 0.5) * dx;
  let h = mid * mid;
  rect(bar{i}, (ox + mid*ux, oy - h*uy/2), dx*ux, h*uy);
  filled(bar{i});  color(bar{i}, magenta);  opacity(bar{i}, 0.45);  tag(bar{i}, bars);
}
hidden(bars);

// --- script ---
show(head, 0.5);
par { draw(xax, 0.5);  draw(yax, 0.5); }
draw(curve, 0.9);
show(total, 0.3);
show(exact, 0.3);
wait(0.3);

// bars sweep in while the total counts up to the reduction's value
par {
  stagger(0.03) { for i in 0..n { show(bar{i}, 0.25); } }
  to(total, value, area, 1.6, linear);
}
wait(1.4);
pulse(total);
wait(1.0);

tangent

The tangent line to a curve, sliding along it — its tilt is read from the function itself, so it’s always the true slope (flat at the peaks).

title("The Tangent Line — a curve's slope, made visible");
canvas("16:9");

text(hdr, (cx, 60), "The slope of sin x, everywhere at once");
size(hdr, 30); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

// the curve — plot remembers its function, so tangent can ask it questions.
// center the domain 0..6.3 across the canvas (midpoint x=3.15 sits at cx)
plot(f, (cx - 440, cy + 40), 140, 120, "sin(x)", (0, 6.3));
color(f, cyan); stroke(f, 3); untraced(f);

// a tangent that touches f where x = 0.5 (line + contact dot, one call)
tangent(tan, f, 0.5, 260);
color(tan, gold); untraced(tan);

text(cap, (cx, h - 60), "watch the tilt follow the curve");
size(cap, 20); color(cap, dim); display(cap); hidden(cap);

// ---- timeline ----
show(hdr, 0.5);
draw(f, 1.4);
show(tan, 0.6);
show(cap, 0.4);
wait(0.4);

// slide the touch point along the whole curve — the slope is derived live
to(tan, x, 5.8, 5);
wait(0.3);
to(tan, x, 1.6, 2.5);   // back toward the first peak, where the slope is 0

analysis

Ask one curve everything at once — tangent, a live slope number, the normal, the area sweeping open beneath it, and the integral climbing to its true value.

title("Reading a curve: slope, tangent, normal, area");
canvas("16:9");

text(hdr, (cx, 58), "Asking a curve questions");
size(hdr, 30); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

// one curve — everything below asks IT, by name
plot(f, (cx - 440, cy + 30), 140, 110, "sin(x)", (0, 6.3));
color(f, cyan); stroke(f, 3); untraced(f);

// the area under it — starts collapsed at x=0.6, sweeps open
area(reg, f, 0.6, 0.6);
color(reg, lime);

// a live integral readout that climbs as the area sweeps
integral(area_val, f, 0.6, 0.6, (cx + 340, cy - 210));
color(area_val, lime);

// tangent + its live slope number, both riding the same point
tangent(tan, f, 0.6, 240);
color(tan, gold);

slope(sl, f, 0.6);
color(sl, gold);

// the normal, perpendicular at the same place
normal(nrm, f, 0.6, 150);
color(nrm, magenta); hidden(nrm);

// ---- timeline ----
show(hdr, 0.5);
draw(f, 1.4);
show(tan, 0.5);
show(sl, 0.4);
wait(0.4);

// sweep the area open while the tangent + slope slide together and the
// integral readout climbs
par {
  to(reg, x, 5.7, 4);
  to(area_val, x, 5.7, 4);
  to(tan, x, 5.7, 4);
  to(sl, x, 5.7, 4);
}
wait(0.4);

// reveal the normal and glide everything back to the first peak (slope 0)
show(nrm, 0.4);
par {
  to(tan, x, 1.571, 2.5);
  to(sl, x, 1.571, 2.5);
  to(nrm, x, 1.571, 2.5);
}

newton

Newton’s method, drawn as a zig-zag: from a first guess, slide down each tangent to the axis, back up to the curve, and watch the guesses walk to the root.

title("Newton's method: chasing a root");
canvas("16:9");

text(hdr, (cx, 56), "Newton's method finds where x squared = 2");
size(hdr, 28); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

// a reference frame so the x-axis (where the tangents land) is visible
axes(ax, (cx - 250, cy + 170), 540, 360, 1);
color(ax, dim); untraced(ax);

// f(x) = x^2 - 2, whose positive root is sqrt(2)
plot(f, (cx - 250, cy + 170), 180, 70, "x*x - 2", (-0.4, 3));
color(f, cyan); stroke(f, 3); untraced(f);

// the true zero-crossing, marked
roots(zero, f);
color(zero, lime); hidden(zero);

// the Newton zig-zag from a first guess of x = 3
newton(walk, f, 3);
color(walk, gold); stroke(walk, 3); untraced(walk);

text(cap, (cx, h - 60), "each tangent slides the guess closer");
size(cap, 20); color(cap, dim); display(cap); hidden(cap);

// ---- timeline ----
show(hdr, 0.5);
draw(ax, 0.8);
draw(f, 1.4);
wait(0.3);
show(cap, 0.4);

// walk the iterates in to the root
draw(walk, 3.5);
wait(0.3);

// reveal the exact root it converged on
show(zero, 0.5);
pulse(zero, 0.6);

inverse-derivatives

Why a function and its inverse have reciprocal slopes: e^x and ln x mirrored across y = x, with the slopes at matching points multiplying to 1.

title("Inverse-function derivatives — why the pairs mirror");
canvas("16:9");

// uniform scale (sx == sy) so a function and its inverse reflect correctly
let ox = cx - 470;
let oy = cy + 110;
let s = 72;

text(hdr, (cx, 52), "A function and its inverse: mirror curves, reciprocal slopes");
size(hdr, 26); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

// ---------------- the mirror plane ----------------
axes(ax, (ox, oy), 470, 300, 1);
color(ax, dim); untraced(ax);

// y = x, the mirror line
line(diag, (ox - 2.6*s, oy + 2.6*s), (ox + 3.8*s, oy - 3.8*s));
color(diag, dim); untraced(diag);
text(diaglab, (ox + 3.4*s, oy - 3.4*s - 22), "y = x");
size(diaglab, 16); color(diaglab, dim); display(diaglab); hidden(diaglab);

// e^x and its inverse ln x — reflections of each other
plot(ef, (ox, oy), s, s, "exp(x)", (-2.6, 1.45));
color(ef, cyan); stroke(ef, 3); untraced(ef);
text(eflab, (ox + 1.45*s + 8, oy - 4.1*s), "e^x");
size(eflab, 18); color(eflab, cyan); display(eflab); hidden(eflab);

plot(lf, (ox, oy), s, s, "ln(x)", (0.075, 4.3));
color(lf, magenta); stroke(lf, 3); untraced(lf);
text(lflab, (ox + 4.2*s, oy - 1.45*s), "ln x");
size(lflab, 18); color(lflab, magenta); display(lflab); hidden(lflab);

// tangent + live slope at a point on e^x, and at its mirror point on ln x
tangent(te, ef, 0.5, 150);
color(te, cyan); hidden(te);
slope(se, ef, 0.5);
color(se, cyan); hidden(se);

tangent(tl, lf, 1.65, 150);
color(tl, magenta); hidden(tl);
slope(sl, lf, 1.65);
color(sl, magenta); hidden(sl);

text(rec, (cx + 340, cy + 60), "slope x slope = 1");
size(rec, 22); color(rec, lime); bold(rec); display(rec); hidden(rec);
text(rec2, (cx + 340, cy + 96), "(1.65) x (0.61)");
size(rec2, 18); color(rec2, dim); display(rec2); hidden(rec2);

// ---------------- the four identity pairs ----------------
text(t1, (cx + 340, cy - 190), "(e^x)' = e^x        (ln x)' = 1/x");
size(t1, 17); color(t1, fg); display(t1); hidden(t1);
text(t2, (cx + 340, cy - 150), "(sin x)' = sqrt(1-sin^2 x)   (arcsin x)' = 1/sqrt(1-x^2)");
size(t2, 15); color(t2, fg); display(t2); hidden(t2);
text(t3, (cx + 340, cy - 118), "(cos x)' = -sqrt(1-cos^2 x)  (arccos x)' = -1/sqrt(1-x^2)");
size(t3, 15); color(t3, fg); display(t3); hidden(t3);
text(t4, (cx + 340, cy - 86), "(tan x)' = 1+tan^2 x         (arctan x)' = 1/(1+x^2)");
size(t4, 15); color(t4, fg); display(t4); hidden(t4);

// ================= timeline =================
show(hdr, 0.6);
draw(ax, 0.7);
draw(diag, 0.5);
show(diaglab, 0.3);
par {
  draw(ef, 1.4);
  draw(lf, 1.4);
}
par {
  show(eflab, 0.4);
  show(lflab, 0.4);
}
wait(0.3);

// the reciprocal-slope check
par {
  show(te, 0.4);
  show(se, 0.4);
}
par {
  show(tl, 0.4);
  show(sl, 0.4);
}
show(rec, 0.5);
show(rec2, 0.4);
flash(rec, lime);
wait(0.4);

// the four pairs it generates
stagger(0.4) {
  show(t1, 0.4);
  show(t2, 0.4);
  show(t3, 0.4);
  show(t4, 0.4);
}

derivative-of-ln-x

A visual proof of (ln x)' = 1/x: one continuous 3D coordinate plane turns over, x/y exchange screen roles, and unchanged algebra terms retain their identity.

// ============================================================================
// derivative-of-ln-x.manic — inverse-function derivatives on a turning plane
// ----------------------------------------------------------------------------
// The curve is first read as y=e^x. A true 3-D camera turn exchanges the screen
// roles of world x/y, so the same relationship reads x=e^y. While the graph is
// hidden for the first plane turn, morph3 exchanges its coordinates; the same
// geometry can then remain visible through the return turn into y=ln(x).
// ============================================================================

title("Why the derivative of ln x is 1/x");
canvas("16:9");
template("plain");
// Landscape proof: the upper-right stays clear while the algebra owns the
// bottom and the vertical axis label owns the top-centre.
watermark(manicMark, (1135, 30), "Made With Manic");

// Orthographic overhead camera: the continuous pole-safe orbit frame keeps the
// whole turn smooth, and roll3 controls which world direction is screen-up.
camera3((0, 0.5, 12), (0, 0.5, 0), 8.5, orthographic);

// ---------------------------------------------------------------------------
// ONE WORLD PLANE · axes, grid, exponential, tangent and exact slope triangle
// ---------------------------------------------------------------------------

grid3(grid, (0, 0, 0), 4, 1);
color(grid, dim); opacity(grid, 0.30); tag(grid, world);

arrow3(xaxis, (-4.05, 0, 0), (4.05, 0, 0));
arrow3(yaxis, (0, -3.4, 0), (0, 4.05, 0));
color(xaxis, fg); color(yaxis, fg); thick(xaxis, 0.012); thick(yaxis, 0.012);
tag(xaxis, world); tag(yaxis, world);

for i in -4..5 {
  if i != 0 {
    line3(xtick{i}, (i, -0.07, 0), (i, 0.07, 0));
    line3(ytick{i}, (-0.07, i, 0), (0.07, i, 0));
    color(xtick{i}, dim); color(ytick{i}, dim);
    tag(xtick{i}, world); tag(ytick{i}, world);
  }
}

equation(xlab, (0,0), `x`, 31); pin3(xlab, (4.10, -0.18, 0)); tag(xlab, world);
equation(ylab, (0,0), `y`, 31); pin3(ylab, (-0.18, 4.10, 0)); tag(ylab, world);
hidden(world);

// Source curve γ(t)=(t,e^t), and its inverse parameterisation γ⁻¹(t)=(e^t,t).
curve3(curve, "t", "exp(t)", "0", (-3.6, 1.42));
curve3(curveTarget, "exp(t)", "t", "0", (-3.6, 1.42));
color(curve, lime); color(curveTarget, lime); thick(curve, 0.024); thick(curveTarget, 0.024);
untraced(curve); hidden(curveTarget); morph3(curve, curveTarget);

equation(expName, (0,0), `y=e^x`, 31); color(expName, lime); pin3(expName, (-1.45, 2.20, 0)); hidden(expName);
equation(swappedName, (0,0), `x=e^y`, 31); color(swappedName, lime); pin3(swappedName, (2.65, -1.20, 0)); hidden(swappedName);
equation(logName, (0,0), `y=\ln(x)`, 31); color(logName, lime); pin3(logName, (2.65, 0.90, 0)); hidden(logName);

// At t=0.6: P=(0.6,e^0.6), and e^0.6 ≈ 1.822. The tangent reaches y=0
// exactly one unit of run before P, so its slope triangle is rise/run = y/1.
curve3(tangent, "-0.65+2*t", "-0.455529+3.644238*t", "0", (0,1));
curve3(tangentTarget, "-0.455529+3.644238*t", "-0.65+2*t", "0", (0,1));
color(tangent, magenta); color(tangentTarget, magenta); thick(tangent, 0.018); thick(tangentTarget, 0.018);
untraced(tangent); hidden(tangentTarget); morph3(tangent, tangentTarget);

curve3(runSide, "-0.4+t", "0", "0", (0,1));
curve3(runTarget, "0", "-0.4+t", "0", (0,1));
color(runSide, gold); color(runTarget, gold); thick(runSide, 0.024); thick(runTarget, 0.024);
untraced(runSide); hidden(runTarget); morph3(runSide, runTarget);

curve3(riseSide, "0.6", "1.822119*t", "0", (0,1));
curve3(riseTarget, "1.822119*t", "0.6", "0", (0,1));
color(riseSide, cyan); color(riseTarget, cyan); thick(riseSide, 0.024); thick(riseTarget, 0.024);
untraced(riseSide); hidden(riseTarget); morph3(riseSide, riseTarget);

point3(contact, (0.6, 1.822119, 0), 0.075); color(contact, fg); hidden(contact);
point3(contactTarget, (1.822119, 0.6, 0), 0.075); color(contactTarget, fg); hidden(contactTarget);

equation(riseY, (0,0), `y`, 28); color(riseY, cyan); pin3(riseY, (0.82, 0.91, 0)); hidden(riseY);
equation(runOne, (0,0), `1`, 28); color(runOne, gold); pin3(runOne, (0.10, -0.22, 0)); hidden(runOne);
equation(targetX, (0,0), `x`, 28); color(targetX, cyan); pin3(targetX, (0.91, 0.82, 0)); hidden(targetX);
equation(targetOne, (0,0), `1`, 28); color(targetOne, gold); pin3(targetOne, (-0.22, 0.10, 0)); hidden(targetOne);

// The diagonal is the hinge / mirror relation during the plane turns.
for i in -9..10 {
  line3(diag{i}, (i*0.42, i*0.42, 0.02), (i*0.42+0.24, i*0.42+0.24, 0.02));
  color(diag{i}, magenta); thick(diag{i}, 0.018); untraced(diag{i}); tag(diag{i}, mirror);
}
equation(diagName, (0,0), `y=x`, 27); color(diagName, magenta); pin3(diagName, (2.55, 2.55, 0.02)); hidden(diagName);

// Screen-space algebra. Separate equations keep the camera/geometry generic.
equation(slopeExp, (cx, 655), `\textcolor{magenta}{\mathrm{slope}}=\textcolor{cyan}{e^x}`, 40); hidden(slopeExp);
equation(slopeY, (cx, 655), `\textcolor{magenta}{\mathrm{slope}}=\textcolor{cyan}{y}`, 40); hidden(slopeY);
equation(slopeFracY, (cx, 655), `\textcolor{magenta}{\mathrm{slope}}=\frac{\textcolor{cyan}{y}}{\textcolor{gold}{1}}=\frac{\textcolor{cyan}{\mathrm{rise}}}{\textcolor{gold}{\mathrm{run}}}`, 40); hidden(slopeFracY);
// Persistent algebra pieces. The unchanged prefix/equality never disappear:
// only the term being justified moves, fades, or arrives. This is the same
// object-continuity principle used by matching-transform systems, expressed
// with ordinary Manic entities rather than replacing a whole equation image.
equation(slopeWord, (500, 655), `\textcolor{magenta}{\mathrm{slope}}`, 40); hidden(slopeWord); tag(slopeWord, inverseAlgebra);
equation(mainEquals, (575, 655), `=`, 40); hidden(mainEquals); tag(mainEquals, inverseAlgebra);
equation(heightTerm, (630, 655), `\textcolor{cyan}{\mathrm{height}}`, 40); hidden(heightTerm); tag(heightTerm, inverseAlgebra);
equation(xTerm, (630, 655), `\textcolor{cyan}{x}`, 40); hidden(xTerm); tag(xTerm, inverseAlgebra);
equation(oneTerm, (630, 674), `\textcolor{gold}{1}`, 36); hidden(oneTerm); tag(oneTerm, inverseAlgebra);
line(termBar, (616, 657), (644, 657)); color(termBar, fg); stroke(termBar, 2); untraced(termBar); tag(termBar, inverseAlgebra);
equation(ratioEquals, (685, 655), `=`, 40); hidden(ratioEquals); tag(ratioEquals, inverseAlgebra);
equation(ratioTerm, (780, 655), `\frac{\textcolor{cyan}{\mathrm{rise}}}{\textcolor{gold}{\mathrm{run}}}`, 40); hidden(ratioTerm); tag(ratioTerm, inverseAlgebra);
equation(derivativeTerm, (475, 655), `\frac{d}{dx}\ln(x)`, 41); hidden(derivativeTerm); tag(derivativeTerm, inverseAlgebra);

// Split glyphs let generic `cycle` retain their identity through xy → yx.
equation(planeX, (550, 640), `x`, 54); hidden(planeX); tag(planeX, planeLabel);
equation(planeY, (575, 640), `y`, 54); hidden(planeY); tag(planeY, planeLabel);
equation(planeWord, (685, 640), `\mathrm{plane}`, 54); hidden(planeWord); tag(planeWord, planeLabel);

// ---------------------------------------------------------------------------
// TIMELINE · 75.49 seconds including manic's final one-second tail
// ---------------------------------------------------------------------------

show(world, 1.20);
draw(curve, 2.40);
show(expName, 0.60);
wait(2.50);

show(slopeExp, 0.70);
wait(2.20);
par { draw(riseSide, 1.20); show(riseY, 0.45); show(contact, 0.30); }
par { fade(slopeExp, 0.55); show(slopeY, 0.55); }
wait(2.00);

par { draw(tangent, 1.20); draw(runSide, 1.00); show(runOne, 0.40); }
par { fade(slopeY, 0.60); show(slopeFracY, 0.60); }
wait(7.90);

// First turn: remove the measurement clutter, reveal the mirror hinge, and
// move from the top of the plane to its underside. Below + -90° roll makes
// screen-horizontal follow world y and screen-vertical follow world x.
par {
  fade(curve, 0.70); fade(expName, 0.70); fade(tangent, 0.70);
  fade(runSide, 0.70); fade(riseSide, 0.70); fade(contact, 0.70);
  fade(riseY, 0.70); fade(runOne, 0.70); fade(slopeFracY, 0.70);
}
par { draw(mirror, 0.70); show(diagName, 0.50); show(planeLabel, 0.50); }
par {
  orbit3(-90, -90, 12, 7.00, smooth);
  roll3(90, 7.00, smooth);
  // The graph is hidden here, so exchange its coordinates before it returns.
  to(curve, morph, 1, 7.00, smooth);
  to(tangent, morph, 1, 7.00, smooth);
  to(runSide, morph, 1, 7.00, smooth);
  to(riseSide, morph, 1, 7.00, smooth);
  seq { wait(2.80); cycle(planeX, planeY, 1.40, 70, smooth); }
}

// Same world geometry, now read with exchanged screen axes.
par {
  show(curve, 0.70); show(tangent, 0.70); show(runSide, 0.70); show(riseSide, 0.70);
  show(contactTarget, 0.50); show(swappedName, 0.55); show(targetX, 0.45); show(targetOne, 0.45);
  fade(diagName, 0.45); erase(mirror, 0.70); fade(planeLabel, 0.45);
}
par { show(slopeWord, 0.65); show(mainEquals, 0.65); show(heightTerm, 0.65); }
wait(3.00);
par { fade(heightTerm, 0.60); show(xTerm, 0.60); }
wait(3.00);
par { show(ratioEquals, 0.60); show(ratioTerm, 0.60); }
wait(3.00);
// x becomes x/1 in place: x lifts, the denominator arrives, and the rest of
// the displayed identity remains untouched.
par { move(xTerm, (630, 640), 0.60, smooth); show(oneTerm, 0.60); draw(termBar, 0.60); }
wait(6.20);

// Second turn: return the camera overhead while keeping the transformed curve
// and triangle visible. The same objects land as an ordinary y=ln(x) graph.
par {
  draw(mirror, 0.60); show(diagName, 0.45); show(planeLabel, 0.45);
  fade(slopeWord, 0.60); fade(mainEquals, 0.60); fade(xTerm, 0.60);
  fade(oneTerm, 0.60); erase(termBar, 0.60); fade(ratioEquals, 0.60); fade(ratioTerm, 0.60);
}
par {
  orbit3(-90, 90, 12, 7.00, smooth);
  roll3(0, 7.00, smooth);
  fade(swappedName, 3.00); show(logName, 3.00);
  // Prepare the next algebra state invisibly while the plane is turning.
  move(ratioTerm, (630, 655), 1.20, smooth);
  move(oneTerm, (630, 640), 1.20, smooth);
  move(xTerm, (630, 674), 1.20, smooth);
  seq { wait(2.80); cycle(planeX, planeY, 1.40, -70, smooth); }
}
par {
  fade(planeLabel, 0.45); fade(diagName, 0.45); erase(mirror, 0.70);
  show(slopeWord, 0.65); show(mainEquals, 0.65); show(ratioTerm, 0.65);
}
wait(2.20);
// Only the right-hand term changes: rise/run becomes 1/x.
par { fade(ratioTerm, 0.60); show(oneTerm, 0.60); show(xTerm, 0.60); draw(termBar, 0.60); }
wait(3.00);
// The proven reciprocal stays; only the name on the left becomes d/dx ln(x).
par { fade(slopeWord, 0.70); show(derivativeTerm, 0.70); pulse(curve, 0.70); }
wait(9.89);

spline

Interpolation: one smooth curve drawn through a scattered set of points — it passes through every knot exactly.

title("A smooth curve through the data");
canvas("16:9");

text(hdr, (cx, 70), "Interpolation: one smooth curve through every point");
size(hdr, 26); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

// scattered data points — the spline passes through all of them
spline(s, (300, 620), (520, 340), (760, 560), (1000, 300), (1240, 480), (1500, 260));
color(s, cyan); stroke(s, 4); untraced(s);

text(cap, (cx, h - 60), "Catmull-Rom — it hits each knot exactly");
size(cap, 20); color(cap, dim); display(cap); hidden(cap);

// ---- timeline ----
show(hdr, 0.5);
// pop the knots in first
show(s.knots, 0.6);
wait(0.3);
// then trace the smooth curve through them
draw(s, 2.2);
show(cap, 0.4);

sqrt-tanx

√(tan θ) by pure geometry — a 3B1B-style proof: on the unit circle, tan θ is the vertical tangent length; Euclid’s geometric mean (semicircle on diameter 1+a, altitude at 1) turns that length into √(tan θ). Then the curve itself, painted teal → violet → coral. Uses the expanded semantic palette.

// ============================================================================
//  sqrt-tanx.manic — √(tan x) by PURE GEOMETRY (3B1B-style)
// ----------------------------------------------------------------------------
//  THE PROBLEM: √(tan θ) looks like algebra. It is geometry.
//
//  THE PROOF, in three pictures:
//   1. On the unit circle, tan θ IS the length of the vertical tangent segment.
//   2. √a is the geometric mean of 1 and a — Euclid: semicircle on diameter
//      1+a, erect a perpendicular at the "1" mark; its height is √a.
//   3. Set a = tan θ. The altitude IS √(tan θ). No algebra required.
//
//  Then we sweep θ and watch the construction's height paint the curve —
//  teal → violet → coral — using the expanded semantic palette.
//
//    manic examples/sqrt-tanx.manic
//    manic examples/sqrt-tanx.manic --still 22
// ============================================================================

title("√(tan x) — Pure Geometry");
canvas("16:9");
template("blank");

// ---- stage ----
circle(well, (cx, 400), 340);
filled(well);
gradient(well, panel, void, radial);
opacity(well, 0.55);

// ============================================================================
//  LEFT — the unit circle, where tan θ is a length
// ============================================================================
let ox = 250;
let oy = 430;
let R = 145;
// a friendly angle: θ = 0.95 rad ≈ 54.4°, tan ≈ 1.40, √tan ≈ 1.18
let th = 0.95;
let Px = ox + R*cos(th);
let Py = oy - R*sin(th);
let Ty = oy - R*tan(th);

circle(O, (ox, oy), 7); outlined(O); color(O, fg); stroke(O, 1.5); hidden(O);
dot(A, (ox + R, oy), 5); color(A, dim); hidden(A);          // (1, 0)
// contact points: open dashed rings (filled dots hide the circle + tangent)
circle(P, (Px, Py), 11);
outlined(P); color(P, mint); stroke(P, 2); dashed(P, 3.5, 2.8); untraced(P); hidden(P);
circle(T, (ox + R, Ty), 11);
outlined(T); color(T, coral); stroke(T, 2); dashed(T, 3.5, 2.8); untraced(T); hidden(T);

// ray as a line (not arrow) so the filled arrowhead doesn't cover P
line(ray, (ox, oy), (Px, Py));
color(ray, mint); stroke(ray, 2.5); untraced(ray); hidden(ray);

// the tangent SEGMENT — its length IS tan θ (in radii)
line(tanseg, (ox + R, oy), (ox + R, Ty));
color(tanseg, coral); stroke(tanseg, 5); untraced(tanseg); hidden(tanseg);

// angle mark — textbook style: a thin ARC, never a filled wedge (fills hide the diagram)
arc(wedge, (ox, oy), R*0.42, 0, -th*180/pi);
color(wedge, violet); stroke(wedge, 2.5); untraced(wedge); hidden(wedge);

circle(uc, (ox, oy), R);
outlined(uc); outline(uc, teal); stroke(uc, 3); untraced(uc); hidden(uc);

line(axX, (ox - R - 30, oy), (ox + R + 100, oy));
color(axX, dim); stroke(axX, 1.5); untraced(axX); hidden(axX);
line(axY, (ox, oy + R + 40), (ox, oy - R - 50));
color(axY, dim); stroke(axY, 1.5); untraced(axY); hidden(axY);

line(tline, (ox + R, oy + R + 50), (ox + R, oy - R - 90));
color(tline, dim); stroke(tline, 1.5); dashed(tline, 10, 8); untraced(tline); hidden(tline);

text(labP, (Px + 14, Py - 14), "P"); size(labP, 20); color(labP, mint); hidden(labP);
text(labO, (ox - 18, oy + 22), "O"); size(labO, 18); color(labO, dim); hidden(labO);
text(labA, (ox + R + 14, oy + 22), "1"); size(labA, 18); color(labA, dim); hidden(labA);
text(labT, (ox + R + 18, Ty), "tan θ"); size(labT, 20); color(labT, coral); hidden(labT);
text(labTh, (ox + 48, oy - 28), "θ"); size(labTh, 22); color(labTh, violet); hidden(labTh);

// ============================================================================
//  RIGHT — Euclid's geometric mean: √a from 1 and a
// ============================================================================
let gx = 620;
let gy = 500;
let u = 110;                         // px per unit
let a = tan(th);                     // ≈ 1.40
let root = sqrt(a);                  // ≈ 1.18
let G0x = gx;
let G1x = gx + u;                    // the "1" mark
let G2x = gx + u*(1 + a);            // the "1+a" mark
let mid = (G0x + G2x)*0.5;
let rad = u*(1 + a)*0.5;

dot(G0, (G0x, gy), 5); color(G0, dim); hidden(G0);
dot(G1, (G1x, gy), 6); color(G1, teal); glow(G1, 0.4); hidden(G1);
dot(G2, (G2x, gy), 5); color(G2, coral); hidden(G2);
line(base, (G0x, gy), (G2x, gy));
color(base, fg); stroke(base, 3); untraced(base); hidden(base);

// upper semicircle on diameter [0, 1+a]
// screen angles: 0° right, 90° down, 270° up — from left through UP: start 180, sweep +180
arc(semi, (mid, gy), rad, 180, 180);
color(semi, indigo); stroke(semi, 3); untraced(semi); hidden(semi);

// altitude at the "1" mark — height = √(1·a) = √(tan θ)
line(alt, (G1x, gy), (G1x, gy - root*u));
color(alt, violet); stroke(alt, 5); untraced(alt); hidden(alt);
dot(H, (G1x, gy - root*u), 8); color(H, violet); glow(H, 0.7); hidden(H);

text(lab0, (G0x, gy + 28), "0"); size(lab0, 18); color(lab0, dim); hidden(lab0);
text(lab1, (G1x, gy + 28), "1"); size(lab1, 18); color(lab1, teal); hidden(lab1);
text(labA2, (G2x, gy + 28), "1+tanθ"); size(labA2, 18); color(labA2, coral); hidden(labA2);
text(labH, (G1x + 16, gy - root*u - 8), "√(tan θ)"); size(labH, 22); color(labH, violet); hidden(labH);

// brace / connector: coral tan length → feeds the geometric mean
arrow(feed, (ox + R + 36, (oy + Ty)*0.5), (G2x - 10, gy - 40));
color(feed, coral); stroke(feed, 2); dashed(feed, 8, 6); untraced(feed); hidden(feed);

// ============================================================================
//  BOTTOM — the curve itself, colored by the new palette
// ============================================================================
axes(ax, (920, 400), 280, 220);
hidden(ax);
plot(curve, (920, 400), 95, 85, "sqrt(tan(x))", (0.25, 1.35));
stroke(curve, 5); untraced(curve); hidden(curve);
gradient(curve, teal, violet, coral, 270);
// low x → small √tan (teal); high x → large (coral), via height = truth

// ============================================================================
//  TYPOGRAPHY
// ============================================================================
caption(q, "what IS the square root of a tangent?", (cx, 58), 32, gold);
equation(law, (cx, 110), `\sqrt{\tan\theta}`, 44);
color(law, violet); hidden(law);
equation(mean, (900, 160), `\sqrt{a}=\sqrt{1\cdot a}`, 28);
color(mean, teal); hidden(mean);
text(cap, (cx, h - 36), ""); size(cap, 20); color(cap, dim); display(cap);

// ============================================================================
//  SCRIPT
// ============================================================================

// 1 — HOOK
say(cap, "an expression that looks like algebra — but it is a length", 0.4);
wordpop(q, 0.16);
wait(0.3);
show(law, 0.5);
wait(0.6);

// 2 — UNIT CIRCLE
say(cap, "start with the unit circle and an angle θ", 0.4);
par { show(axX, 0.05); show(axY, 0.05); show(uc, 0.05); show(tline, 0.05); }
par {
  draw(axX, 0.5); draw(axY, 0.5);
  draw(uc, 1.0);
}
par { show(O, 0.3); show(labO, 0.3); }
draw(tline, 0.5);
show(A, 0.3); show(labA, 0.3);
wait(0.3);

// 3 — THE ANGLE AND THE RAY
say(cap, "draw the ray at angle θ — it meets the circle at P", 0.4);
show(wedge, 0.05); draw(wedge, 0.5); show(labTh, 0.3);
show(ray, 0.05); draw(ray, 0.7);
show(P, 0.05); draw(P, 0.35); show(labP, 0.3);
pulse(P);
wait(0.4);

// 4 — TAN θ IS A LENGTH
say(cap, "extend to the vertical tangent line — that segment's length IS tan θ", 0.4);
show(tanseg, 0.05); draw(tanseg, 0.9);
show(T, 0.05); draw(T, 0.35); show(labT, 0.3);
flash(tanseg, coral);
wait(0.7);

// 5 — GEOMETRIC MEAN
say(cap, "now forget the circle — Euclid: √a is the geometric mean of 1 and a", 0.4);
show(mean, 0.5);
par {
  show(G0, 0.3); show(G1, 0.3); show(G2, 0.3);
  show(lab0, 0.3); show(lab1, 0.3); show(labA2, 0.3);
  show(base, 0.05);
}
draw(base, 0.6);
wait(0.3);

say(cap, "semicircle on diameter 1 + tan θ — then erect a perpendicular at 1", 0.4);
show(semi, 0.05); draw(semi, 1.2);
show(alt, 0.05); draw(alt, 0.9);
show(H, 0.3); show(labH, 0.3);
flash(alt, violet);
wait(0.5);

say(cap, "by Thales + similar triangles, that height equals √(1 · tan θ)", 0.4);
show(feed, 0.05); draw(feed, 0.7);
pulse(H); pulse(T);
wait(0.8);

// 6 — THE IDENTITY
recolor(cap, violet);
say(cap, "so the altitude IS √(tan θ) — the symbol was a length all along", 0.4);
rewrite(law, `\sqrt{\tan\theta}=h`, 0.8, smooth);
wait(0.9);

// 7 — THE CURVE
recolor(cap, dim);
say(cap, "every such height, for every θ, paints the curve √(tan x)", 0.4);
show(ax, 0.5);
show(curve, 0.05); draw(curve, 2.2);
wait(0.4);
say(cap, "teal near zero, coral as tan θ climbs toward the asymptote at π/2", 0.4);
flash(curve, violet);
wait(0.8);

// 8 — POINT
recolor(cap, teal);
say(cap, "√(tan θ) is not a formula to memorize — it is a geometric construction", 0.4);
wait(1.6);

integral-sqrt-tanx

Integrate √(tan P): substitute P = t + π/4, read A(t) from the circle x²+y²=2 and H(t) from the hyperbola x²−y²=2, then dA−dH recovers the integrand. Outline-only angle marks — no filled discs hiding the construction.

// ============================================================================
//  integral-sqrt-tanx.manic — ∫ √(tan P) dP by PURE GEOMETRY
//  Companion to sqrt-tanx.manic. Storyboard: the handwritten circle+hyperbola
//  derivation (x²+y²=2 meets x²−y²=2; A(t)−H(t) recovers the integrand).
// ----------------------------------------------------------------------------
//  THE PROBLEM: √(tan P) is a length. What is its antiderivative?
//
//  THE GEOMETRY (one diagram, two curves of "radius" √2):
//   · circle   x² + y² = 2     →   A(t) = arcsin(√2 sin t)
//   · hyperbola x² − y² = 2    →   H(t) = arcosh(√2 cos t)
//   · substitution  P = t + π/4  (so t ∈ (0, π/4) ⇒ P ∈ (π/4, π/2))
//
//  THE TRUTH:
//      dA − dH  =  √2 · √(tan P) · dP
//  therefore
//      ∫ √(tan P) dP  =  (1/√2)(A(t) − H(t)) + C
//
//  Colours (expanded palette): teal = circle/A, coral = hyperbola/H,
//  violet = the integral, mint = the moving point, gold = the hook.
//
//    manic examples/integral-sqrt-tanx.manic
//    manic examples/integral-sqrt-tanx.manic --still 20
// ============================================================================

title("∫ √(tan P) dP — Circle Meets Hyperbola");
canvas("16:9");
template("blank");

// ---- stage ----
circle(well, (cx, 400), 360);
filled(well);
gradient(well, panel, void, radial);
opacity(well, 0.5);

// ============================================================================
//  THE DIAGRAM — circle x²+y²=2 and hyperbola x²−y²=2
//  Screen: origin at (ox,oy), scale s px per unit. Radius √2 ≈ 1.414.
// ============================================================================
let ox = 340;
let oy = 400;
let s = 130;                 // px per math-unit
let R = s*sqrt(2);           // circle radius = √2
// a friendly t inside (0, π/4): t = 0.40 rad ≈ 23°
let t = 0.40;
let P = t + pi/4;            // ≈ 1.185 rad ≈ 68°
// point C on the circle: (√2 cos t, √2 sin t)
let Cx = ox + s*sqrt(2)*cos(t);
let Cy = oy - s*sqrt(2)*sin(t);
// foot on the x-axis and the "hyperbola x" = √2 cosh u with cosh u = √2 cos t?
// From notes: X = √2 cos t = cosh H, so the hyperbola vertex is at x=√2.
// Point on right branch with x = √2 cos t... wait cosh H = √2 cos t, so
// x_hyp = cosh H = √2 cos t (in math units where a=1 for cosh param form
// of x²−y²=1). Our hyperbola is x²−y²=2 = (x/√2)² − (y/√2)², so
// parametric: x = √2 cosh u, y = √2 sinh u. And cosh H = √2 cos t? Notes say
// cosh(H) = X = √2 cos t — that would require cosh H ≤ √2, H = arcosh(√2 cos t).
// For the diagram, mark the circle point and the matching hyperbola x.

// axes
line(axX, (ox - R - 40, oy), (ox + R + 120, oy));
color(axX, dim); stroke(axX, 1.5); untraced(axX); hidden(axX);
line(axY, (ox, oy + R + 50), (ox, oy - R - 60));
color(axY, dim); stroke(axY, 1.5); untraced(axY); hidden(axY);

// circle x² + y² = 2 — OUTLINED only. `circle` defaults to filled; a solid
// disc hides axes and labels underneath (engine-test: never fill constructions).
circle(circ, (ox, oy), R);
outlined(circ); outline(circ, teal); stroke(circ, 3.5); untraced(circ); hidden(circ);

// hyperbola x² − y² = 2  →  a = b = √2  (in math units) → a_px = R
hyperbola(hyp, (ox, oy), R, R, 1.15);
color(hyp, coral); stroke(hyp, 3); untraced(hyp);
hidden(hyp.r); hidden(hyp.l);

// origin: thin open ring (tiny r + thick stroke reads as a filled blob)
circle(O, (ox, oy), 7);
outlined(O); color(O, fg); stroke(O, 1.5); hidden(O);

// contact point C: dashed open circle so circle + projections show through.
// Keep radius >> stroke so the interior stays empty (textbook marker).
circle(C, (Cx, Cy), 12);
outlined(C); color(C, mint); stroke(C, 2); dashed(C, 3.5, 2.8); untraced(C); hidden(C);

// radius toward C — a LINE, not an arrow: arrowheads are filled discs and
// hide the open marker at the contact point (engine-test visibility rule)
line(ray, (ox, oy), (Cx, Cy));
color(ray, mint); stroke(ray, 2.5); untraced(ray); hidden(ray);

// horizontal from C to y-axis? notes have Y = √2 sin t as height
line(ht, (ox, Cy), (Cx, Cy));
color(ht, violet); stroke(ht, 2); dashed(ht, 8, 6); untraced(ht); hidden(ht);
// vertical drop to x-axis
line(vt, (Cx, oy), (Cx, Cy));
color(vt, teal); stroke(vt, 2); dashed(vt, 8, 6); untraced(vt); hidden(vt);

// angle mark — textbook style: a thin ARC, never a filled disc (fills hide axes)
arc(wedge, (ox, oy), R*0.38, 0, -t*180/pi);
color(wedge, violet); stroke(wedge, 2.5); untraced(wedge); hidden(wedge);

// labels on the diagram
text(labO, (ox - 16, oy + 22), "O"); size(labO, 18); color(labO, dim); hidden(labO);
text(labC, (Cx + 22, Cy - 22), "C(t)"); size(labC, 20); color(labC, mint); hidden(labC);
text(labT, (ox + 42, oy - 22), "t"); size(labT, 22); color(labT, violet); hidden(labT);
text(labCirc, (ox - 20, oy - R - 24), "x² + y² = 2"); size(labCirc, 20); color(labCirc, teal); hidden(labCirc);
text(labHyp, (ox + R + 55, oy + 40), "x² − y² = 2"); size(labHyp, 20); color(labHyp, coral); hidden(labHyp);

// region hint: dashed circle (not a filled disc, not just a short arc)
circle(zone, (ox + R*0.42, oy - R*0.18), R*0.38);
outlined(zone); color(zone, indigo); stroke(zone, 2); dashed(zone, 7, 5);
untraced(zone); hidden(zone);

// ============================================================================
//  RIGHT — the algebraic spine, rewritten live
// ============================================================================
equation(eqP, (920, 150), `P=t+\tfrac{\pi}{4}`, 32);
color(eqP, gold); hidden(eqP);

equation(eqA, (920, 230), `A(t)=\sin^{-1}(\sqrt{2}\sin t)`, 28);
color(eqA, teal); hidden(eqA);

equation(eqH, (920, 300), `H(t)=\cosh^{-1}(\sqrt{2}\cos t)`, 28);
color(eqH, coral); hidden(eqH);

equation(eqD, (920, 390), `dA-dH=\sqrt{2}\,\sqrt{\tan P}\,dP`, 28);
color(eqD, violet); hidden(eqD);

equation(eqI, (920, 480), `\int\sqrt{\tan P}\,dP=\tfrac{1}{\sqrt{2}}(A-H)+C`, 30);
color(eqI, mint); hidden(eqI);

// final closed form (boxed punchline)
equation(eqF, (920, 580), `\tfrac{1}{\sqrt{2}}\Big(\sin^{-1}(\sqrt{2}\sin(P-\tfrac{\pi}{4}))-\cosh^{-1}(\sqrt{2}\cos(P-\tfrac{\pi}{4}))\Big)+C`, 22);
color(eqF, gold); hidden(eqF);

// ============================================================================
//  THE CURVE — √(tan x) on (π/4, ~1.4), then its antiderivative via ln-form of acosh
// ============================================================================
axes(ax, (920, 400), 300, 240);
hidden(ax);
// integrand (same spirit as the companion film)
plot(integrand, (920, 400), 90, 70, "sqrt(tan(x))", (0.85, 1.45));
stroke(integrand, 4); untraced(integrand); hidden(integrand);
gradient(integrand, teal, violet, coral, 270);

// antiderivative F(P) = (1/√2)(asin(√2 sin(P-π/4)) - acosh(√2 cos(P-π/4)))
// acosh(u) = ln(u + sqrt(u*u - 1))
plot(anti, (920, 400), 90, 55,
  "(asin(sqrt(2)*sin(x-pi/4)) - ln(sqrt(2)*cos(x-pi/4) + sqrt(2*cos(x-pi/4)*cos(x-pi/4) - 1)))/sqrt(2)",
  (0.85, 1.45));
stroke(anti, 4); untraced(anti); hidden(anti);
gradient(anti, mint, indigo, violet, 270);

// ============================================================================
//  TYPOGRAPHY
// ============================================================================
caption(q, "how do you integrate a square root of a tangent?", (cx, 52), 30, gold);
equation(hook, (cx, 105), `\int\sqrt{\tan P}\,dP`, 42);
color(hook, violet); hidden(hook);
text(cap, (cx, h - 34), ""); size(cap, 20); color(cap, dim); display(cap);

// ============================================================================
//  SCRIPT
// ============================================================================

// 1 — HOOK
say(cap, "√(tan P) is a length — we proved that. Now integrate it.", 0.4);
wordpop(q, 0.14);
wait(0.25);
show(hook, 0.5);
wait(0.6);

// 2 — THE SUBSTITUTION
say(cap, "one substitution opens the geometry: P = t + π/4", 0.4);
show(eqP, 0.5);
flash(eqP, gold);
wait(0.7);

// 3 — THE STAGE: two curves of the same "2"
say(cap, "draw two curves that share the constant 2 — a circle and a hyperbola", 0.4);
par { show(axX, 0.05); show(axY, 0.05); }
par { draw(axX, 0.4); draw(axY, 0.4); }
show(circ, 0.05); draw(circ, 1.0);
show(labCirc, 0.3); show(O, 0.3); show(labO, 0.3);
wait(0.3);
show(hyp.r, 0.05); show(hyp.l, 0.05);
draw(hyp.r, 1.0); draw(hyp.l, 1.0);
show(labHyp, 0.3);
wait(0.5);

say(cap, "circle: x² + y² = 2.   hyperbola: x² − y² = 2.   Same 2 — intentional.", 0.4);
pulse(circ); pulse(hyp.r);
wait(0.7);

// 4 — THE MOVING POINT
say(cap, "park a point C(t) = (√2 cos t, √2 sin t) on the circle — t < π/4", 0.4);
show(wedge, 0.05); draw(wedge, 0.45); show(labT, 0.3);
show(ray, 0.05); draw(ray, 0.7);
show(C, 0.05); draw(C, 0.4); show(labC, 0.3);
show(ht, 0.05); show(vt, 0.05);
draw(ht, 0.5); draw(vt, 0.5);
show(zone, 0.05); draw(zone, 0.6);
wait(0.6);

// 5 — A(t) FROM THE CIRCLE
say(cap, "from the y-coordinate: A(t) = arcsin(√2 sin t) — an angle on that circle", 0.4);
show(eqA, 0.5);
flash(eqA, teal);
wait(0.8);

// 6 — H(t) FROM THE HYPERBOLA
say(cap, "from the x-coordinate: H(t) = arcosh(√2 cos t) — a hyperbolic angle", 0.4);
show(eqH, 0.5);
flash(eqH, coral);
wait(0.8);

// 7 — THE DIFFERENTIAL IDENTITY
say(cap, "differentiate both — their difference IS the integrand", 0.4);
show(eqD, 0.6);
flash(eqD, violet);
wait(0.5);
say(cap, "dA − dH = √2 · √(tan P) · dP   — geometry differentiated", 0.4);
wait(1.0);

// 8 — INTEGRATE
recolor(cap, mint);
say(cap, "integrate both sides — the √2 cancels into the prefactor", 0.4);
show(eqI, 0.6);
pulse(eqI);
wait(0.9);

// 9 — CLOSED FORM
recolor(cap, violet);
say(cap, "substitute t = P − π/4 back — the antiderivative in closed form", 0.4);
show(eqF, 0.7);
flash(eqF, violet);
wait(1.0);

// 10 — SEE IT: integrand then antiderivative
recolor(cap, dim);
say(cap, "the integrand √(tan x) climbing toward π/2", 0.4);
par {
  fade(eqA, 0.35); fade(eqH, 0.35); fade(eqD, 0.35); fade(eqI, 0.35); fade(eqF, 0.35);
  fade(eqP, 0.35);
}
show(ax, 0.4);
show(integrand, 0.05); draw(integrand, 1.8);
wait(0.5);

say(cap, "and its antiderivative — (1/√2)(A − H) — the circle minus the hyperbola", 0.4);
show(anti, 0.05); draw(anti, 2.0);
flash(anti, mint);
wait(0.8);

// 11 — POINT
recolor(cap, teal);
say(cap, "a hard integral, solved because two curves of the same 2 were waiting", 0.4);
wait(1.8);

trajectory

A phase portrait: three paths flowing under a differential system, each spiralling into the sink at the origin.

title("Phase portrait: flowing into a spiral sink");
canvas("16:9");

text(hdr, (cx, 60), "dx/dt = -y - 0.2x,   dy/dt = x - 0.2y");
size(hdr, 26); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

// a reference frame centered on the sink
axes(ax, (cx, cy + 20), 620, 360, 1);
color(ax, dim); untraced(ax);

// three trajectories from different starts, each spiraling into the origin
trajectory(t1, "-y - 0.2*x", "x - 0.2*y", (3.2, 0), (cx, cy + 20), 110, 520);
color(t1, cyan); stroke(t1, 3); untraced(t1);

trajectory(t2, "-y - 0.2*x", "x - 0.2*y", (0, 3.4), (cx, cy + 20), 110, 520);
color(t2, magenta); stroke(t2, 3); untraced(t2);

trajectory(t3, "-y - 0.2*x", "x - 0.2*y", (-3.0, -2.4), (cx, cy + 20), 110, 520);
color(t3, gold); stroke(t3, 3); untraced(t3);

// ---- timeline ----
show(hdr, 0.5);
draw(ax, 0.8);
par {
  draw(t1, 3.5);
  draw(t2, 3.5);
  draw(t3, 3.5);
}

band

The area trapped between two curves, filled directly with band(top,bottom) while both boundary plots remain visible.

title("The area between two curves");
canvas("16:9");

let ox = cx - 460;
let oy = cy + 40;

text(hdr, (cx, 58), "The region trapped between two curves");
size(hdr, 26); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

axes(ax, (ox, oy), 900, 260, 1);
color(ax, dim); untraced(ax);

// two curves over the same stretch of x
plot(upper, (ox, oy), 140, 90, "0.4*x + 1.4", (0, 6.3));
color(upper, cyan); stroke(upper, 3); untraced(upper);

plot(lower, (ox, oy), 140, 90, "sin(x)", (0, 6.3));
color(lower, magenta); stroke(lower, 3); untraced(lower);

// the band between them
band(gap, upper, lower);
color(gap, lime); hidden(gap);

text(cap, (cx, h - 56), "band(top, bottom) fills the space between");
size(cap, 20); color(cap, dim); display(cap); hidden(cap);

// ---- timeline ----
show(hdr, 0.6);
draw(ax, 0.7);
par {
  draw(upper, 1.4);
  draw(lower, 1.4);
}
wait(0.3);
to(gap, opacity, 0.3, 0.6);   // fade in to translucent (so the curves read through)
show(cap, 0.4);

curve-features

Read a cubic by its geometry: maxima/minima where the slope is zero and an inflection where the curve changes its bend (extrema, inflections).

title("Reading a curve's shape — maxima, minima, inflection");
canvas("16:9");

let ox = cx - 540;   // math x=0 maps here (centres the domain 1..5 under cx)
let oy = cy;

text(hdr, (cx, 56), "Where the curve turns, and where it changes its bend");
size(hdr, 26); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

axes(ax, (ox, oy), 940, 240, 1);
color(ax, dim); untraced(ax);

// a cubic S-curve: one maximum, one minimum, one inflection
plot(f, (ox, oy), 180, 170, "0.4*((x-3)*(x-3)*(x-3) - 4*(x-3))", (1, 5));
color(f, cyan); stroke(f, 4); untraced(f);

// maxima & minima (slope = 0)
extrema(turn, f);
color(turn, gold);

// inflection (concavity flips, f'' = 0)
inflections(bend, f);
color(bend, magenta);

text(lg, (cx + 300, 150), "gold: max / min  (slope 0)");
size(lg, 18); color(lg, gold); display(lg); hidden(lg);
text(lm, (cx + 300, 186), "pink: inflection  (bend flips)");
size(lm, 18); color(lm, magenta); display(lm); hidden(lm);

// ---- timeline ----
show(hdr, 0.6);
draw(ax, 0.7);
draw(f, 1.6);
wait(0.3);
show(turn, 0.5);
show(lg, 0.4);
pulse(turn, 0.6);
wait(0.3);
show(bend, 0.5);
show(lm, 0.4);
pulse(bend, 0.6);

ftc

The Fundamental Theorem of Calculus: accumulate the area under a curve, differentiate that area function, and watch the original function return.

title("The Fundamental Theorem of Calculus");
canvas("16:9");

let ox = cx - 460;   // math x=0 maps here
let oy = cy + 20;

text(hdr, (cx, 52), "Differentiate the area — and the function comes back");
size(hdr, 26); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

axes(ax, (ox, oy), 900, 200, 1);
color(ax, dim); untraced(ax);

// f(x) = cos x
plot(f, (ox, oy), 140, 150, "cos(x)", (0, 6.3));
color(f, cyan); stroke(f, 4); untraced(f);

// F(x) = area under f from 0 to x  =  sin x
accum(bigF, f);
color(bigF, lime); stroke(bigF, 3); untraced(bigF);

// F'(x): differentiate the area function — it lands right back on f
deriv(dF, bigF);
color(dF, gold); stroke(dF, 3); untraced(dF);

// legend
text(lf, (cx + 300, 150), "f(x) = cos x");
size(lf, 20); color(lf, cyan); display(lf); hidden(lf);
text(lF, (cx + 300, 190), "F(x) = area so far");
size(lF, 20); color(lF, lime); display(lF); hidden(lF);
text(ld, (cx + 300, 230), "F'(x) = f(x)");
size(ld, 20); color(ld, gold); bold(ld); display(ld); hidden(ld);

text(cap, (cx, h - 52), "the slope of the area-so-far IS the original curve");
size(cap, 20); color(cap, dim); display(cap); hidden(cap);

// ================= timeline =================
show(hdr, 0.6);
draw(ax, 0.7);

// 1. the function
draw(f, 1.3);
show(lf, 0.4);
wait(0.3);

// 2. its accumulated area, as a new curve (this is sin x)
draw(bigF, 1.6);
show(lF, 0.4);
wait(0.4);

// 3. differentiate that area function — it traces back onto f
draw(dF, 1.6);
show(ld, 0.4);
flash(dF, gold);
show(cap, 0.5);

limit

A removable discontinuity visualized as an approaching point, open circle and live finite limit at x→0.

title("A limit — the value a curve heads toward");
canvas("16:9");

let ox = cx - 120;
let oy = cy;

text(hdr, (cx, 54), "sin(x) / x is undefined at 0 — but it heads straight for 1");
size(hdr, 24); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

axes(ax, (ox, oy), 620, 300, 1);
color(ax, dim); untraced(ax);

// sin(x)/x — a removable hole at x = 0, where the limit is 1
plot(f, (ox, oy), 150, 220, "sin(x)/x", (-6.2, 6.2));
color(f, cyan); stroke(f, 4); untraced(f);

// the limit at x -> 0: open circle at (0, 1), guides, value, and an approaching dot
limit(lim, f, 0);
color(lim, gold);

text(cap, (cx, h - 54), "slide the point in — f(x) closes on the open circle");
size(cap, 20); color(cap, dim); display(cap); hidden(cap);

// ---- timeline ----
show(hdr, 0.6);
draw(ax, 0.7);
draw(f, 1.6);
wait(0.3);
show(lim, 0.5);
show(cap, 0.4);
wait(0.3);
// walk the point toward x = 0 from the left — it approaches the open circle
to(lim, x, 0, 3.5);

limit-infinity

A rational function settling onto its horizontal asymptote, with limit(...,inf) detecting and marking the value at infinity.

title("A limit at infinity — limit(id, curve, inf)");
canvas("16:9");

let ox = 90;          // x = 0 near the left
let oy = cy + 250;    // y = 0 baseline

text(hdr, (cx, 52), "(5x^3 - 2x + 7) / (x^3 + 4x^2 + 3)  ->  5  as x -> infinity");
size(hdr, 24); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

text(sub, (cx, 92), "same degree top and bottom: the ratio of leading coefficients, 5/1");
size(sub, 17); color(sub, dim); display(sub); hidden(sub);

// the x-axis (y = 0)
line(xaxis, (ox, oy), (ox + 1130, oy));
color(xaxis, dim); untraced(xaxis);

// the rational function, climbing toward its asymptote
plot(f, (ox, oy), 9, 88, "(5*x*x*x - 2*x + 7)/(x*x*x + 4*x*x + 3)", (0.5, 125));
color(f, cyan); stroke(f, 4); untraced(f);

// the limit at infinity: auto-detects the horizontal asymptote y = 5
limit(lim, f, inf);
color(lim, gold); hidden(lim);

// ---- timeline ----
show(hdr, 0.6);
show(sub, 0.4);
draw(xaxis, 0.5);
draw(f, 2.4);
show(lim, 0.7);

taylor

Taylor polynomials of increasing degree closing in on sin(x), one additional approximation at a time.

title("Taylor series — polynomials closing in on a curve");
canvas("16:9");

let ox = cx;         // x=0 at centre
let oy = cy + 10;

text(hdr, (cx, 52), "Add one more term, and the polynomial hugs more of the curve");
size(hdr, 24); color(hdr, cyan); bold(hdr); display(hdr); hidden(hdr);

axes(ax, (ox, oy), 640, 260, 1);
color(ax, dim); untraced(ax);

// the target function
plot(f, (ox, oy), 95, 120, "sin(x)", (-6.2, 6.2));
color(f, cyan); stroke(f, 5); untraced(f);

// Taylor polynomials about x = 0, growing in degree
taylor(p1, f, 0, 1);
color(p1, dim); stroke(p1, 3); untraced(p1);
taylor(p3, f, 0, 3);
color(p3, gold); stroke(p3, 3); untraced(p3);
taylor(p5, f, 0, 5);
color(p5, magenta); stroke(p5, 3); untraced(p5);
taylor(p7, f, 0, 7);
color(p7, lime); stroke(p7, 3); untraced(p7);

text(l1, (cx + 300, 150), "n = 1   (a line)");
size(l1, 18); color(l1, dim); display(l1); hidden(l1);
text(l3, (cx + 300, 186), "n = 3");
size(l3, 18); color(l3, gold); display(l3); hidden(l3);
text(l5, (cx + 300, 222), "n = 5");
size(l5, 18); color(l5, magenta); display(l5); hidden(l5);
text(l7, (cx + 300, 258), "n = 7");
size(l7, 18); color(l7, lime); display(l7); hidden(l7);

// ---- timeline ----
show(hdr, 0.6);
draw(ax, 0.7);
draw(f, 1.6);
wait(0.3);
draw(p1, 0.8);  show(l1, 0.3);  wait(0.3);
draw(p3, 0.9);  show(l3, 0.3);  wait(0.3);
draw(p5, 1.0);  show(l5, 0.3);  wait(0.3);
draw(p7, 1.1);  show(l7, 0.3);