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

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);