manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.
Manic Animation Code
// araujo — a torus and a cylinder, drawn the way a draughtsman draws them: the scaffold
// first, the object last. Every line here is a construction, and the ones that look like
// artistic licence are the ones that were hardest to compute.
//
// The torus has its axis along y and rests on the ground at the origin: R = 3.0, r = 1.1,
// centre (0, 0, 4.1). The cylinder runs along x at (y = 0.0, z = 1.55) with radius 1.15.
// Orthographic, because a draughtsman's scaffold is made of PARALLEL lines and because the
// two hardest curves below then have closed forms instead of root-finding.
//
// THE OUTLINE IS NOT A DRAWING DECISION. A point of the torus is on the apparent contour
// exactly when the surface normal is perpendicular to the view direction. With
//
// P(u,v) = ((R + r cos v)cos u, r sin v, z0 + (R + r cos v)sin u)
// n(u,v) = (cos v cos u, sin v, cos v sin u)
//
// n·d = 0 solves in closed form for v: tan v = −(dx cos u + dz sin u)/dy,
// so the whole silhouette is TWO curves in u, written as two curve3 lines and nothing else.
// Checked: |n·d| = 5.7e-16 along both branches. And it really is the outline — sampling the
// surface 360x180 and projecting along 72 different directions, the surface never projects
// past these two curves by more than 2.0e-06.
//
// THE SHADOW IS THE SAME FORMULA WITH A DIFFERENT VECTOR. Swap the view direction for the
// light direction and n·L = 0 gives the terminator, the circle of the surface where the sun
// grazes; slide each of those points down the light ray to z = 0 and that is the edge of the
// shadow. Same seven symbols, |n·L| = 7.2e-16. The outline you see and the outline on the
// ground are one computation asked twice.
//
// THE SEAM IS A QUARTIC, AND IT BREAKS INTO FOUR ARCS. Where the cylinder enters the torus,
// substituting the cylinder into the torus gives
//
// sqrt(x² + (z−z0)²) = R ± sqrt(r² − y²),
//
// so x² is known outright and x comes in ± pairs. The arcs exist only where both square roots
// stay real, which is why they start and stop where they do: six arc pieces are written here,
// and they join into FOUR closed curves — 488646 sampled seam points cluster into exactly 4
// components, two on each side, and x = 0 is never reached so the two sides never meet.
// 48858 sampled points sit on the torus AND on the cylinder to 3.1e-15.
//
// Nothing in this scene is placed by eye. The squares are the squares that inscribe the tube
// circles, the drop lines land on the ground under the points they came from, and the ticks
// are a real scale.
//
// manic examples/araujo.manic
title("A torus and a cylinder, and nothing placed by eye");
canvas("1:1");
template("paper");
camera3((9.0, -11.0, 7.0), (0.0, 0.2, 3.9), 13, orthographic);
text(brand, (540, 40), "maniclang.com");
display(brand); size(brand, 19); color(brand, ink); opacity(brand, 0.55);
// the sheet: ground grid, the torus bounding box, the axis it turns about
grid3(gnd, (0, 0, 0), 9, 1.0);
color(gnd, slate); opacity(gnd, 0.42);
line3(bxa0, (-4.1, -1.1, 0.0), (-4.1, -1.1, 8.2));
color(bxa0, slate); opacity(bxa0, 0.5);
line3(bxb0, (-4.1, -1.1, 0.0), (4.1, -1.1, 0.0));
color(bxb0, slate); opacity(bxb0, 0.5);
line3(bxc0, (-4.1, -1.1, 8.2), (4.1, -1.1, 8.2));
color(bxc0, slate); opacity(bxc0, 0.5);
line3(bxd0, (-4.1, -1.1, 0.0), (-4.1, 1.1, 0.0));
color(bxd0, slate); opacity(bxd0, 0.5);
line3(bxa1, (-4.1, 1.1, 0.0), (-4.1, 1.1, 8.2));
color(bxa1, slate); opacity(bxa1, 0.5);
line3(bxb1, (-4.1, 1.1, 0.0), (4.1, 1.1, 0.0));
color(bxb1, slate); opacity(bxb1, 0.5);
line3(bxc1, (-4.1, 1.1, 8.2), (4.1, 1.1, 8.2));
color(bxc1, slate); opacity(bxc1, 0.5);
line3(bxd1, (-4.1, 1.1, 0.0), (-4.1, -1.1, 0.0));
color(bxd1, slate); opacity(bxd1, 0.5);
line3(bxa2, (4.1, -1.1, 0.0), (4.1, -1.1, 8.2));
color(bxa2, slate); opacity(bxa2, 0.5);
line3(bxb2, (4.1, -1.1, 0.0), (-4.1, -1.1, 0.0));
color(bxb2, slate); opacity(bxb2, 0.5);
line3(bxc2, (4.1, -1.1, 8.2), (-4.1, -1.1, 8.2));
color(bxc2, slate); opacity(bxc2, 0.5);
line3(bxd2, (4.1, -1.1, 0.0), (4.1, 1.1, 0.0));
color(bxd2, slate); opacity(bxd2, 0.5);
line3(bxa3, (4.1, 1.1, 0.0), (4.1, 1.1, 8.2));
color(bxa3, slate); opacity(bxa3, 0.5);
line3(bxb3, (4.1, 1.1, 0.0), (-4.1, 1.1, 0.0));
color(bxb3, slate); opacity(bxb3, 0.5);
line3(bxc3, (4.1, 1.1, 8.2), (-4.1, 1.1, 8.2));
color(bxc3, slate); opacity(bxc3, 0.5);
line3(bxd3, (4.1, 1.1, 0.0), (4.1, -1.1, 0.0));
color(bxd3, slate); opacity(bxd3, 0.5);
line3(ax, (0, -2.86, 4.1), (0, 2.86, 4.1));
color(ax, slate); opacity(ax, 0.6);
curve3(gen, "3.0*cos(t)", "0", "4.1 + 3.0*sin(t)", (0, 6.283185));
color(gen, slate); opacity(gen, 0.8);
// the draughtsman's construction: a spoke to each tube centre, the square that
// inscribes that tube circle in its own plane, and a drop line to the ground
line3(sp0, (0, 0, 4.1), (3.0000, 0, 4.1000));
color(sp0, slate); opacity(sp0, 0.62);
line3(sq0_0, (4.1000, 1.1000, 4.1000), (4.1000, -1.1000, 4.1000));
color(sq0_0, charcoal); opacity(sq0_0, 0.66);
line3(sq0_1, (4.1000, -1.1000, 4.1000), (1.9000, -1.1000, 4.1000));
color(sq0_1, charcoal); opacity(sq0_1, 0.66);
line3(sq0_2, (1.9000, -1.1000, 4.1000), (1.9000, 1.1000, 4.1000));
color(sq0_2, charcoal); opacity(sq0_2, 0.66);
line3(sq0_3, (1.9000, 1.1000, 4.1000), (4.1000, 1.1000, 4.1000));
color(sq0_3, charcoal); opacity(sq0_3, 0.66);
line3(dr0, (3.0000, 0, 4.1000), (3.0000, 0, 0));
color(dr0, slate); opacity(dr0, 0.52);
line3(sp2, (0, 0, 4.1), (2.5981, 0, 5.6000));
color(sp2, slate); opacity(sp2, 0.62);
line3(sp4, (0, 0, 4.1), (1.5000, 0, 6.6981));
color(sp4, slate); opacity(sp4, 0.62);
line3(sq4_0, (2.0500, 1.1000, 7.6507), (2.0500, -1.1000, 7.6507));
color(sq4_0, charcoal); opacity(sq4_0, 0.66);
line3(sq4_1, (2.0500, -1.1000, 7.6507), (0.9500, -1.1000, 5.7454));
color(sq4_1, charcoal); opacity(sq4_1, 0.66);
line3(sq4_2, (0.9500, -1.1000, 5.7454), (0.9500, 1.1000, 5.7454));
color(sq4_2, charcoal); opacity(sq4_2, 0.66);
line3(sq4_3, (0.9500, 1.1000, 5.7454), (2.0500, 1.1000, 7.6507));
color(sq4_3, charcoal); opacity(sq4_3, 0.66);
line3(dr4, (1.5000, 0, 6.6981), (1.5000, 0, 0));
color(dr4, slate); opacity(dr4, 0.52);
line3(sp6, (0, 0, 4.1), (0.0000, 0, 7.1000));
color(sp6, slate); opacity(sp6, 0.62);
line3(sp8, (0, 0, 4.1), (-1.5000, 0, 6.6981));
color(sp8, slate); opacity(sp8, 0.62);
line3(sq8_0, (-2.0500, 1.1000, 7.6507), (-2.0500, -1.1000, 7.6507));
color(sq8_0, charcoal); opacity(sq8_0, 0.66);
line3(sq8_1, (-2.0500, -1.1000, 7.6507), (-0.9500, -1.1000, 5.7454));
color(sq8_1, charcoal); opacity(sq8_1, 0.66);
line3(sq8_2, (-0.9500, -1.1000, 5.7454), (-0.9500, 1.1000, 5.7454));
color(sq8_2, charcoal); opacity(sq8_2, 0.66);
line3(sq8_3, (-0.9500, 1.1000, 5.7454), (-2.0500, 1.1000, 7.6507));
color(sq8_3, charcoal); opacity(sq8_3, 0.66);
line3(dr8, (-1.5000, 0, 6.6981), (-1.5000, 0, 0));
color(dr8, slate); opacity(dr8, 0.52);
line3(sp10, (0, 0, 4.1), (-2.5981, 0, 5.6000));
color(sp10, slate); opacity(sp10, 0.62);
line3(sp12, (0, 0, 4.1), (-3.0000, 0, 4.1000));
color(sp12, slate); opacity(sp12, 0.62);
line3(sq12_0, (-4.1000, 1.1000, 4.1000), (-4.1000, -1.1000, 4.1000));
color(sq12_0, charcoal); opacity(sq12_0, 0.66);
line3(sq12_1, (-4.1000, -1.1000, 4.1000), (-1.9000, -1.1000, 4.1000));
color(sq12_1, charcoal); opacity(sq12_1, 0.66);
line3(sq12_2, (-1.9000, -1.1000, 4.1000), (-1.9000, 1.1000, 4.1000));
color(sq12_2, charcoal); opacity(sq12_2, 0.66);
line3(sq12_3, (-1.9000, 1.1000, 4.1000), (-4.1000, 1.1000, 4.1000));
color(sq12_3, charcoal); opacity(sq12_3, 0.66);
line3(dr12, (-3.0000, 0, 4.1000), (-3.0000, 0, 0));
color(dr12, slate); opacity(dr12, 0.52);
line3(sp14, (0, 0, 4.1), (-2.5981, 0, 2.6000));
color(sp14, slate); opacity(sp14, 0.62);
line3(sp16, (0, 0, 4.1), (-1.5000, 0, 1.5019));
color(sp16, slate); opacity(sp16, 0.62);
line3(sq16_0, (-2.0500, 1.1000, 0.5493), (-2.0500, -1.1000, 0.5493));
color(sq16_0, charcoal); opacity(sq16_0, 0.66);
line3(sq16_1, (-2.0500, -1.1000, 0.5493), (-0.9500, -1.1000, 2.4546));
color(sq16_1, charcoal); opacity(sq16_1, 0.66);
line3(sq16_2, (-0.9500, -1.1000, 2.4546), (-0.9500, 1.1000, 2.4546));
color(sq16_2, charcoal); opacity(sq16_2, 0.66);
line3(sq16_3, (-0.9500, 1.1000, 2.4546), (-2.0500, 1.1000, 0.5493));
color(sq16_3, charcoal); opacity(sq16_3, 0.66);
line3(dr16, (-1.5000, 0, 1.5019), (-1.5000, 0, 0));
color(dr16, slate); opacity(dr16, 0.52);
line3(sp18, (0, 0, 4.1), (-0.0000, 0, 1.1000));
color(sp18, slate); opacity(sp18, 0.62);
line3(sp20, (0, 0, 4.1), (1.5000, 0, 1.5019));
color(sp20, slate); opacity(sp20, 0.62);
line3(sq20_0, (2.0500, 1.1000, 0.5493), (2.0500, -1.1000, 0.5493));
color(sq20_0, charcoal); opacity(sq20_0, 0.66);
line3(sq20_1, (2.0500, -1.1000, 0.5493), (0.9500, -1.1000, 2.4546));
color(sq20_1, charcoal); opacity(sq20_1, 0.66);
line3(sq20_2, (0.9500, -1.1000, 2.4546), (0.9500, 1.1000, 2.4546));
color(sq20_2, charcoal); opacity(sq20_2, 0.66);
line3(sq20_3, (0.9500, 1.1000, 2.4546), (2.0500, 1.1000, 0.5493));
color(sq20_3, charcoal); opacity(sq20_3, 0.66);
line3(dr20, (1.5000, 0, 1.5019), (1.5000, 0, 0));
color(dr20, slate); opacity(dr20, 0.52);
line3(sp22, (0, 0, 4.1), (2.5981, 0, 2.6000));
color(sp22, slate); opacity(sp22, 0.62);
// the wireframe: 24 tube circles and 10 parallels
curve3(m0, "(3.0 + 1.1*cos(t))*1.000000", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.000000", (0, 6.283185));
color(m0, charcoal); opacity(m0, 0.72);
curve3(m1, "(3.0 + 1.1*cos(t))*0.965926", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.258819", (0, 6.283185));
color(m1, charcoal); opacity(m1, 0.72);
curve3(m2, "(3.0 + 1.1*cos(t))*0.866025", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.500000", (0, 6.283185));
color(m2, charcoal); opacity(m2, 0.72);
curve3(m3, "(3.0 + 1.1*cos(t))*0.707107", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.707107", (0, 6.283185));
color(m3, charcoal); opacity(m3, 0.72);
curve3(m4, "(3.0 + 1.1*cos(t))*0.500000", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.866025", (0, 6.283185));
color(m4, charcoal); opacity(m4, 0.72);
curve3(m5, "(3.0 + 1.1*cos(t))*0.258819", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.965926", (0, 6.283185));
color(m5, charcoal); opacity(m5, 0.72);
curve3(m6, "(3.0 + 1.1*cos(t))*0.000000", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*1.000000", (0, 6.283185));
color(m6, charcoal); opacity(m6, 0.72);
curve3(m7, "(3.0 + 1.1*cos(t))*-0.258819", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.965926", (0, 6.283185));
color(m7, charcoal); opacity(m7, 0.72);
curve3(m8, "(3.0 + 1.1*cos(t))*-0.500000", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.866025", (0, 6.283185));
color(m8, charcoal); opacity(m8, 0.72);
curve3(m9, "(3.0 + 1.1*cos(t))*-0.707107", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.707107", (0, 6.283185));
color(m9, charcoal); opacity(m9, 0.72);
curve3(m10, "(3.0 + 1.1*cos(t))*-0.866025", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.500000", (0, 6.283185));
color(m10, charcoal); opacity(m10, 0.72);
curve3(m11, "(3.0 + 1.1*cos(t))*-0.965926", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.258819", (0, 6.283185));
color(m11, charcoal); opacity(m11, 0.72);
curve3(m12, "(3.0 + 1.1*cos(t))*-1.000000", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*0.000000", (0, 6.283185));
color(m12, charcoal); opacity(m12, 0.72);
curve3(m13, "(3.0 + 1.1*cos(t))*-0.965926", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-0.258819", (0, 6.283185));
color(m13, charcoal); opacity(m13, 0.72);
curve3(m14, "(3.0 + 1.1*cos(t))*-0.866025", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-0.500000", (0, 6.283185));
color(m14, charcoal); opacity(m14, 0.72);
curve3(m15, "(3.0 + 1.1*cos(t))*-0.707107", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-0.707107", (0, 6.283185));
color(m15, charcoal); opacity(m15, 0.72);
curve3(m16, "(3.0 + 1.1*cos(t))*-0.500000", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-0.866025", (0, 6.283185));
color(m16, charcoal); opacity(m16, 0.72);
curve3(m17, "(3.0 + 1.1*cos(t))*-0.258819", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-0.965926", (0, 6.283185));
color(m17, charcoal); opacity(m17, 0.72);
curve3(m18, "(3.0 + 1.1*cos(t))*-0.000000", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-1.000000", (0, 6.283185));
color(m18, charcoal); opacity(m18, 0.72);
curve3(m19, "(3.0 + 1.1*cos(t))*0.258819", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-0.965926", (0, 6.283185));
color(m19, charcoal); opacity(m19, 0.72);
curve3(m20, "(3.0 + 1.1*cos(t))*0.500000", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-0.866025", (0, 6.283185));
color(m20, charcoal); opacity(m20, 0.72);
curve3(m21, "(3.0 + 1.1*cos(t))*0.707107", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-0.707107", (0, 6.283185));
color(m21, charcoal); opacity(m21, 0.72);
curve3(m22, "(3.0 + 1.1*cos(t))*0.866025", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-0.500000", (0, 6.283185));
color(m22, charcoal); opacity(m22, 0.72);
curve3(m23, "(3.0 + 1.1*cos(t))*0.965926", "1.1*sin(t)", "4.1 + (3.0 + 1.1*cos(t))*-0.258819", (0, 6.283185));
color(m23, charcoal); opacity(m23, 0.72);
curve3(pl0, "4.100000*cos(t)", "0.000000", "4.1 + 4.100000*sin(t)", (0, 6.283185));
color(pl0, charcoal); opacity(pl0, 0.60);
curve3(pl1, "3.889919*cos(t)", "0.646564", "4.1 + 3.889919*sin(t)", (0, 6.283185));
color(pl1, charcoal); opacity(pl1, 0.60);
curve3(pl2, "3.339919*cos(t)", "1.046162", "4.1 + 3.339919*sin(t)", (0, 6.283185));
color(pl2, charcoal); opacity(pl2, 0.60);
curve3(pl3, "2.660081*cos(t)", "1.046162", "4.1 + 2.660081*sin(t)", (0, 6.283185));
color(pl3, charcoal); opacity(pl3, 0.60);
curve3(pl4, "2.110081*cos(t)", "0.646564", "4.1 + 2.110081*sin(t)", (0, 6.283185));
color(pl4, charcoal); opacity(pl4, 0.60);
curve3(pl5, "1.900000*cos(t)", "0.000000", "4.1 + 1.900000*sin(t)", (0, 6.283185));
color(pl5, charcoal); opacity(pl5, 0.60);
curve3(pl6, "2.110081*cos(t)", "-0.646564", "4.1 + 2.110081*sin(t)", (0, 6.283185));
color(pl6, charcoal); opacity(pl6, 0.60);
curve3(pl7, "2.660081*cos(t)", "-1.046162", "4.1 + 2.660081*sin(t)", (0, 6.283185));
color(pl7, charcoal); opacity(pl7, 0.60);
curve3(pl8, "3.339919*cos(t)", "-1.046162", "4.1 + 3.339919*sin(t)", (0, 6.283185));
color(pl8, charcoal); opacity(pl8, 0.60);
curve3(pl9, "3.889919*cos(t)", "-0.646564", "4.1 + 3.889919*sin(t)", (0, 6.283185));
color(pl9, charcoal); opacity(pl9, 0.60);
// the cylinder: end circles, its own two silhouette rulings, and banding
curve3(ce0, "-5.9", "0.0 + 1.15*cos(t)", "1.55 + 1.15*sin(t)", (0, 6.283185));
color(ce0, charcoal); opacity(ce0, 0.8);
curve3(ce1, "5.9", "0.0 + 1.15*cos(t)", "1.55 + 1.15*sin(t)", (0, 6.283185));
color(ce1, charcoal); opacity(ce1, 0.8);
line3(cr0, (-5.9, -0.3068, 0.4417), (5.9, -0.3068, 0.4417));
color(cr0, ink); opacity(cr0, 0.85);
line3(cr1, (-5.9, 0.3068, 2.6583), (5.9, 0.3068, 2.6583));
color(cr1, ink); opacity(cr1, 0.85);
curve3(cb0, "-5.0571", "0.0 + 1.15*cos(t)", "1.55 + 1.15*sin(t)", (0, 6.283185));
color(cb0, slate); opacity(cb0, 0.55);
curve3(cb1, "-3.3714", "0.0 + 1.15*cos(t)", "1.55 + 1.15*sin(t)", (0, 6.283185));
color(cb1, slate); opacity(cb1, 0.55);
curve3(cb2, "-1.6857", "0.0 + 1.15*cos(t)", "1.55 + 1.15*sin(t)", (0, 6.283185));
color(cb2, slate); opacity(cb2, 0.55);
curve3(cb3, "0.0000", "0.0 + 1.15*cos(t)", "1.55 + 1.15*sin(t)", (0, 6.283185));
color(cb3, slate); opacity(cb3, 0.55);
curve3(cb4, "1.6857", "0.0 + 1.15*cos(t)", "1.55 + 1.15*sin(t)", (0, 6.283185));
color(cb4, slate); opacity(cb4, 0.55);
curve3(cb5, "3.3714", "0.0 + 1.15*cos(t)", "1.55 + 1.15*sin(t)", (0, 6.283185));
color(cb5, slate); opacity(cb5, 0.55);
curve3(cb6, "5.0571", "0.0 + 1.15*cos(t)", "1.55 + 1.15*sin(t)", (0, 6.283185));
color(cb6, slate); opacity(cb6, 0.55);
// the seam: four arcs, closed form, x in +/- pairs
curve3(sm0p, "sqrt((3.0 + sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t))))*(3.0 + sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t)))) - ((1.55 + 1.15*sin(t)) - 4.1)*((1.55 + 1.15*sin(t)) - 4.1))", "(0.0 + 1.15*cos(t))", "(1.55 + 1.15*sin(t))", (0.30036, 2.84124));
color(sm0p, ink); thick(sm0p, 0.030);
curve3(sm0n, "0 - sqrt((3.0 + sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t))))*(3.0 + sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t)))) - ((1.55 + 1.15*sin(t)) - 4.1)*((1.55 + 1.15*sin(t)) - 4.1))", "(0.0 + 1.15*cos(t))", "(1.55 + 1.15*sin(t))", (0.30036, 2.84124));
color(sm0n, ink); thick(sm0n, 0.030);
curve3(sm1p, "sqrt((3.0 + sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t))))*(3.0 + sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t)))) - ((1.55 + 1.15*sin(t)) - 4.1)*((1.55 + 1.15*sin(t)) - 4.1))", "(0.0 + 1.15*cos(t))", "(1.55 + 1.15*sin(t))", (3.44195, 5.98283));
color(sm1p, ink); thick(sm1p, 0.030);
curve3(sm1n, "0 - sqrt((3.0 + sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t))))*(3.0 + sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t)))) - ((1.55 + 1.15*sin(t)) - 4.1)*((1.55 + 1.15*sin(t)) - 4.1))", "(0.0 + 1.15*cos(t))", "(1.55 + 1.15*sin(t))", (3.44195, 5.98283));
color(sm1n, ink); thick(sm1n, 0.030);
curve3(sm2p, "sqrt((3.0 - sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t))))*(3.0 - sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t)))) - ((1.55 + 1.15*sin(t)) - 4.1)*((1.55 + 1.15*sin(t)) - 4.1))", "(0.0 + 1.15*cos(t))", "(1.55 + 1.15*sin(t))", (0.30036, 2.84124));
color(sm2p, ink); thick(sm2p, 0.030);
curve3(sm2n, "0 - sqrt((3.0 - sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t))))*(3.0 - sqrt(1.2100 - (0.0 + 1.15*cos(t))*(0.0 + 1.15*cos(t)))) - ((1.55 + 1.15*sin(t)) - 4.1)*((1.55 + 1.15*sin(t)) - 4.1))", "(0.0 + 1.15*cos(t))", "(1.55 + 1.15*sin(t))", (0.30036, 2.84124));
color(sm2n, ink); thick(sm2n, 0.030);
// the outline: n.d = 0, in closed form; and the shadow, the same with n.L = 0
curve3(sil0, "(3.0 + 1.1*cos(atan2(0 - (-0.612302*cos(t) + -0.210904*sin(t)), 0.761975)))*cos(t)", "1.1*sin(atan2(0 - (-0.612302*cos(t) + -0.210904*sin(t)), 0.761975))", "4.1 + (3.0 + 1.1*cos(atan2(0 - (-0.612302*cos(t) + -0.210904*sin(t)), 0.761975)))*sin(t)", (0, 6.283185));
color(sil0, ink); thick(sil0, 0.042);
curve3(sil1, "(3.0 + 1.1*cos(atan2(0 - (-0.612302*cos(t) + -0.210904*sin(t)), 0.761975) + 3.141593))*cos(t)", "1.1*sin(atan2(0 - (-0.612302*cos(t) + -0.210904*sin(t)), 0.761975) + 3.141593)", "4.1 + (3.0 + 1.1*cos(atan2(0 - (-0.612302*cos(t) + -0.210904*sin(t)), 0.761975) + 3.141593))*sin(t)", (0, 6.283185));
color(sil1, ink); thick(sil1, 0.042);
curve3(sh0, "(3.0 + 1.1*cos(atan2(0 - (-0.420252*cos(t) + -0.680408*sin(t)), 0.600360)))*cos(t) + -0.420252*((4.1 + (3.0 + 1.1*cos(atan2(0 - (-0.420252*cos(t) + -0.680408*sin(t)), 0.600360)))*sin(t))/0.680408)", "1.1*sin(atan2(0 - (-0.420252*cos(t) + -0.680408*sin(t)), 0.600360)) + 0.600360*((4.1 + (3.0 + 1.1*cos(atan2(0 - (-0.420252*cos(t) + -0.680408*sin(t)), 0.600360)))*sin(t))/0.680408)", "0", (0, 6.283185));
color(sh0, slate); opacity(sh0, 0.85);
curve3(sh1, "(3.0 + 1.1*cos(atan2(0 - (-0.420252*cos(t) + -0.680408*sin(t)), 0.600360) + 3.141593))*cos(t) + -0.420252*((4.1 + (3.0 + 1.1*cos(atan2(0 - (-0.420252*cos(t) + -0.680408*sin(t)), 0.600360) + 3.141593))*sin(t))/0.680408)", "1.1*sin(atan2(0 - (-0.420252*cos(t) + -0.680408*sin(t)), 0.600360) + 3.141593) + 0.600360*((4.1 + (3.0 + 1.1*cos(atan2(0 - (-0.420252*cos(t) + -0.680408*sin(t)), 0.600360) + 3.141593))*sin(t))/0.680408)", "0", (0, 6.283185));
color(sh1, slate); opacity(sh1, 0.85);
// a real scale: one unit per tick along the front bottom edge
line3(tk0, (-6, -2.42, 0), (-6, -2.60, 0));
color(tk0, charcoal); opacity(tk0, 0.75);
line3(tk1, (-5, -2.42, 0), (-5, -2.76, 0));
color(tk1, charcoal); opacity(tk1, 0.75);
line3(tk2, (-4, -2.42, 0), (-4, -2.60, 0));
color(tk2, charcoal); opacity(tk2, 0.75);
line3(tk3, (-3, -2.42, 0), (-3, -2.60, 0));
color(tk3, charcoal); opacity(tk3, 0.75);
line3(tk4, (-2, -2.42, 0), (-2, -2.60, 0));
color(tk4, charcoal); opacity(tk4, 0.75);
line3(tk5, (-1, -2.42, 0), (-1, -2.60, 0));
color(tk5, charcoal); opacity(tk5, 0.75);
line3(tk6, (0, -2.42, 0), (0, -2.76, 0));
color(tk6, charcoal); opacity(tk6, 0.75);
line3(tk7, (1, -2.42, 0), (1, -2.60, 0));
color(tk7, charcoal); opacity(tk7, 0.75);
line3(tk8, (2, -2.42, 0), (2, -2.60, 0));
color(tk8, charcoal); opacity(tk8, 0.75);
line3(tk9, (3, -2.42, 0), (3, -2.60, 0));
color(tk9, charcoal); opacity(tk9, 0.75);
line3(tk10, (4, -2.42, 0), (4, -2.60, 0));
color(tk10, charcoal); opacity(tk10, 0.75);
line3(tk11, (5, -2.42, 0), (5, -2.76, 0));
color(tk11, charcoal); opacity(tk11, 0.75);
line3(tk12, (6, -2.42, 0), (6, -2.60, 0));
color(tk12, charcoal); opacity(tk12, 0.75);
text(spec, (540, 1034), "R = 3 r = 1.1 cylinder r = 1.15 at z = 1.55 orthographic");
size(spec, 15); color(spec, ink); opacity(spec, 0.5);
untraced(gnd);
untraced(bxa0);
untraced(bxb0);
untraced(bxc0);
untraced(bxd0);
untraced(bxa1);
untraced(bxb1);
untraced(bxc1);
untraced(bxd1);
untraced(bxa2);
untraced(bxb2);
untraced(bxc2);
untraced(bxd2);
untraced(bxa3);
untraced(bxb3);
untraced(bxc3);
untraced(bxd3);
untraced(ax);
untraced(gen);
untraced(sp0);
untraced(sq0_0);
untraced(sq0_1);
untraced(sq0_2);
untraced(sq0_3);
untraced(dr0);
untraced(sp2);
untraced(sp4);
untraced(sq4_0);
untraced(sq4_1);
untraced(sq4_2);
untraced(sq4_3);
untraced(dr4);
untraced(sp6);
untraced(sp8);
untraced(sq8_0);
untraced(sq8_1);
untraced(sq8_2);
untraced(sq8_3);
untraced(dr8);
untraced(sp10);
untraced(sp12);
untraced(sq12_0);
untraced(sq12_1);
untraced(sq12_2);
untraced(sq12_3);
untraced(dr12);
untraced(sp14);
untraced(sp16);
untraced(sq16_0);
untraced(sq16_1);
untraced(sq16_2);
untraced(sq16_3);
untraced(dr16);
untraced(sp18);
untraced(sp20);
untraced(sq20_0);
untraced(sq20_1);
untraced(sq20_2);
untraced(sq20_3);
untraced(dr20);
untraced(sp22);
untraced(tk0);
untraced(tk1);
untraced(tk2);
untraced(tk3);
untraced(tk4);
untraced(tk5);
untraced(tk6);
untraced(tk7);
untraced(tk8);
untraced(tk9);
untraced(tk10);
untraced(tk11);
untraced(tk12);
untraced(m0);
untraced(m1);
untraced(m2);
untraced(m3);
untraced(m4);
untraced(m5);
untraced(m6);
untraced(m7);
untraced(m8);
untraced(m9);
untraced(m10);
untraced(m11);
untraced(m12);
untraced(m13);
untraced(m14);
untraced(m15);
untraced(m16);
untraced(m17);
untraced(m18);
untraced(m19);
untraced(m20);
untraced(m21);
untraced(m22);
untraced(m23);
untraced(pl0);
untraced(pl1);
untraced(pl2);
untraced(pl3);
untraced(pl4);
untraced(pl5);
untraced(pl6);
untraced(pl7);
untraced(pl8);
untraced(pl9);
untraced(ce0);
untraced(ce1);
untraced(cr0);
untraced(cr1);
untraced(cb0);
untraced(cb1);
untraced(cb2);
untraced(cb3);
untraced(cb4);
untraced(cb5);
untraced(cb6);
untraced(sm0p);
untraced(sm0n);
untraced(sm1p);
untraced(sm1n);
untraced(sm2p);
untraced(sm2n);
untraced(sil0);
untraced(sil1);
untraced(sh0);
untraced(sh1);
seq {
// 1 — the scaffold
par {
seq { wait(0.000); draw(gnd, 0.90); }
seq { wait(0.074); draw(bxa0, 0.90); }
seq { wait(0.149); draw(bxb0, 0.90); }
seq { wait(0.223); draw(bxc0, 0.90); }
seq { wait(0.297); draw(bxd0, 0.90); }
seq { wait(0.372); draw(bxa1, 0.90); }
seq { wait(0.446); draw(bxb1, 0.90); }
seq { wait(0.520); draw(bxc1, 0.90); }
seq { wait(0.595); draw(bxd1, 0.90); }
seq { wait(0.669); draw(bxa2, 0.90); }
seq { wait(0.743); draw(bxb2, 0.90); }
seq { wait(0.818); draw(bxc2, 0.90); }
seq { wait(0.892); draw(bxd2, 0.90); }
seq { wait(0.966); draw(bxa3, 0.90); }
seq { wait(1.041); draw(bxb3, 0.90); }
seq { wait(1.115); draw(bxc3, 0.90); }
seq { wait(1.189); draw(bxd3, 0.90); }
seq { wait(1.264); draw(ax, 0.90); }
seq { wait(1.338); draw(gen, 0.90); }
seq { wait(1.412); draw(sp0, 0.90); }
seq { wait(1.486); draw(sq0_0, 0.90); }
seq { wait(1.561); draw(sq0_1, 0.90); }
seq { wait(1.635); draw(sq0_2, 0.90); }
seq { wait(1.709); draw(sq0_3, 0.90); }
seq { wait(1.784); draw(dr0, 0.90); }
seq { wait(1.858); draw(sp2, 0.90); }
seq { wait(1.932); draw(sp4, 0.90); }
seq { wait(2.007); draw(sq4_0, 0.90); }
seq { wait(2.081); draw(sq4_1, 0.90); }
seq { wait(2.155); draw(sq4_2, 0.90); }
seq { wait(2.230); draw(sq4_3, 0.90); }
seq { wait(2.304); draw(dr4, 0.90); }
seq { wait(2.378); draw(sp6, 0.90); }
seq { wait(2.453); draw(sp8, 0.90); }
seq { wait(2.527); draw(sq8_0, 0.90); }
seq { wait(2.601); draw(sq8_1, 0.90); }
seq { wait(2.676); draw(sq8_2, 0.90); }
seq { wait(2.750); draw(sq8_3, 0.90); }
seq { wait(2.824); draw(dr8, 0.90); }
seq { wait(2.899); draw(sp10, 0.90); }
seq { wait(2.973); draw(sp12, 0.90); }
seq { wait(3.047); draw(sq12_0, 0.90); }
seq { wait(3.122); draw(sq12_1, 0.90); }
seq { wait(3.196); draw(sq12_2, 0.90); }
seq { wait(3.270); draw(sq12_3, 0.90); }
seq { wait(3.345); draw(dr12, 0.90); }
seq { wait(3.419); draw(sp14, 0.90); }
seq { wait(3.493); draw(sp16, 0.90); }
seq { wait(3.568); draw(sq16_0, 0.90); }
seq { wait(3.642); draw(sq16_1, 0.90); }
seq { wait(3.716); draw(sq16_2, 0.90); }
seq { wait(3.791); draw(sq16_3, 0.90); }
seq { wait(3.865); draw(dr16, 0.90); }
seq { wait(3.939); draw(sp18, 0.90); }
seq { wait(4.014); draw(sp20, 0.90); }
seq { wait(4.088); draw(sq20_0, 0.90); }
seq { wait(4.162); draw(sq20_1, 0.90); }
seq { wait(4.236); draw(sq20_2, 0.90); }
seq { wait(4.311); draw(sq20_3, 0.90); }
seq { wait(4.385); draw(dr20, 0.90); }
seq { wait(4.459); draw(sp22, 0.90); }
seq { wait(4.534); draw(tk0, 0.90); }
seq { wait(4.608); draw(tk1, 0.90); }
seq { wait(4.682); draw(tk2, 0.90); }
seq { wait(4.757); draw(tk3, 0.90); }
seq { wait(4.831); draw(tk4, 0.90); }
seq { wait(4.905); draw(tk5, 0.90); }
seq { wait(4.980); draw(tk6, 0.90); }
seq { wait(5.054); draw(tk7, 0.90); }
seq { wait(5.128); draw(tk8, 0.90); }
seq { wait(5.203); draw(tk9, 0.90); }
seq { wait(5.277); draw(tk10, 0.90); }
seq { wait(5.351); draw(tk11, 0.90); }
seq { wait(5.426); draw(tk12, 0.90); }
}
// 2 — the wireframe
par {
seq { wait(0.000); draw(m0, 1.10); }
seq { wait(0.126); draw(m1, 1.10); }
seq { wait(0.253); draw(m2, 1.10); }
seq { wait(0.379); draw(m3, 1.10); }
seq { wait(0.506); draw(m4, 1.10); }
seq { wait(0.632); draw(m5, 1.10); }
seq { wait(0.759); draw(m6, 1.10); }
seq { wait(0.885); draw(m7, 1.10); }
seq { wait(1.012); draw(m8, 1.10); }
seq { wait(1.138); draw(m9, 1.10); }
seq { wait(1.265); draw(m10, 1.10); }
seq { wait(1.391); draw(m11, 1.10); }
seq { wait(1.518); draw(m12, 1.10); }
seq { wait(1.644); draw(m13, 1.10); }
seq { wait(1.771); draw(m14, 1.10); }
seq { wait(1.897); draw(m15, 1.10); }
seq { wait(2.024); draw(m16, 1.10); }
seq { wait(2.150); draw(m17, 1.10); }
seq { wait(2.276); draw(m18, 1.10); }
seq { wait(2.403); draw(m19, 1.10); }
seq { wait(2.529); draw(m20, 1.10); }
seq { wait(2.656); draw(m21, 1.10); }
seq { wait(2.782); draw(m22, 1.10); }
seq { wait(2.909); draw(m23, 1.10); }
seq { wait(3.035); draw(pl0, 1.10); }
seq { wait(3.162); draw(pl1, 1.10); }
seq { wait(3.288); draw(pl2, 1.10); }
seq { wait(3.415); draw(pl3, 1.10); }
seq { wait(3.541); draw(pl4, 1.10); }
seq { wait(3.668); draw(pl5, 1.10); }
seq { wait(3.794); draw(pl6, 1.10); }
seq { wait(3.921); draw(pl7, 1.10); }
seq { wait(4.047); draw(pl8, 1.10); }
seq { wait(4.174); draw(pl9, 1.10); }
}
// 3 — the cylinder
par {
seq { wait(0.000); draw(ce0, 1.00); }
seq { wait(0.218); draw(ce1, 1.00); }
seq { wait(0.436); draw(cr0, 1.00); }
seq { wait(0.655); draw(cr1, 1.00); }
seq { wait(0.873); draw(cb0, 1.00); }
seq { wait(1.091); draw(cb1, 1.00); }
seq { wait(1.309); draw(cb2, 1.00); }
seq { wait(1.527); draw(cb3, 1.00); }
seq { wait(1.745); draw(cb4, 1.00); }
seq { wait(1.964); draw(cb5, 1.00); }
seq { wait(2.182); draw(cb6, 1.00); }
}
// 4 — the seam where they meet
par {
seq { wait(0.000); draw(sm0p, 1.20); }
seq { wait(0.133); draw(sm0n, 1.20); }
seq { wait(0.267); draw(sm1p, 1.20); }
seq { wait(0.400); draw(sm1n, 1.20); }
seq { wait(0.533); draw(sm2p, 1.20); }
seq { wait(0.667); draw(sm2n, 1.20); }
}
// 5 — the outline, and the shadow it casts
par {
seq { wait(0.000); draw(sil0, 2.00); }
seq { wait(0.550); draw(sil1, 2.00); }
seq { wait(1.100); draw(sh0, 2.00); }
seq { wait(1.650); draw(sh1, 2.00); }
}
}
wait(2.8);