Geometry (olympiad)
Every construction is live — the derived points recompute as the inputs move.
Each block is the whole file — copy it into x.manic and run manic x.manic (live) or --record out (video).
equilateral
Euclid I.1 — an equilateral triangle from two circles.
// Equilateral Triangle — Euclid, Elements Book I, Proposition 1. Given a segment
// AB: draw the circle centred at A through B and the circle centred at B through
// A; where they cross is the apex of an equilateral triangle. Every side then
// equals AB. It's a fully DYNAMIC construction — drag B at the end and the
// circles, the intersection, and the triangle all stay correct.
//
// New geo builtins: circle2 (circle by centre + a point on it) and circlecircle
// (the two intersection points of two circles).
//
// Note: each compass circle has radius |AB|, so keep A and B close enough that
// the circles fit the canvas (here |AB| ~ 200 px).
//
// manic examples/equilateral.manic
title("Equilateral Triangle");
canvas("16:9");
text(head, (cx, 96), "Euclid I.1 -- two circles give an equilateral triangle");
color(head, cyan); size(head, 24); hidden(head);
point(A, (540, 470), "A");
point(B, (740, 470), "B");
segment(ab, A, B); color(ab, fg); stroke(ab, 3); untraced(ab);
// the two compass circles (each of radius AB)
circle2(cA, A, B); color(cA, dim); stroke(cA, 1.5); untraced(cA);
circle2(cB, B, A); color(cB, dim); stroke(cB, 1.5); untraced(cB);
// where they meet: C0 (below AB) and C1 (above AB) — take the apex above
circlecircle(C, A, B, B, A);
hidden(C0); hidden(C1);
label(C1, "C", (16, -16)); color(C1.label, lime);
segment(ac, A, C1); color(ac, lime); stroke(ac, 3); untraced(ac);
segment(bc, B, C1); color(bc, lime); stroke(bc, 3); untraced(bc);
// --- construct it ---
show(head, 0.5);
show(A, 0.3); show(B, 0.3);
draw(ab, 0.6);
section("Two circles");
par { draw(cA, 0.9); draw(cB, 0.9); }
show(C1, 0.4);
section("The triangle");
par { draw(ac, 0.7); draw(bc, 0.7); }
par { pulse(ac); pulse(bc); pulse(ab); }
wait(0.6);
// --- drag a vertex: it stays equilateral (circles stay on-canvas) ---
section("Drag a vertex");
move(B, (700, 360), 1.6, smooth);
wait(0.3);
move(B, (660, 560), 1.6, smooth);
wait(0.3);
move(B, (740, 470), 1.2, smooth);
wait(1.0);
triangle
A triangle with its centres and cevians.
// Triangle Geometry — the geo kit (olympiad helpers à la olympiad.asy/cse5.asy).
// Points drive everything: circumcircle, incircle, centroid, circumcenter,
// angle mark, and the foot of an altitude are all *constructed* from A, B, C.
//
// manic examples/triangle.manic
// manic examples/triangle.manic --record out --fps 60
title("Triangle Geometry");
canvas(1280, 720);
text(head, (640, 118), "constructed from three points");
display(head); color(head, cyan); size(head, 32); hidden(head);
text(cap, (640, 668), ""); color(cap, dim); size(cap, 22);
// the three free points
point(A, (380, 560), "A");
point(B, (900, 560), "B");
point(C, (640, 190), "C");
hidden(A); hidden(B); hidden(C);
// sides
segment(ab, A, B); segment(bc, B, C); segment(ca, C, A);
untraced(ab); untraced(bc); untraced(ca);
// constructions
circumcircle(cc, A, B, C); untraced(cc);
circumcenter(O, A, B, C); hidden(O);
incircle(ic, A, B, C); untraced(ic);
centroid(G, A, B, C); hidden(G);
anglemark(angC, A, C, B); untraced(angC);
foot(F, C, A, B); hidden(F);
segment(alt, C, F); untraced(alt);
// --- script ---
show(head, 0.5);
say(cap, "three points make a triangle");
par { show(A); show(B); show(C); }
par { draw(ab, 0.5); draw(bc, 0.5); draw(ca, 0.5); }
draw(angC, 0.4);
wait(0.5);
section("Circumcircle");
say(cap, "the unique circle through all three vertices");
par { show(O); draw(cc, 0.9); }
wait(0.6);
section("Incircle & Centroid");
say(cap, "incircle (tangent to all sides) and centroid");
par { draw(ic, 0.9); show(G); }
wait(0.6);
section("Altitude");
say(cap, "drop a perpendicular from C to AB — its foot F");
par { show(F); draw(alt, 0.6); }
flash(F, magenta);
wait(1.0);
// the payoff: constructions are dynamic — drag a vertex and everything
// (circumcircle, incircle, centroid, foot, angle mark, sides) recomputes.
section("Drag a vertex");
say(cap, "move C — every construction follows");
move(C, (430, 230), 1.2, smooth);
move(C, (850, 210), 1.2, smooth);
move(C, (640, 190), 1.0, smooth);
say(cap, "and drag A");
move(A, (300, 520), 0.9, smooth);
move(A, (380, 560), 0.8, smooth);
wait(1.2);
incircle_tangents
The incircle and its tangent points.
// The Incircle & Contact Triangle — the incircle touches each side at the foot
// of the perpendicular from the incenter, and each radius meets the side at a
// right angle. The three touch points form the contact triangle.
//
// manic examples/incircle_tangents.manic
// manic examples/incircle_tangents.manic --record out --fps 60
title("The Incircle");
canvas(1280, 720);
text(head, (640, 120), "tangent to all three sides");
display(head); color(head, cyan); size(head, 28); hidden(head);
text(cap, (640, 668), ""); color(cap, dim); size(cap, 22);
point(A, (300, 560), "A");
point(B, (1000, 560), "B");
point(C, (640, 160), "C");
hidden(A); hidden(B); hidden(C);
segment(ab, A, B); segment(bc, B, C); segment(ca, C, A);
untraced(ab); untraced(bc); untraced(ca);
incenter(I, A, B, C); color(I, cyan); label(I, "I", (16, -14)); hidden(I);
incircle(ic, A, B, C); untraced(ic);
// touch points = feet of perpendiculars from I to each side
foot(tBC, I, B, C); foot(tCA, I, C, A); foot(tAB, I, A, B);
color(tBC, magenta); color(tCA, magenta); color(tAB, magenta);
hidden(tBC); hidden(tCA); hidden(tAB);
// radii to the touch points, with right-angle marks
segment(rBC, I, tBC); segment(rCA, I, tCA); segment(rAB, I, tAB);
color(rBC, lime); color(rCA, lime); color(rAB, lime);
untraced(rBC); untraced(rCA); untraced(rAB);
rightangle(qBC, I, tBC, B); rightangle(qCA, I, tCA, C); rightangle(qAB, I, tAB, A);
untraced(qBC); untraced(qCA); untraced(qAB);
// the contact triangle
segment(k1, tBC, tCA); segment(k2, tCA, tAB); segment(k3, tAB, tBC);
untraced(k1); untraced(k2); untraced(k3);
show(head, 0.5);
say(cap, "a triangle and its incentre I");
par { show(A); show(B); show(C); }
par { draw(ab, 0.5); draw(bc, 0.5); draw(ca, 0.5); }
show(I, 0.3);
wait(0.3);
section("Inscribed circle");
say(cap, "the incircle touches each side once");
draw(ic, 1.0);
stagger(0.15) { show(tBC); show(tCA); show(tAB); }
wait(0.3);
section("Radii ⟂ sides");
say(cap, "each radius meets its side at a right angle");
par { draw(rBC, 0.5); draw(rCA, 0.5); draw(rAB, 0.5); }
par { draw(qBC, 0.4); draw(qCA, 0.4); draw(qAB, 0.4); }
wait(0.4);
section("Contact triangle");
say(cap, "the three touch points form the contact triangle");
par { draw(k1, 0.5); draw(k2, 0.5); draw(k3, 0.5); }
wait(1.2);
tangents
Tangent lines from a point to a circle.
// Tangent Lines — the two tangents from an external point P to a circle, and
// the theorem that each tangent is perpendicular to the radius at its touch
// point. Everything is a DYNAMIC construction: move P and the touch points,
// tangent lines, radii, and right-angle marks all recompute live.
//
// New geo builtins: circle2 (circle by centre + a point on it), tangent
// (touch points from an external point), plus segment/rightangle tracking them.
//
// manic examples/tangents.manic
title("Tangent Lines");
canvas("16:9");
text(head, (cx, 96), "two tangents from a point -- each meets the radius at 90 degrees");
color(head, cyan); size(head, 24); hidden(head);
point(O, (520, 400), "O");
point(A, (520, 200)); // a point on the circle -> radius 200
point(P, (940, 380), "P");
hidden(A); // A just defines the radius; don't show it
circle2(circ, O, A); color(circ, dim); stroke(circ, 2); untraced(circ);
// the two touch points t0 / t1, and the tangent lines to them
tangent(t, P, O, A);
segment(l0, P, t0); color(l0, cyan); stroke(l0, 3); untraced(l0);
segment(l1, P, t1); color(l1, cyan); stroke(l1, 3); untraced(l1);
// radius to each touch point + the right-angle marks
segment(r0, O, t0); color(r0, dim); untraced(r0);
segment(r1, O, t1); color(r1, dim); untraced(r1);
rightangle(ra0, O, t0, P); color(ra0, lime); hidden(ra0);
rightangle(ra1, O, t1, P); color(ra1, lime); hidden(ra1);
// --- reveal ---
show(head, 0.5);
draw(circ, 0.8);
show(O, 0.3); show(P, 0.3);
section("The tangents");
par { draw(l0, 0.7); draw(l1, 0.7); }
show(t0, 0.3); show(t1, 0.3);
section("Radius meets tangent");
par { draw(r0, 0.5); draw(r1, 0.5); }
par { show(ra0, 0.4); show(ra1, 0.4); }
wait(0.6);
// --- prove it's dynamic: move P, everything tracks ---
section("Move the point");
move(P, (820, 230), 1.6, smooth);
wait(0.4);
move(P, (980, 470), 1.6, smooth);
wait(0.8);
move(P, (940, 380), 1.2, smooth);
wait(1.0);
orthocenter
The orthocentre from the three altitudes.
// Altitudes & Orthocenter — the three altitudes of a triangle meet at one
// point, the orthocenter H. Each altitude drops perpendicular to a side.
// Dynamic: drag a vertex and the altitudes still concur.
//
// manic examples/orthocenter.manic
// manic examples/orthocenter.manic --record out --fps 60
title("Altitudes & Orthocenter");
canvas(1280, 720);
text(head, (640, 120), "the three altitudes concur");
display(head); color(head, cyan); size(head, 28); hidden(head);
text(cap, (640, 668), ""); color(cap, dim); size(cap, 22);
point(A, (330, 540), "A");
point(B, (980, 560), "B");
point(C, (700, 190), "C");
hidden(A); hidden(B); hidden(C);
segment(ab, A, B); segment(bc, B, C); segment(ca, C, A);
untraced(ab); untraced(bc); untraced(ca);
// feet of the three altitudes
foot(fA, A, B, C); foot(fB, B, C, A); foot(fC, C, A, B);
color(fA, magenta); color(fB, magenta); color(fC, magenta);
hidden(fA); hidden(fB); hidden(fC);
// the altitudes themselves
segment(hA, A, fA); segment(hB, B, fB); segment(hC, C, fC);
color(hA, lime); color(hB, lime); color(hC, lime);
untraced(hA); untraced(hB); untraced(hC);
rightangle(qA, A, fA, B); rightangle(qB, B, fB, C); rightangle(qC, C, fC, A);
untraced(qA); untraced(qB); untraced(qC);
orthocenter(H, A, B, C); color(H, cyan); label(H, "H", (16, -14)); hidden(H);
show(head, 0.5);
say(cap, "a triangle");
par { show(A); show(B); show(C); }
par { draw(ab, 0.5); draw(bc, 0.5); draw(ca, 0.5); }
wait(0.3);
section("Drop the altitudes");
say(cap, "from each vertex, perpendicular to the opposite side");
seq {
par { draw(hA, 0.5); draw(qA, 0.4); show(fA); }
par { draw(hB, 0.5); draw(qB, 0.4); show(fB); }
par { draw(hC, 0.5); draw(qC, 0.4); show(fC); }
}
wait(0.3);
section("Orthocenter");
say(cap, "all three meet at the orthocenter H");
show(H, 0.4);
flash(H, magenta);
wait(0.6);
section("Drag a vertex");
say(cap, "move C — the altitudes still concur");
move(C, (520, 230), 1.2, smooth);
move(C, (820, 250), 1.2, smooth);
move(C, (700, 190), 1.0, smooth);
wait(1.0);
euler_line
The Euler line through centroid, circumcentre, orthocentre.
// The Euler Line — in any triangle, the circumcenter O, centroid G, and
// orthocenter H are collinear (and OG : GH = 1 : 2). Constructions are
// dynamic: drag C and the three centres stay on one line.
//
// manic examples/euler_line.manic
// manic examples/euler_line.manic --record out --fps 60
title("The Euler Line");
canvas(1280, 720);
text(head, (640, 120), "circumcenter, centroid, orthocenter — collinear");
display(head); color(head, cyan); size(head, 26); hidden(head);
text(cap, (640, 668), ""); color(cap, dim); size(cap, 22);
point(A, (300, 560), "A");
point(B, (1000, 540), "B");
point(C, (560, 190), "C");
hidden(A); hidden(B); hidden(C);
segment(ab, A, B); segment(bc, B, C); segment(ca, C, A);
untraced(ab); untraced(bc); untraced(ca);
circumcircle(cc, A, B, C); untraced(cc);
circumcenter(O, A, B, C); color(O, magenta); label(O, "O", (18, -14)); hidden(O);
centroid(G, A, B, C); color(G, lime); label(G, "G", (18, -14)); hidden(G);
orthocenter(H, A, B, C); color(H, cyan); label(H, "H", (-30, -14)); hidden(H);
segment(euler, O, H); color(euler, magenta); stroke(euler, 3); untraced(euler);
show(head, 0.5);
say(cap, "any triangle, with its circumcircle");
par { show(A); show(B); show(C); }
par { draw(ab, 0.5); draw(bc, 0.5); draw(ca, 0.5); }
draw(cc, 0.9);
wait(0.4);
section("Three centres");
say(cap, "circumcenter O, centroid G, orthocenter H");
stagger(0.3) { show(O); show(G); show(H); }
wait(0.4);
section("The Euler line");
say(cap, "they always lie on a single line");
draw(euler, 0.9);
wait(0.6);
section("Drag a vertex");
say(cap, "move C — O, G, H stay collinear");
move(C, (770, 220), 1.2, smooth);
move(C, (420, 250), 1.2, smooth);
move(C, (560, 190), 1.0, smooth);
wait(1.0);
nine_point
The nine-point circle.
// The Nine-Point Circle — one circle through the three side-midpoints AND the
// three altitude feet. (It's the circumcircle of the medial triangle.)
// Dynamic: drag C and the circle still catches all six points.
//
// manic examples/nine_point.manic
// manic examples/nine_point.manic --record out --fps 60
title("The Nine-Point Circle");
canvas(1280, 720);
text(head, (640, 120), "three midpoints + three feet, one circle");
display(head); color(head, cyan); size(head, 26); hidden(head);
text(cap, (640, 668), ""); color(cap, dim); size(cap, 22);
point(A, (320, 560), "A");
point(B, (1000, 560), "B");
point(C, (620, 175), "C");
hidden(A); hidden(B); hidden(C);
segment(ab, A, B); segment(bc, B, C); segment(ca, C, A);
untraced(ab); untraced(bc); untraced(ca);
// side midpoints
midpoint(mAB, A, B); midpoint(mBC, B, C); midpoint(mCA, C, A);
color(mAB, lime); color(mBC, lime); color(mCA, lime);
hidden(mAB); hidden(mBC); hidden(mCA);
// altitude feet
foot(fA, A, B, C); foot(fB, B, C, A); foot(fC, C, A, B);
color(fA, magenta); color(fB, magenta); color(fC, magenta);
hidden(fA); hidden(fB); hidden(fC);
// the nine-point circle = circumcircle of the medial triangle
circumcircle(npc, mAB, mBC, mCA); outline(npc, cyan); untraced(npc);
show(head, 0.5);
say(cap, "start with a triangle");
par { show(A); show(B); show(C); }
par { draw(ab, 0.5); draw(bc, 0.5); draw(ca, 0.5); }
wait(0.3);
section("Six points");
say(cap, "the three side-midpoints (lime)");
stagger(0.2) { show(mAB); show(mBC); show(mCA); }
say(cap, "and the three altitude feet (magenta)");
stagger(0.2) { show(fA); show(fB); show(fC); }
wait(0.4);
section("One circle");
say(cap, "a single circle passes through all six");
draw(npc, 1.0);
wait(0.6);
section("Drag a vertex");
say(cap, "move C — the circle still catches all six");
move(C, (820, 220), 1.3, smooth);
move(C, (440, 240), 1.3, smooth);
move(C, (620, 175), 1.0, smooth);
wait(1.0);
conics
Ellipse, parabola, hyperbola.
// The Conic Sections — the three curves you get by slicing a cone: the ellipse,
// the parabola, and the hyperbola. Each is a geo-kit primitive; they reveal one
// at a time with the defining property.
//
// manic examples/conics.manic
// manic examples/conics.manic --template blueprint
title("The Conic Sections");
canvas("16:9");
text(head, (cx, 80), "three curves from slicing a cone");
display(head); color(head, cyan); size(head, 26); hidden(head);
text(cap, (cx, 662), ""); color(cap, dim); size(cap, 23);
// --- ellipse (left) ---
ellipse(el, (300, 400), 165, 100); color(el, cyan); stroke(el, 3); untraced(el);
text(ell, (300, 250), "ellipse"); color(ell, cyan); size(ell, 26); hidden(ell);
// --- parabola (centre) ---
parabola(pa, (660, 540), 150, 270); color(pa, lime); stroke(pa, 3); untraced(pa);
text(pal, (660, 235), "parabola"); color(pal, lime); size(pal, 26); hidden(pal);
// --- hyperbola (right) — two branches, tagged `hy` ---
hyperbola(hy, (1010, 400), 55, 120); color(hy, magenta); stroke(hy, 3); untraced(hy);
text(hyl, (1010, 205), "hyperbola"); color(hyl, magenta); size(hyl, 26); hidden(hyl);
// --- reveal ---
show(head, 0.5);
section("Ellipse");
say(cap, "ellipse -- the sum of distances to two foci stays constant");
draw(el, 0.9);
show(ell, 0.4);
wait(0.5);
section("Parabola");
say(cap, "parabola -- every point is equidistant from a focus and a line");
draw(pa, 0.9);
show(pal, 0.4);
wait(0.5);
section("Hyperbola");
say(cap, "hyperbola -- two branches; the difference of distances stays constant");
draw(hy, 0.9);
show(hyl, 0.4);
wait(1.4);